diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-07-17 13:57:45 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-07-19 13:44:40 +0000 |
commit | 6ec7b8da05d21a3878bd21c691b41e675d74bb1c (patch) | |
tree | b87f250bc19413750b9bb9cdbf2da20ef5014820 /chromium/v8/src/ast | |
parent | ec02ee4181c49b61fce1c8fb99292dbb8139cc90 (diff) | |
download | qtwebengine-chromium-6ec7b8da05d21a3878bd21c691b41e675d74bb1c.tar.gz |
BASELINE: Update Chromium to 60.0.3112.70
Change-Id: I9911c2280a014d4632f254857876a395d4baed2d
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/v8/src/ast')
-rw-r--r-- | chromium/v8/src/ast/ast-expression-rewriter.cc | 2 | ||||
-rw-r--r-- | chromium/v8/src/ast/ast-numbering.cc | 3 | ||||
-rw-r--r-- | chromium/v8/src/ast/ast-types.cc | 8 | ||||
-rw-r--r-- | chromium/v8/src/ast/ast-value-factory.cc | 10 | ||||
-rw-r--r-- | chromium/v8/src/ast/ast-value-factory.h | 21 | ||||
-rw-r--r-- | chromium/v8/src/ast/ast.cc | 106 | ||||
-rw-r--r-- | chromium/v8/src/ast/ast.h | 198 | ||||
-rw-r--r-- | chromium/v8/src/ast/compile-time-value.cc | 20 | ||||
-rw-r--r-- | chromium/v8/src/ast/compile-time-value.h | 15 | ||||
-rw-r--r-- | chromium/v8/src/ast/scopes.cc | 85 | ||||
-rw-r--r-- | chromium/v8/src/ast/scopes.h | 20 | ||||
-rw-r--r-- | chromium/v8/src/ast/variables.cc | 1 | ||||
-rw-r--r-- | chromium/v8/src/ast/variables.h | 51 |
13 files changed, 310 insertions, 230 deletions
diff --git a/chromium/v8/src/ast/ast-expression-rewriter.cc b/chromium/v8/src/ast/ast-expression-rewriter.cc index d23612f2b4f..a3ee43204ac 100644 --- a/chromium/v8/src/ast/ast-expression-rewriter.cc +++ b/chromium/v8/src/ast/ast-expression-rewriter.cc @@ -31,7 +31,7 @@ void AstExpressionRewriter::VisitDeclarations(Declaration::List* declarations) { void AstExpressionRewriter::VisitStatements(ZoneList<Statement*>* statements) { for (int i = 0; i < statements->length(); i++) { AST_REWRITE_LIST_ELEMENT(Statement, statements, i); - // Not stopping when a jump statement is found. + if (statements->at(i)->IsJump()) break; } } diff --git a/chromium/v8/src/ast/ast-numbering.cc b/chromium/v8/src/ast/ast-numbering.cc index 24ccf79244d..202b61b17fe 100644 --- a/chromium/v8/src/ast/ast-numbering.cc +++ b/chromium/v8/src/ast/ast-numbering.cc @@ -563,6 +563,7 @@ void AstNumberingVisitor::VisitClassLiteral(ClassLiteral* node) { IncrementNodeCount(); DisableFullCodegenAndCrankshaft(kClassLiteral); node->set_base_id(ReserveIdRange(ClassLiteral::num_ids())); + LanguageModeScope language_mode_scope(this, STRICT); if (node->extends()) Visit(node->extends()); if (node->constructor()) Visit(node->constructor()); if (node->class_variable_proxy()) { @@ -715,7 +716,7 @@ bool AstNumberingVisitor::Renumber(FunctionLiteral* node) { node->set_dont_optimize_reason(dont_optimize_reason()); node->set_suspend_count(suspend_count_); - if (FLAG_trace_opt) { + if (FLAG_trace_opt && !FLAG_turbo) { if (disable_crankshaft_reason_ != kNoReason) { // TODO(leszeks): This is a quick'n'dirty fix to allow the debug name of // the function to be accessed in the below print. This DCHECK will fail diff --git a/chromium/v8/src/ast/ast-types.cc b/chromium/v8/src/ast/ast-types.cc index 9e14730c976..8ff1d883519 100644 --- a/chromium/v8/src/ast/ast-types.cc +++ b/chromium/v8/src/ast/ast-types.cc @@ -302,16 +302,13 @@ AstType::bitset AstBitsetType::Lub(i::Map* map) { case FILLER_TYPE: case ACCESS_CHECK_INFO_TYPE: case INTERCEPTOR_INFO_TYPE: - case CALL_HANDLER_INFO_TYPE: case PROMISE_RESOLVE_THENABLE_JOB_INFO_TYPE: case PROMISE_REACTION_JOB_INFO_TYPE: case FUNCTION_TEMPLATE_INFO_TYPE: case OBJECT_TEMPLATE_INFO_TYPE: case ALLOCATION_MEMENTO_TYPE: - case TYPE_FEEDBACK_INFO_TYPE: case ALIASED_ARGUMENTS_ENTRY_TYPE: case DEBUG_INFO_TYPE: - case BREAK_POINT_INFO_TYPE: case STACK_FRAME_INFO_TYPE: case CELL_TYPE: case WEAK_CELL_TYPE: @@ -319,7 +316,10 @@ AstType::bitset AstBitsetType::Lub(i::Map* map) { case TUPLE2_TYPE: case TUPLE3_TYPE: case CONTEXT_EXTENSION_TYPE: - case CONSTANT_ELEMENTS_PAIR_TYPE: + case PADDING_TYPE_1: + case PADDING_TYPE_2: + case PADDING_TYPE_3: + case PADDING_TYPE_4: UNREACHABLE(); return kNone; } diff --git a/chromium/v8/src/ast/ast-value-factory.cc b/chromium/v8/src/ast/ast-value-factory.cc index 74613c5eae5..a304aa0e008 100644 --- a/chromium/v8/src/ast/ast-value-factory.cc +++ b/chromium/v8/src/ast/ast-value-factory.cc @@ -31,6 +31,7 @@ #include "src/char-predicates-inl.h" #include "src/objects-inl.h" #include "src/objects.h" +#include "src/string-hasher.h" #include "src/utils.h" namespace v8 { @@ -189,10 +190,8 @@ bool AstValue::BooleanValue() const { case SYMBOL: UNREACHABLE(); break; - case NUMBER_WITH_DOT: case NUMBER: return DoubleToBoolean(number_); - case SMI_WITH_DOT: case SMI: return smi_ != 0; case BOOLEAN: @@ -224,11 +223,9 @@ void AstValue::Internalize(Isolate* isolate) { break; } break; - case NUMBER_WITH_DOT: case NUMBER: set_value(isolate->factory()->NewNumber(number_, TENURED)); break; - case SMI_WITH_DOT: case SMI: set_value(handle(Smi::FromInt(smi_), isolate)); break; @@ -342,9 +339,8 @@ const AstValue* AstValueFactory::NewSymbol(AstSymbol symbol) { return AddValue(value); } - -const AstValue* AstValueFactory::NewNumber(double number, bool with_dot) { - AstValue* value = new (zone_) AstValue(number, with_dot); +const AstValue* AstValueFactory::NewNumber(double number) { + AstValue* value = new (zone_) AstValue(number); return AddValue(value); } diff --git a/chromium/v8/src/ast/ast-value-factory.h b/chromium/v8/src/ast/ast-value-factory.h index 19452bc3258..34e8b9e1c1a 100644 --- a/chromium/v8/src/ast/ast-value-factory.h +++ b/chromium/v8/src/ast/ast-value-factory.h @@ -189,10 +189,6 @@ class AstValue : public ZoneObject { bool IsNumber() const { return IsSmi() || IsHeapNumber(); } - bool ContainsDot() const { - return type_ == NUMBER_WITH_DOT || type_ == SMI_WITH_DOT; - } - const AstRawString* AsString() const { CHECK_EQ(STRING, type_); return string_; @@ -236,10 +232,8 @@ class AstValue : public ZoneObject { bool BooleanValue() const; - bool IsSmi() const { return type_ == SMI || type_ == SMI_WITH_DOT; } - bool IsHeapNumber() const { - return type_ == NUMBER || type_ == NUMBER_WITH_DOT; - } + bool IsSmi() const { return type_ == SMI; } + bool IsHeapNumber() const { return type_ == NUMBER; } bool IsFalse() const { return type_ == BOOLEAN && !bool_; } bool IsTrue() const { return type_ == BOOLEAN && bool_; } bool IsUndefined() const { return type_ == UNDEFINED; } @@ -267,9 +261,7 @@ class AstValue : public ZoneObject { STRING, SYMBOL, NUMBER, - NUMBER_WITH_DOT, SMI, - SMI_WITH_DOT, BOOLEAN, NULL_TYPE, UNDEFINED, @@ -284,13 +276,13 @@ class AstValue : public ZoneObject { symbol_ = symbol; } - explicit AstValue(double n, bool with_dot) : next_(nullptr) { + explicit AstValue(double n) : next_(nullptr) { int int_value; if (DoubleToSmiInteger(n, &int_value)) { - type_ = with_dot ? SMI_WITH_DOT : SMI; + type_ = SMI; smi_ = int_value; } else { - type_ = with_dot ? NUMBER_WITH_DOT : NUMBER; + type_ = NUMBER; number_ = n; } } @@ -481,8 +473,7 @@ class AstValueFactory { V8_EXPORT_PRIVATE const AstValue* NewString(const AstRawString* string); // A JavaScript symbol (ECMA-262 edition 6). const AstValue* NewSymbol(AstSymbol symbol); - V8_EXPORT_PRIVATE const AstValue* NewNumber(double number, - bool with_dot = false); + V8_EXPORT_PRIVATE const AstValue* NewNumber(double number); const AstValue* NewSmi(uint32_t number); const AstValue* NewBoolean(bool b); const AstValue* NewStringList(ZoneList<const AstRawString*>* strings); diff --git a/chromium/v8/src/ast/ast.cc b/chromium/v8/src/ast/ast.cc index d7d70ae4336..b367df7daed 100644 --- a/chromium/v8/src/ast/ast.cc +++ b/chromium/v8/src/ast/ast.cc @@ -19,6 +19,7 @@ #include "src/elements.h" #include "src/objects-inl.h" #include "src/objects/literal-objects.h" +#include "src/objects/map.h" #include "src/property-details.h" #include "src/property.h" #include "src/string-stream.h" @@ -147,8 +148,8 @@ bool Expression::IsValidReferenceExpressionOrThis() const { bool Expression::IsAnonymousFunctionDefinition() const { return (IsFunctionLiteral() && AsFunctionLiteral()->IsAnonymousFunctionDefinition()) || - (IsDoExpression() && - AsDoExpression()->IsAnonymousFunctionDefinition()); + (IsClassLiteral() && + AsClassLiteral()->IsAnonymousFunctionDefinition()); } void Expression::MarkTail() { @@ -161,12 +162,6 @@ void Expression::MarkTail() { } } -bool DoExpression::IsAnonymousFunctionDefinition() const { - // This is specifically to allow DoExpressions to represent ClassLiterals. - return represented_function_ != nullptr && - represented_function_->raw_name()->IsEmpty(); -} - bool Statement::IsJump() const { switch (node_type()) { #define JUMP_NODE_LIST(V) \ @@ -350,6 +345,23 @@ bool FunctionLiteral::NeedsHomeObject(Expression* expr) { return expr->AsFunctionLiteral()->scope()->NeedsHomeObject(); } +void FunctionLiteral::ReplaceBodyAndScope(FunctionLiteral* other) { + DCHECK_NULL(body_); + DCHECK_NOT_NULL(scope_); + DCHECK_NOT_NULL(other->scope()); + + Scope* outer_scope = scope_->outer_scope(); + + body_ = other->body(); + scope_ = other->scope(); + scope_->ReplaceOuterScope(outer_scope); +#ifdef DEBUG + scope_->set_replaced_from_parse_task(true); +#endif + + function_length_ = other->function_length_; +} + ObjectLiteralProperty::ObjectLiteralProperty(Expression* key, Expression* value, Kind kind, bool is_computed_name) : LiteralProperty(key, value, is_computed_name), @@ -490,7 +502,7 @@ void ObjectLiteral::AssignFeedbackSlots(FeedbackVectorSpec* spec, ObjectLiteral::Property* property = properties()->at(property_index); Expression* value = property->value(); - if (property->kind() != ObjectLiteral::Property::PROTOTYPE) { + if (!property->IsPrototype()) { if (FunctionLiteral::NeedsHomeObject(value)) { property->SetSlot(spec->AddStoreICSlot(language_mode)); } @@ -512,7 +524,7 @@ void ObjectLiteral::CalculateEmitStore(Zone* zone) { for (int i = properties()->length() - 1; i >= 0; i--) { ObjectLiteral::Property* property = properties()->at(i); if (property->is_computed_name()) continue; - if (property->kind() == ObjectLiteral::Property::PROTOTYPE) continue; + if (property->IsPrototype()) continue; Literal* literal = property->key()->AsLiteral(); DCHECK(!literal->IsNullLiteral()); @@ -532,31 +544,42 @@ void ObjectLiteral::CalculateEmitStore(Zone* zone) { } } - -bool ObjectLiteral::IsBoilerplateProperty(ObjectLiteral::Property* property) { - return property != NULL && - property->kind() != ObjectLiteral::Property::PROTOTYPE; +void ObjectLiteral::InitFlagsForPendingNullPrototype(int i) { + // We still check for __proto__:null after computed property names. + for (; i < properties()->length(); i++) { + if (properties()->at(i)->IsNullPrototype()) { + set_has_null_protoype(true); + break; + } + } } void ObjectLiteral::InitDepthAndFlags() { - if (depth_ > 0) return; - - int position = 0; - // Accumulate the value in local variables and store it at the end. + if (is_initialized()) return; bool is_simple = true; + bool has_seen_prototype = false; int depth_acc = 1; - uint32_t max_element_index = 0; + uint32_t nof_properties = 0; uint32_t elements = 0; + uint32_t max_element_index = 0; for (int i = 0; i < properties()->length(); i++) { ObjectLiteral::Property* property = properties()->at(i); - if (!IsBoilerplateProperty(property)) { + if (property->IsPrototype()) { + has_seen_prototype = true; + // __proto__:null has no side-effects and is set directly on the + // boilerplate. + if (property->IsNullPrototype()) { + set_has_null_protoype(true); + continue; + } + DCHECK(!has_null_prototype()); is_simple = false; continue; } - - if (static_cast<uint32_t>(position) == boilerplate_properties_ * 2) { + if (nof_properties == boilerplate_properties_) { DCHECK(property->is_computed_name()); is_simple = false; + if (!has_seen_prototype) InitFlagsForPendingNullPrototype(i); break; } DCHECK(!property->is_computed_name()); @@ -578,7 +601,7 @@ void ObjectLiteral::InitDepthAndFlags() { // TODO(verwaest): Remove once we can store them inline. if (FLAG_track_double_fields && (value->IsNumberLiteral() || !is_compile_time_value)) { - bit_field_ = MayStoreDoublesField::update(bit_field_, true); + set_may_store_doubles(true); } is_simple = is_simple && is_compile_time_value; @@ -596,15 +619,12 @@ void ObjectLiteral::InitDepthAndFlags() { elements++; } - // Increment the position for the key and the value. - position += 2; + nof_properties++; } - bit_field_ = FastElementsField::update( - bit_field_, - (max_element_index <= 32) || ((2 * elements) >= max_element_index)); - bit_field_ = HasElementsField::update(bit_field_, elements > 0); - + set_fast_elements((max_element_index <= 32) || + ((2 * elements) >= max_element_index)); + set_has_elements(elements > 0); set_is_simple(is_simple); set_depth(depth_acc); } @@ -616,7 +636,7 @@ void ObjectLiteral::BuildConstantProperties(Isolate* isolate) { bool has_seen_proto = false; for (int i = 0; i < properties()->length(); i++) { ObjectLiteral::Property* property = properties()->at(i); - if (!IsBoilerplateProperty(property)) { + if (property->IsPrototype()) { has_seen_proto = true; continue; } @@ -641,9 +661,7 @@ void ObjectLiteral::BuildConstantProperties(Isolate* isolate) { int position = 0; for (int i = 0; i < properties()->length(); i++) { ObjectLiteral::Property* property = properties()->at(i); - if (!IsBoilerplateProperty(property)) { - continue; - } + if (property->IsPrototype()) continue; if (static_cast<uint32_t>(position) == boilerplate_properties_ * 2) { DCHECK(property->is_computed_name()); @@ -693,7 +711,7 @@ ElementsKind ArrayLiteral::constant_elements_kind() const { void ArrayLiteral::InitDepthAndFlags() { DCHECK_LT(first_spread_index_, 0); - if (depth_ > 0) return; + if (is_initialized()) return; int constants_length = values()->length(); @@ -1013,6 +1031,24 @@ void Expression::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { } } +void SmallMapList::AddMapIfMissing(Handle<Map> map, Zone* zone) { + if (!Map::TryUpdate(map).ToHandle(&map)) return; + for (int i = 0; i < length(); ++i) { + if (at(i).is_identical_to(map)) return; + } + Add(map, zone); +} + +void SmallMapList::FilterForPossibleTransitions(Map* root_map) { + for (int i = list_.length() - 1; i >= 0; i--) { + if (at(i)->FindRootMap() != root_map) { + list_.RemoveElement(list_.at(i)); + } + } +} + +Handle<Map> SmallMapList::at(int i) const { return Handle<Map>(list_.at(i)); } + SmallMapList* Expression::GetReceiverTypes() { switch (node_type()) { #define NODE_LIST(V) \ diff --git a/chromium/v8/src/ast/ast.h b/chromium/v8/src/ast/ast.h index 9d7b4de82c5..0fc9af621c9 100644 --- a/chromium/v8/src/ast/ast.h +++ b/chromium/v8/src/ast/ast.h @@ -252,29 +252,15 @@ class SmallMapList final { bool is_empty() const { return list_.is_empty(); } int length() const { return list_.length(); } - void AddMapIfMissing(Handle<Map> map, Zone* zone) { - if (!Map::TryUpdate(map).ToHandle(&map)) return; - for (int i = 0; i < length(); ++i) { - if (at(i).is_identical_to(map)) return; - } - Add(map, zone); - } + void AddMapIfMissing(Handle<Map> map, Zone* zone); - void FilterForPossibleTransitions(Map* root_map) { - for (int i = list_.length() - 1; i >= 0; i--) { - if (at(i)->FindRootMap() != root_map) { - list_.RemoveElement(list_.at(i)); - } - } - } + void FilterForPossibleTransitions(Map* root_map); void Add(Handle<Map> handle, Zone* zone) { list_.Add(handle.location(), zone); } - Handle<Map> at(int i) const { - return Handle<Map>(list_.at(i)); - } + Handle<Map> at(int i) const; Handle<Map> first() const { return at(0); } Handle<Map> last() const { return at(length() - 1); } @@ -484,20 +470,12 @@ class DoExpression final : public Expression { void set_block(Block* b) { block_ = b; } VariableProxy* result() { return result_; } void set_result(VariableProxy* v) { result_ = v; } - FunctionLiteral* represented_function() { return represented_function_; } - void set_represented_function(FunctionLiteral* f) { - represented_function_ = f; - } - bool IsAnonymousFunctionDefinition() const; private: friend class AstNodeFactory; DoExpression(Block* block, VariableProxy* result, int pos) - : Expression(pos, kDoExpression), - block_(block), - result_(result), - represented_function_(nullptr) { + : Expression(pos, kDoExpression), block_(block), result_(result) { DCHECK_NOT_NULL(block_); DCHECK_NOT_NULL(result_); } @@ -506,7 +484,6 @@ class DoExpression final : public Expression { Block* block_; VariableProxy* result_; - FunctionLiteral* represented_function_; }; @@ -977,11 +954,11 @@ class CaseClause final : public Expression { CaseClause(Expression* label, ZoneList<Statement*>* statements, int pos); int local_id(int n) const { return base_id() + parent_num_ids() + n; } + FeedbackSlot feedback_slot_; Expression* label_; Label body_target_; ZoneList<Statement*>* statements_; AstType* compare_type_; - FeedbackSlot feedback_slot_; }; @@ -1238,9 +1215,9 @@ class Literal final : public Expression { // Base class for literals that need space in the type feedback vector. class MaterializedLiteral : public Expression { public: + bool is_initialized() const { return 0 < depth_; } int depth() const { - // only callable after initialization. - DCHECK(depth_ >= 1); + DCHECK(is_initialized()); return depth_; } @@ -1270,10 +1247,11 @@ class MaterializedLiteral : public Expression { void set_is_simple(bool is_simple) { bit_field_ = IsSimpleField::update(bit_field_, is_simple); } + friend class CompileTimeValue; void set_depth(int depth) { - DCHECK_LE(1, depth); + DCHECK(!is_initialized()); depth_ = depth; } @@ -1359,6 +1337,11 @@ class ObjectLiteralProperty final : public LiteralProperty { void set_receiver_type(Handle<Map> map) { receiver_type_ = map; } + bool IsNullPrototype() const { + return IsPrototype() && value()->IsNullLiteral(); + } + bool IsPrototype() const { return kind() == PROTOTYPE; } + private: friend class AstNodeFactory; @@ -1396,9 +1379,9 @@ class ObjectLiteral final : public MaterializedLiteral { bool has_rest_property() const { return HasRestPropertyField::decode(bit_field_); } - - // Decide if a property should be in the object boilerplate. - static bool IsBoilerplateProperty(Property* property); + bool has_null_prototype() const { + return HasNullPrototypeField::decode(bit_field_); + } // Populate the depth field and flags. void InitDepthAndFlags(); @@ -1426,12 +1409,16 @@ class ObjectLiteral final : public MaterializedLiteral { // Assemble bitfield of flags for the CreateObjectLiteral helper. int ComputeFlags(bool disable_mementos = false) const { int flags = fast_elements() ? kFastElements : kNoFlags; - if (has_shallow_properties()) { - flags |= kShallowProperties; - } - if (disable_mementos) { - flags |= kDisableMementos; - } + if (has_shallow_properties()) flags |= kShallowProperties; + if (disable_mementos) flags |= kDisableMementos; + if (has_null_prototype()) flags |= kHasNullPrototype; + return flags; + } + + int EncodeLiteralType() { + int flags = fast_elements() ? kFastElements : kNoFlags; + if (has_shallow_properties()) flags |= kShallowProperties; + if (has_null_prototype()) flags |= kHasNullPrototype; return flags; } @@ -1440,7 +1427,7 @@ class ObjectLiteral final : public MaterializedLiteral { kFastElements = 1, kShallowProperties = 1 << 1, kDisableMementos = 1 << 2, - kHasRestProperty = 1 << 3, + kHasNullPrototype = 1 << 3, }; struct Accessors: public ZoneObject { @@ -1476,12 +1463,28 @@ class ObjectLiteral final : public MaterializedLiteral { bit_field_ |= FastElementsField::encode(false) | HasElementsField::encode(false) | MayStoreDoublesField::encode(false) | - HasRestPropertyField::encode(has_rest_property); + HasRestPropertyField::encode(has_rest_property) | + HasNullPrototypeField::encode(false); } static int parent_num_ids() { return MaterializedLiteral::num_ids(); } int local_id(int n) const { return base_id() + parent_num_ids() + n; } + void InitFlagsForPendingNullPrototype(int i); + + void set_may_store_doubles(bool may_store_doubles) { + bit_field_ = MayStoreDoublesField::update(bit_field_, may_store_doubles); + } + void set_fast_elements(bool fast_elements) { + bit_field_ = FastElementsField::update(bit_field_, fast_elements); + } + void set_has_elements(bool has_elements) { + bit_field_ = HasElementsField::update(bit_field_, has_elements); + } + void set_has_null_protoype(bool has_null_prototype) { + bit_field_ = HasNullPrototypeField::update(bit_field_, has_null_prototype); + } + uint32_t boilerplate_properties_; Handle<BoilerplateDescription> constant_properties_; ZoneList<Property*>* properties_; @@ -1494,6 +1497,8 @@ class ObjectLiteral final : public MaterializedLiteral { : public BitField<bool, HasElementsField::kNext, 1> {}; class HasRestPropertyField : public BitField<bool, MayStoreDoublesField::kNext, 1> {}; + class HasNullPrototypeField + : public BitField<bool, HasRestPropertyField::kNext, 1> {}; }; @@ -1582,9 +1587,7 @@ class ArrayLiteral final : public MaterializedLiteral { // Assemble bitfield of flags for the CreateArrayLiteral helper. int ComputeFlags(bool disable_mementos = false) const { int flags = depth() == 1 ? kShallowElements : kNoFlags; - if (disable_mementos) { - flags |= kDisableMementos; - } + if (disable_mementos) flags |= kDisableMementos; return flags; } @@ -1668,7 +1671,11 @@ class VariableProxy final : public Expression { } HoleCheckMode hole_check_mode() const { - return HoleCheckModeField::decode(bit_field_); + HoleCheckMode mode = HoleCheckModeField::decode(bit_field_); + DCHECK_IMPLIES(mode == HoleCheckMode::kRequired, + var()->binding_needs_init() || + var()->local_if_not_shadowed()->binding_needs_init()); + return mode; } void set_needs_hole_check() { bit_field_ = @@ -2160,10 +2167,10 @@ class BinaryOperation final : public Expression { BinaryOperation(Token::Value op, Expression* left, Expression* right, int pos) : Expression(pos, kBinaryOperation), - has_fixed_right_arg_(false), - fixed_right_arg_value_(0), left_(left), - right_(right) { + right_(right), + has_fixed_right_arg_(false), + fixed_right_arg_value_(0) { bit_field_ |= OperatorField::encode(op); DCHECK(Token::IsBinaryOp(op)); } @@ -2171,14 +2178,14 @@ class BinaryOperation final : public Expression { static int parent_num_ids() { return Expression::num_ids(); } int local_id(int n) const { return base_id() + parent_num_ids() + n; } + FeedbackSlot feedback_slot_; + Expression* left_; + Expression* right_; + Handle<AllocationSite> allocation_site_; // TODO(rossberg): the fixed arg should probably be represented as a Constant // type for the RHS. Currenty it's actually a Maybe<int> bool has_fixed_right_arg_; int fixed_right_arg_value_; - Expression* left_; - Expression* right_; - Handle<AllocationSite> allocation_site_; - FeedbackSlot feedback_slot_; class OperatorField : public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {}; @@ -2306,11 +2313,11 @@ class CompareOperation final : public Expression { static int parent_num_ids() { return Expression::num_ids(); } int local_id(int n) const { return base_id() + parent_num_ids() + n; } + FeedbackSlot feedback_slot_; Expression* left_; Expression* right_; - AstType* combined_type_; - FeedbackSlot feedback_slot_; + class OperatorField : public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {}; }; @@ -2645,6 +2652,14 @@ class FunctionLiteral final : public Expression { bool AllowsLazyCompilation(); + bool CanSuspend() { + if (suspend_count() > 0) { + DCHECK(IsResumableFunction(kind())); + return true; + } + return false; + } + Handle<String> debug_name() const { if (raw_name_ != NULL && !raw_name_->IsEmpty()) { return raw_name_->string(); @@ -2742,6 +2757,8 @@ class FunctionLiteral final : public Expression { function_literal_id_ = function_literal_id; } + void ReplaceBodyAndScope(FunctionLiteral* other); + private: friend class AstNodeFactory; @@ -2827,6 +2844,7 @@ class ClassLiteral final : public Expression { public: typedef ClassLiteralProperty Property; + Scope* scope() const { return scope_; } VariableProxy* class_variable_proxy() const { return class_variable_proxy_; } Expression* extends() const { return extends_; } void set_extends(Expression* e) { extends_ = e; } @@ -2842,6 +2860,13 @@ class ClassLiteral final : public Expression { return HasStaticComputedNames::decode(bit_field_); } + bool is_anonymous_expression() const { + return IsAnonymousExpression::decode(bit_field_); + } + bool IsAnonymousFunctionDefinition() const { + return is_anonymous_expression(); + } + // Object literals need one feedback slot for each non-trivial value, as well // as some slots for home objects. void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode, @@ -2858,23 +2883,27 @@ class ClassLiteral final : public Expression { private: friend class AstNodeFactory; - ClassLiteral(VariableProxy* class_variable_proxy, Expression* extends, - FunctionLiteral* constructor, ZoneList<Property*>* properties, - int start_position, int end_position, - bool has_name_static_property, bool has_static_computed_names) + ClassLiteral(Scope* scope, VariableProxy* class_variable_proxy, + Expression* extends, FunctionLiteral* constructor, + ZoneList<Property*>* properties, int start_position, + int end_position, bool has_name_static_property, + bool has_static_computed_names, bool is_anonymous) : Expression(start_position, kClassLiteral), end_position_(end_position), + scope_(scope), class_variable_proxy_(class_variable_proxy), extends_(extends), constructor_(constructor), properties_(properties) { bit_field_ |= HasNameStaticProperty::encode(has_name_static_property) | - HasStaticComputedNames::encode(has_static_computed_names); + HasStaticComputedNames::encode(has_static_computed_names) | + IsAnonymousExpression::encode(is_anonymous); } int end_position_; FeedbackSlot home_object_slot_; FeedbackSlot proxy_slot_; + Scope* scope_; VariableProxy* class_variable_proxy_; Expression* extends_; FunctionLiteral* constructor_; @@ -2884,6 +2913,8 @@ class ClassLiteral final : public Expression { : public BitField<bool, Expression::kNextBitFieldIndex, 1> {}; class HasStaticComputedNames : public BitField<bool, HasNameStaticProperty::kNext, 1> {}; + class IsAnonymousExpression + : public BitField<bool, HasStaticComputedNames::kNext, 1> {}; }; @@ -2909,9 +2940,9 @@ class NativeFunctionLiteral final : public Expression { name_(name), extension_(extension) {} + FeedbackSlot literal_feedback_slot_; const AstRawString* name_; v8::Extension* extension_; - FeedbackSlot literal_feedback_slot_; }; @@ -3211,17 +3242,12 @@ class AstVisitor BASE_EMBEDDED { class AstNodeFactory final BASE_EMBEDDED { public: - explicit AstNodeFactory(AstValueFactory* ast_value_factory) - : zone_(nullptr), ast_value_factory_(ast_value_factory) { - if (ast_value_factory != nullptr) { - zone_ = ast_value_factory->zone(); - } - } + AstNodeFactory(AstValueFactory* ast_value_factory, Zone* zone) + : zone_(zone), ast_value_factory_(ast_value_factory) {} AstValueFactory* ast_value_factory() const { return ast_value_factory_; } void set_ast_value_factory(AstValueFactory* ast_value_factory) { ast_value_factory_ = ast_value_factory; - zone_ = ast_value_factory->zone(); } VariableDeclaration* NewVariableDeclaration(VariableProxy* proxy, @@ -3370,9 +3396,8 @@ class AstNodeFactory final BASE_EMBEDDED { return new (zone_) Literal(ast_value_factory_->NewSymbol(symbol), pos); } - Literal* NewNumberLiteral(double number, int pos, bool with_dot = false) { - return new (zone_) - Literal(ast_value_factory_->NewNumber(number, with_dot), pos); + Literal* NewNumberLiteral(double number, int pos) { + return new (zone_) Literal(ast_value_factory_->NewNumber(number), pos); } Literal* NewSmiLiteral(uint32_t number, int pos) { @@ -3590,15 +3615,18 @@ class AstNodeFactory final BASE_EMBEDDED { ClassLiteral::Property(key, value, kind, is_static, is_computed_name); } - ClassLiteral* NewClassLiteral(VariableProxy* proxy, Expression* extends, + ClassLiteral* NewClassLiteral(Scope* scope, VariableProxy* proxy, + Expression* extends, FunctionLiteral* constructor, ZoneList<ClassLiteral::Property*>* properties, int start_position, int end_position, bool has_name_static_property, - bool has_static_computed_names) { - return new (zone_) ClassLiteral( - proxy, extends, constructor, properties, start_position, end_position, - has_name_static_property, has_static_computed_names); + bool has_static_computed_names, + bool is_anonymous) { + return new (zone_) + ClassLiteral(scope, proxy, extends, constructor, properties, + start_position, end_position, has_name_static_property, + has_static_computed_names, is_anonymous); } NativeFunctionLiteral* NewNativeFunctionLiteral(const AstRawString* name, @@ -3646,24 +3674,6 @@ class AstNodeFactory final BASE_EMBEDDED { Zone* zone() const { return zone_; } void set_zone(Zone* zone) { zone_ = zone; } - // Handles use of temporary zones when parsing inner function bodies. - class BodyScope { - public: - BodyScope(AstNodeFactory* factory, Zone* temp_zone, bool use_temp_zone) - : factory_(factory), prev_zone_(factory->zone_) { - if (use_temp_zone) { - factory->zone_ = temp_zone; - } - } - - void Reset() { factory_->zone_ = prev_zone_; } - ~BodyScope() { Reset(); } - - private: - AstNodeFactory* factory_; - Zone* prev_zone_; - }; - private: // This zone may be deallocated upon returning from parsing a function body // which we can guarantee is not going to be compiled or have its AST diff --git a/chromium/v8/src/ast/compile-time-value.cc b/chromium/v8/src/ast/compile-time-value.cc index 27dd29fee0a..b86343d059f 100644 --- a/chromium/v8/src/ast/compile-time-value.cc +++ b/chromium/v8/src/ast/compile-time-value.cc @@ -24,28 +24,24 @@ Handle<FixedArray> CompileTimeValue::GetValue(Isolate* isolate, Factory* factory = isolate->factory(); DCHECK(IsCompileTimeValue(expression)); Handle<FixedArray> result = factory->NewFixedArray(2, TENURED); - ObjectLiteral* object_literal = expression->AsObjectLiteral(); - if (object_literal != NULL) { + if (expression->IsObjectLiteral()) { + ObjectLiteral* object_literal = expression->AsObjectLiteral(); DCHECK(object_literal->is_simple()); - if (object_literal->fast_elements()) { - result->set(kLiteralTypeSlot, Smi::FromInt(OBJECT_LITERAL_FAST_ELEMENTS)); - } else { - result->set(kLiteralTypeSlot, Smi::FromInt(OBJECT_LITERAL_SLOW_ELEMENTS)); - } + int literalTypeFlag = object_literal->EncodeLiteralType(); + DCHECK_NE(kArrayLiteralFlag, literalTypeFlag); + result->set(kLiteralTypeSlot, Smi::FromInt(literalTypeFlag)); result->set(kElementsSlot, *object_literal->constant_properties()); } else { ArrayLiteral* array_literal = expression->AsArrayLiteral(); DCHECK(array_literal != NULL && array_literal->is_simple()); - result->set(kLiteralTypeSlot, Smi::FromInt(ARRAY_LITERAL)); + result->set(kLiteralTypeSlot, Smi::FromInt(kArrayLiteralFlag)); result->set(kElementsSlot, *array_literal->constant_elements()); } return result; } -CompileTimeValue::LiteralType CompileTimeValue::GetLiteralType( - Handle<FixedArray> value) { - Smi* literal_type = Smi::cast(value->get(kLiteralTypeSlot)); - return static_cast<LiteralType>(literal_type->value()); +int CompileTimeValue::GetLiteralTypeFlags(Handle<FixedArray> value) { + return Smi::cast(value->get(kLiteralTypeSlot))->value(); } Handle<HeapObject> CompileTimeValue::GetElements(Handle<FixedArray> value) { diff --git a/chromium/v8/src/ast/compile-time-value.h b/chromium/v8/src/ast/compile-time-value.h index d61443e5835..e8ded431227 100644 --- a/chromium/v8/src/ast/compile-time-value.h +++ b/chromium/v8/src/ast/compile-time-value.h @@ -17,19 +17,20 @@ class Expression; // can be fully handled at compile time. class CompileTimeValue : public AllStatic { public: - enum LiteralType { - OBJECT_LITERAL_FAST_ELEMENTS, - OBJECT_LITERAL_SLOW_ELEMENTS, - ARRAY_LITERAL - }; + // This is a special marker used to encode array literals. The value has to be + // different from any value possibly returned by + // ObjectLiteral::EncodeLiteralType. + static const int kArrayLiteralFlag = -1; static bool IsCompileTimeValue(Expression* expression); // Get the value as a compile time value. static Handle<FixedArray> GetValue(Isolate* isolate, Expression* expression); - // Get the type of a compile time value returned by GetValue(). - static LiteralType GetLiteralType(Handle<FixedArray> value); + // Get the encoded literal type. This can either be kArrayLiteralFlag or + // encoded properties of an ObjectLiteral returned by + // ObjectLiteral::EncodeLiteralType. + static int GetLiteralTypeFlags(Handle<FixedArray> value); // Get the elements of a compile time value returned by GetValue(). static Handle<HeapObject> GetElements(Handle<FixedArray> value); diff --git a/chromium/v8/src/ast/scopes.cc b/chromium/v8/src/ast/scopes.cc index 99be5cd3431..78ff1a9d144 100644 --- a/chromium/v8/src/ast/scopes.cc +++ b/chromium/v8/src/ast/scopes.cc @@ -612,7 +612,7 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { Variable* var = DeclareVariableName(name, VAR); if (var != kDummyPreParserVariable && var != kDummyPreParserLexicalVariable) { - DCHECK(FLAG_preparser_scope_analysis); + DCHECK(FLAG_experimental_preparser_scope_analysis); var->set_maybe_assigned(); } } @@ -644,7 +644,7 @@ void DeclarationScope::Analyze(ParseInfo* info, Isolate* isolate, } if (scope->is_eval_scope() && is_sloppy(scope->language_mode())) { - AstNodeFactory factory(info->ast_value_factory()); + AstNodeFactory factory(info->ast_value_factory(), info->zone()); scope->HoistSloppyBlockFunctions(&factory); } @@ -662,7 +662,7 @@ void DeclarationScope::Analyze(ParseInfo* info, Isolate* isolate, scope->set_should_eager_compile(); if (scope->must_use_preparsed_scope_data_) { - DCHECK(FLAG_preparser_scope_analysis); + DCHECK(FLAG_experimental_preparser_scope_analysis); DCHECK_NOT_NULL(info->preparsed_scope_data()); DCHECK_EQ(scope->scope_type_, ScopeType::FUNCTION_SCOPE); info->preparsed_scope_data()->RestoreData(scope); @@ -1044,7 +1044,7 @@ Variable* DeclarationScope::DeclareParameterName( if (name == ast_value_factory->arguments_string()) { has_arguments_parameter_ = true; } - if (FLAG_preparser_scope_analysis) { + if (FLAG_experimental_preparser_scope_analysis) { Variable* var = Declare(zone(), name, VAR); params_.Add(var, zone()); return var; @@ -1205,7 +1205,7 @@ Variable* Scope::DeclareVariableName(const AstRawString* name, DCHECK(scope_info_.is_null()); // Declare the variable in the declaration scope. - if (FLAG_preparser_scope_analysis) { + if (FLAG_experimental_preparser_scope_analysis) { Variable* var = LookupLocal(name); DCHECK_NE(var, kDummyPreParserLexicalVariable); DCHECK_NE(var, kDummyPreParserVariable); @@ -1332,7 +1332,7 @@ Declaration* Scope::CheckLexDeclarationsConflictingWith( void DeclarationScope::AllocateVariables(ParseInfo* info, Isolate* isolate, AnalyzeMode mode) { // Module variables must be allocated before variable resolution - // to ensure that AccessNeedsHoleCheck() can detect import variables. + // to ensure that UpdateNeedsHoleCheck() can detect import variables. if (is_module_scope()) AsModuleScope()->AllocateModuleVariables(); ResolveVariablesRecursively(info); @@ -1371,9 +1371,10 @@ bool Scope::AllowsLazyParsingWithoutUnresolvedVariables( if (s->is_catch_scope()) continue; // With scopes do not introduce variables that need allocation. if (s->is_with_scope()) continue; - // If everything is guaranteed to be context allocated we can ignore the - // scope. - if (s->has_forced_context_allocation()) continue; + // Module scopes context-allocate all variables, and have no + // {this} or {arguments} variables whose existence depends on + // references to them. + if (s->is_module_scope()) continue; // Only block scopes and function scopes should disallow preparsing. DCHECK(s->is_block_scope() || s->is_function_scope()); return false; @@ -1407,19 +1408,6 @@ int Scope::ContextChainLengthUntilOutermostSloppyEval() const { return result; } -int Scope::MaxNestedContextChainLength() { - int max_context_chain_length = 0; - for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { - if (scope->is_function_scope()) continue; - max_context_chain_length = std::max(scope->MaxNestedContextChainLength(), - max_context_chain_length); - } - if (NeedsContext()) { - max_context_chain_length += 1; - } - return max_context_chain_length; -} - DeclarationScope* Scope::GetDeclarationScope() { Scope* scope = this; while (!scope->is_declaration_scope()) { @@ -1552,7 +1540,8 @@ void DeclarationScope::AnalyzePartially( arguments_ = nullptr; } - if (FLAG_preparser_scope_analysis && preparsed_scope_data->Producing()) { + if (FLAG_experimental_preparser_scope_analysis && + preparsed_scope_data->Producing()) { // Store the information needed for allocating the locals of this scope // and its inner scopes. preparsed_scope_data->SaveData(this); @@ -1639,6 +1628,12 @@ void PrintVar(int indent, Variable* var) { if (var->maybe_assigned() == kNotAssigned) { if (comma) PrintF(", "); PrintF("never assigned"); + comma = true; + } + if (var->initialization_flag() == kNeedsInitialization && + !var->binding_needs_init()) { + if (comma) PrintF(", "); + PrintF("hole initialization elided"); } PrintF("\n"); } @@ -1798,7 +1793,9 @@ void Scope::CheckZones() { DCHECK_NULL(scope->inner_scope_); continue; } - CHECK_EQ(scope->zone(), zone()); + if (!scope->replaced_from_parse_task()) { + CHECK_EQ(scope->zone(), zone()); + } scope->CheckZones(); } } @@ -1910,25 +1907,28 @@ void Scope::ResolveVariable(ParseInfo* info, VariableProxy* proxy) { namespace { -bool AccessNeedsHoleCheck(Variable* var, VariableProxy* proxy, Scope* scope) { +void SetNeedsHoleCheck(Variable* var, VariableProxy* proxy) { + proxy->set_needs_hole_check(); + var->ForceHoleInitialization(); +} + +void UpdateNeedsHoleCheck(Variable* var, VariableProxy* proxy, Scope* scope) { if (var->mode() == DYNAMIC_LOCAL) { // Dynamically introduced variables never need a hole check (since they're // VAR bindings, either from var or function declarations), but the variable // they shadow might need a hole check, which we want to do if we decide // that no shadowing variable was dynamically introoduced. - DCHECK(!var->binding_needs_init()); - return AccessNeedsHoleCheck(var->local_if_not_shadowed(), proxy, scope); + DCHECK_EQ(kCreatedInitialized, var->initialization_flag()); + return UpdateNeedsHoleCheck(var->local_if_not_shadowed(), proxy, scope); } - if (!var->binding_needs_init()) { - return false; - } + if (var->initialization_flag() == kCreatedInitialized) return; // It's impossible to eliminate module import hole checks here, because it's // unknown at compilation time whether the binding referred to in the // exporting module itself requires hole checks. if (var->location() == VariableLocation::MODULE && !var->IsExport()) { - return true; + return SetNeedsHoleCheck(var, proxy); } // Check if the binding really needs an initialization check. The check @@ -1939,7 +1939,7 @@ bool AccessNeedsHoleCheck(Variable* var, VariableProxy* proxy, Scope* scope) { // the source physically located after the initializer of the variable, // and that the initializer cannot be skipped due to a nonlinear scope. // - // The condition on the declaration scopes is a conservative check for + // The condition on the closure scopes is a conservative check for // nested functions that access a binding and are called before the // binding is initialized: // function() { f(); let x = 1; function f() { x = 2; } } @@ -1949,22 +1949,24 @@ bool AccessNeedsHoleCheck(Variable* var, VariableProxy* proxy, Scope* scope) { // switch (1) { case 0: let x = 2; case 1: f(x); } // The scope of the variable needs to be checked, in case the use is // in a sub-block which may be linear. - if (var->scope()->GetDeclarationScope() != scope->GetDeclarationScope()) { - return true; + if (var->scope()->GetClosureScope() != scope->GetClosureScope()) { + return SetNeedsHoleCheck(var, proxy); } if (var->is_this()) { - DCHECK(IsDerivedConstructor(scope->GetDeclarationScope()->function_kind())); + DCHECK(IsDerivedConstructor(scope->GetClosureScope()->function_kind())); // TODO(littledan): implement 'this' hole check elimination. - return true; + return SetNeedsHoleCheck(var, proxy); } // We should always have valid source positions. DCHECK(var->initializer_position() != kNoSourcePosition); DCHECK(proxy->position() != kNoSourcePosition); - return var->scope()->is_nonlinear() || - var->initializer_position() >= proxy->position(); + if (var->scope()->is_nonlinear() || + var->initializer_position() >= proxy->position()) { + return SetNeedsHoleCheck(var, proxy); + } } } // anonymous namespace @@ -1992,7 +1994,7 @@ void Scope::ResolveTo(ParseInfo* info, VariableProxy* proxy, Variable* var) { #endif DCHECK_NOT_NULL(var); - if (AccessNeedsHoleCheck(var, proxy, this)) proxy->set_needs_hole_check(); + UpdateNeedsHoleCheck(var, proxy, this); proxy->BindTo(var); } @@ -2031,7 +2033,7 @@ VariableProxy* Scope::FetchFreeVariables(DeclarationScope* max_outer_scope, ParseInfo* info, VariableProxy* stack) { // Module variables must be allocated before variable resolution - // to ensure that AccessNeedsHoleCheck() can detect import variables. + // to ensure that UpdateNeedsHoleCheck() can detect import variables. if (info != nullptr && is_module_scope()) { AsModuleScope()->AllocateModuleVariables(); } @@ -2257,7 +2259,8 @@ void ModuleScope::AllocateModuleVariables() { void Scope::AllocateVariablesRecursively() { DCHECK(!already_resolved_); - DCHECK_IMPLIES(!FLAG_preparser_scope_analysis, num_stack_slots_ == 0); + DCHECK_IMPLIES(!FLAG_experimental_preparser_scope_analysis, + num_stack_slots_ == 0); // Don't allocate variables of preparsed scopes. if (is_declaration_scope() && AsDeclarationScope()->was_lazily_parsed()) { diff --git a/chromium/v8/src/ast/scopes.h b/chromium/v8/src/ast/scopes.h index c7de9e88eea..35c0bb0b2de 100644 --- a/chromium/v8/src/ast/scopes.h +++ b/chromium/v8/src/ast/scopes.h @@ -400,10 +400,6 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { // sloppy eval call. One if this->calls_sloppy_eval(). int ContextChainLengthUntilOutermostSloppyEval() const; - // The maximum number of nested contexts required for this scope and any inner - // scopes. - int MaxNestedContextChainLength(); - // Find the first function, script, eval or (declaration) block scope. This is // the scope where var declarations will be hoisted to in the implementation. DeclarationScope* GetDeclarationScope(); @@ -456,6 +452,11 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { // Check that all Scopes in the scope tree use the same Zone. void CheckZones(); + + bool replaced_from_parse_task() const { return replaced_from_parse_task_; } + void set_replaced_from_parse_task(bool replaced_from_parse_task) { + replaced_from_parse_task_ = replaced_from_parse_task; + } #endif // Retrieve `IsSimpleParameterList` of current or outer function. @@ -535,6 +536,10 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { // True if this scope may contain objects from a temp zone that needs to be // fixed up. bool needs_migration_; + + // True if scope comes from other zone - as a result of being created in a + // parse tasks. + bool replaced_from_parse_task_ = false; #endif // Source positions. @@ -651,7 +656,12 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { } // Inform the scope that the corresponding code uses "super". - void RecordSuperPropertyUsage() { scope_uses_super_property_ = true; } + void RecordSuperPropertyUsage() { + DCHECK((IsConciseMethod(function_kind()) || + IsAccessorFunction(function_kind()) || + IsClassConstructor(function_kind()))); + scope_uses_super_property_ = true; + } // Does this scope access "super" property (super.foo). bool uses_super_property() const { return scope_uses_super_property_; } diff --git a/chromium/v8/src/ast/variables.cc b/chromium/v8/src/ast/variables.cc index cd1d8f77b71..c6611bd0d96 100644 --- a/chromium/v8/src/ast/variables.cc +++ b/chromium/v8/src/ast/variables.cc @@ -27,6 +27,7 @@ Variable::Variable(Scope* scope, const AstRawString* name, VariableMode mode, InitializationFlagField::encode(initialization_flag) | VariableModeField::encode(mode) | IsUsedField::encode(false) | ForceContextAllocationField::encode(false) | + ForceHoleInitializationField::encode(false) | LocationField::encode(VariableLocation::UNALLOCATED) | VariableKindField::encode(kind)) { // Var declared variables never need initialization. diff --git a/chromium/v8/src/ast/variables.h b/chromium/v8/src/ast/variables.h index 3eaa105168d..c01db362744 100644 --- a/chromium/v8/src/ast/variables.h +++ b/chromium/v8/src/ast/variables.h @@ -66,11 +66,47 @@ class Variable final : public ZoneObject { bool IsGlobalObjectProperty() const; bool is_dynamic() const { return IsDynamicVariableMode(mode()); } + + // Returns the InitializationFlag this Variable was created with. + // Scope analysis may allow us to relax this initialization + // requirement, which will be reflected in the return value of + // binding_needs_init(). + InitializationFlag initialization_flag() const { + return InitializationFlagField::decode(bit_field_); + } + + // Whether this variable needs to be initialized with the hole at + // declaration time. Only returns valid results after scope analysis. bool binding_needs_init() const { - DCHECK(initialization_flag() != kNeedsInitialization || - IsLexicalVariableMode(mode())); + DCHECK_IMPLIES(initialization_flag() == kNeedsInitialization, + IsLexicalVariableMode(mode())); + DCHECK_IMPLIES(ForceHoleInitializationField::decode(bit_field_), + initialization_flag() == kNeedsInitialization); + + // Always initialize if hole initialization was forced during + // scope analysis. + if (ForceHoleInitializationField::decode(bit_field_)) return true; + + // If initialization was not forced, no need for initialization + // for stack allocated variables, since UpdateNeedsHoleCheck() + // in scopes.cc has proven that no VariableProxy refers to + // this variable in such a way that a runtime hole check + // would be generated. + if (IsStackAllocated()) return false; + + // Otherwise, defer to the flag set when this Variable was constructed. return initialization_flag() == kNeedsInitialization; } + + // Called during scope analysis when a VariableProxy is found to + // reference this Variable in such a way that a hole check will + // be required at runtime. + void ForceHoleInitialization() { + DCHECK_EQ(kNeedsInitialization, initialization_flag()); + DCHECK(IsLexicalVariableMode(mode())); + bit_field_ = ForceHoleInitializationField::update(bit_field_, true); + } + bool throw_on_const_assignment(LanguageMode language_mode) const { return kind() != SLOPPY_FUNCTION_NAME_VARIABLE || is_strict(language_mode); } @@ -94,9 +130,6 @@ class Variable final : public ZoneObject { return LocationField::decode(bit_field_); } VariableKind kind() const { return VariableKindField::decode(bit_field_); } - InitializationFlag initialization_flag() const { - return InitializationFlagField::decode(bit_field_); - } int index() const { return index_; } @@ -152,10 +185,12 @@ class Variable final : public ZoneObject { class IsUsedField : public BitField16<bool, ForceContextAllocationField::kNext, 1> {}; class InitializationFlagField - : public BitField16<InitializationFlag, IsUsedField::kNext, 2> {}; + : public BitField16<InitializationFlag, IsUsedField::kNext, 1> {}; + class ForceHoleInitializationField + : public BitField16<bool, InitializationFlagField::kNext, 1> {}; class MaybeAssignedFlagField - : public BitField16<MaybeAssignedFlag, InitializationFlagField::kNext, - 2> {}; + : public BitField16<MaybeAssignedFlag, + ForceHoleInitializationField::kNext, 1> {}; Variable** next() { return &next_; } friend List; }; |