diff options
author | Michaël Zasso <targos@protonmail.com> | 2017-06-06 10:28:14 +0200 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2017-06-07 10:33:31 +0200 |
commit | 3dc8c3bed4cf3a77607edbb0b015e33f8b60fc09 (patch) | |
tree | 9dee56e142638b34f1eccbd0ad88c3bce5377c29 /deps/v8/src/ast | |
parent | 91a1bbe3055a660194ca4d403795aa0c03e9d056 (diff) | |
download | android-node-v8-3dc8c3bed4cf3a77607edbb0b015e33f8b60fc09.tar.gz android-node-v8-3dc8c3bed4cf3a77607edbb0b015e33f8b60fc09.tar.bz2 android-node-v8-3dc8c3bed4cf3a77607edbb0b015e33f8b60fc09.zip |
deps: update V8 to 5.9.211.32
PR-URL: https://github.com/nodejs/node/pull/13263
Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com>
Reviewed-By: Myles Borins <myles.borins@gmail.com>
Diffstat (limited to 'deps/v8/src/ast')
-rw-r--r-- | deps/v8/src/ast/ast-expression-rewriter.cc | 9 | ||||
-rw-r--r-- | deps/v8/src/ast/ast-numbering.cc | 75 | ||||
-rw-r--r-- | deps/v8/src/ast/ast-numbering.h | 30 | ||||
-rw-r--r-- | deps/v8/src/ast/ast-traversal-visitor.h | 9 | ||||
-rw-r--r-- | deps/v8/src/ast/ast-types.cc | 4 | ||||
-rw-r--r-- | deps/v8/src/ast/ast-value-factory.cc | 86 | ||||
-rw-r--r-- | deps/v8/src/ast/ast-value-factory.h | 211 | ||||
-rw-r--r-- | deps/v8/src/ast/ast.cc | 68 | ||||
-rw-r--r-- | deps/v8/src/ast/ast.h | 175 | ||||
-rw-r--r-- | deps/v8/src/ast/context-slot-cache.h | 2 | ||||
-rw-r--r-- | deps/v8/src/ast/modules.h | 3 | ||||
-rw-r--r-- | deps/v8/src/ast/prettyprinter.cc | 73 | ||||
-rw-r--r-- | deps/v8/src/ast/scopes.cc | 264 | ||||
-rw-r--r-- | deps/v8/src/ast/scopes.h | 77 | ||||
-rw-r--r-- | deps/v8/src/ast/variables.h | 6 |
15 files changed, 691 insertions, 401 deletions
diff --git a/deps/v8/src/ast/ast-expression-rewriter.cc b/deps/v8/src/ast/ast-expression-rewriter.cc index f46e21b410..d23612f2b4 100644 --- a/deps/v8/src/ast/ast-expression-rewriter.cc +++ b/deps/v8/src/ast/ast-expression-rewriter.cc @@ -265,8 +265,7 @@ void AstExpressionRewriter::VisitAssignment(Assignment* node) { AST_REWRITE_PROPERTY(Expression, node, value); } - -void AstExpressionRewriter::VisitYield(Yield* node) { +void AstExpressionRewriter::VisitSuspend(Suspend* node) { REWRITE_THIS(node); AST_REWRITE_PROPERTY(Expression, node, generator_object); AST_REWRITE_PROPERTY(Expression, node, expression); @@ -377,6 +376,12 @@ void AstExpressionRewriter::VisitGetIterator(GetIterator* node) { AST_REWRITE_PROPERTY(Expression, node, iterable); } +void AstExpressionRewriter::VisitImportCallExpression( + ImportCallExpression* node) { + REWRITE_THIS(node); + AST_REWRITE_PROPERTY(Expression, node, argument); +} + void AstExpressionRewriter::VisitDoExpression(DoExpression* node) { REWRITE_THIS(node); AST_REWRITE_PROPERTY(Block, node, block); diff --git a/deps/v8/src/ast/ast-numbering.cc b/deps/v8/src/ast/ast-numbering.cc index 499760de14..24ccf79244 100644 --- a/deps/v8/src/ast/ast-numbering.cc +++ b/deps/v8/src/ast/ast-numbering.cc @@ -15,17 +15,19 @@ namespace internal { class AstNumberingVisitor final : public AstVisitor<AstNumberingVisitor> { public: AstNumberingVisitor(uintptr_t stack_limit, Zone* zone, - Compiler::EagerInnerFunctionLiterals* eager_literals) + Compiler::EagerInnerFunctionLiterals* eager_literals, + bool collect_type_profile = false) : zone_(zone), eager_literals_(eager_literals), next_id_(BailoutId::FirstUsable().ToInt()), - yield_count_(0), + suspend_count_(0), properties_(zone), language_mode_(SLOPPY), slot_cache_(zone), disable_crankshaft_reason_(kNoReason), dont_optimize_reason_(kNoReason), - catch_prediction_(HandlerTable::UNCAUGHT) { + catch_prediction_(HandlerTable::UNCAUGHT), + collect_type_profile_(collect_type_profile) { InitializeAstVisitor(stack_limit); } @@ -93,7 +95,7 @@ class AstNumberingVisitor final : public AstVisitor<AstNumberingVisitor> { Zone* zone_; Compiler::EagerInnerFunctionLiterals* eager_literals_; int next_id_; - int yield_count_; + int suspend_count_; AstProperties properties_; LanguageMode language_mode_; // The slot cache allows us to reuse certain feedback slots. @@ -101,6 +103,7 @@ class AstNumberingVisitor final : public AstVisitor<AstNumberingVisitor> { BailoutReason disable_crankshaft_reason_; BailoutReason dont_optimize_reason_; HandlerTable::CatchPrediction catch_prediction_; + bool collect_type_profile_; DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); DISALLOW_COPY_AND_ASSIGN(AstNumberingVisitor); @@ -238,12 +241,11 @@ void AstNumberingVisitor::VisitReturnStatement(ReturnStatement* node) { properties_.flags() & AstProperties::kMustUseIgnitionTurbo); } - -void AstNumberingVisitor::VisitYield(Yield* node) { - node->set_yield_id(yield_count_); - yield_count_++; +void AstNumberingVisitor::VisitSuspend(Suspend* node) { + node->set_suspend_id(suspend_count_); + suspend_count_++; IncrementNodeCount(); - node->set_base_id(ReserveIdRange(Yield::num_ids())); + node->set_base_id(ReserveIdRange(Suspend::num_ids())); Visit(node->generator_object()); Visit(node->expression()); } @@ -322,10 +324,17 @@ void AstNumberingVisitor::VisitCallRuntime(CallRuntime* node) { // has to stash it somewhere. Changing the runtime function into another // one in ast-numbering seemed like a simple and straightforward solution to // that problem. - if (node->is_jsruntime() && - node->context_index() == Context::ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX && - catch_prediction_ == HandlerTable::ASYNC_AWAIT) { - node->set_context_index(Context::ASYNC_FUNCTION_AWAIT_UNCAUGHT_INDEX); + if (node->is_jsruntime() && catch_prediction_ == HandlerTable::ASYNC_AWAIT) { + switch (node->context_index()) { + case Context::ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX: + node->set_context_index(Context::ASYNC_FUNCTION_AWAIT_UNCAUGHT_INDEX); + break; + case Context::ASYNC_GENERATOR_AWAIT_CAUGHT: + node->set_context_index(Context::ASYNC_GENERATOR_AWAIT_UNCAUGHT); + break; + default: + break; + } } } @@ -342,10 +351,10 @@ void AstNumberingVisitor::VisitDoWhileStatement(DoWhileStatement* node) { IncrementNodeCount(); DisableSelfOptimization(); node->set_base_id(ReserveIdRange(DoWhileStatement::num_ids())); - node->set_first_yield_id(yield_count_); + node->set_first_suspend_id(suspend_count_); Visit(node->body()); Visit(node->cond()); - node->set_yield_count(yield_count_ - node->first_yield_id()); + node->set_suspend_count(suspend_count_ - node->first_suspend_id()); } @@ -353,10 +362,10 @@ void AstNumberingVisitor::VisitWhileStatement(WhileStatement* node) { IncrementNodeCount(); DisableSelfOptimization(); node->set_base_id(ReserveIdRange(WhileStatement::num_ids())); - node->set_first_yield_id(yield_count_); + node->set_first_suspend_id(suspend_count_); Visit(node->cond()); Visit(node->body()); - node->set_yield_count(yield_count_ - node->first_yield_id()); + node->set_suspend_count(suspend_count_ - node->first_suspend_id()); } @@ -463,15 +472,22 @@ void AstNumberingVisitor::VisitGetIterator(GetIterator* node) { ReserveFeedbackSlots(node); } +void AstNumberingVisitor::VisitImportCallExpression( + ImportCallExpression* node) { + IncrementNodeCount(); + DisableFullCodegenAndCrankshaft(kDynamicImport); + Visit(node->argument()); +} + void AstNumberingVisitor::VisitForInStatement(ForInStatement* node) { IncrementNodeCount(); DisableSelfOptimization(); node->set_base_id(ReserveIdRange(ForInStatement::num_ids())); Visit(node->enumerable()); // Not part of loop. - node->set_first_yield_id(yield_count_); + node->set_first_suspend_id(suspend_count_); Visit(node->each()); Visit(node->body()); - node->set_yield_count(yield_count_ - node->first_yield_id()); + node->set_suspend_count(suspend_count_ - node->first_suspend_id()); ReserveFeedbackSlots(node); } @@ -481,12 +497,12 @@ void AstNumberingVisitor::VisitForOfStatement(ForOfStatement* node) { DisableFullCodegenAndCrankshaft(kForOfStatement); node->set_base_id(ReserveIdRange(ForOfStatement::num_ids())); Visit(node->assign_iterator()); // Not part of loop. - node->set_first_yield_id(yield_count_); + node->set_first_suspend_id(suspend_count_); Visit(node->next_result()); Visit(node->result_done()); Visit(node->assign_each()); Visit(node->body()); - node->set_yield_count(yield_count_ - node->first_yield_id()); + node->set_suspend_count(suspend_count_ - node->first_suspend_id()); } @@ -535,11 +551,11 @@ void AstNumberingVisitor::VisitForStatement(ForStatement* node) { DisableSelfOptimization(); node->set_base_id(ReserveIdRange(ForStatement::num_ids())); if (node->init() != NULL) Visit(node->init()); // Not part of loop. - node->set_first_yield_id(yield_count_); + node->set_first_suspend_id(suspend_count_); if (node->cond() != NULL) Visit(node->cond()); if (node->next() != NULL) Visit(node->next()); Visit(node->body()); - node->set_yield_count(yield_count_ - node->first_yield_id()); + node->set_suspend_count(suspend_count_ - node->first_suspend_id()); } @@ -616,6 +632,7 @@ void AstNumberingVisitor::VisitStatements(ZoneList<Statement*>* statements) { if (statements == NULL) return; for (int i = 0; i < statements->length(); i++) { Visit(statements->at(i)); + if (statements->at(i)->IsJump()) break; } } @@ -687,12 +704,16 @@ bool AstNumberingVisitor::Renumber(FunctionLiteral* node) { LanguageModeScope language_mode_scope(this, node->language_mode()); + if (collect_type_profile_) { + properties_.get_spec()->AddTypeProfileSlot(); + } + VisitDeclarations(scope->declarations()); VisitStatements(node->body()); node->set_ast_properties(&properties_); node->set_dont_optimize_reason(dont_optimize_reason()); - node->set_yield_count(yield_count_); + node->set_suspend_count(suspend_count_); if (FLAG_trace_opt) { if (disable_crankshaft_reason_ != kNoReason) { @@ -714,12 +735,14 @@ bool AstNumberingVisitor::Renumber(FunctionLiteral* node) { bool AstNumbering::Renumber( uintptr_t stack_limit, Zone* zone, FunctionLiteral* function, - Compiler::EagerInnerFunctionLiterals* eager_literals) { + Compiler::EagerInnerFunctionLiterals* eager_literals, + bool collect_type_profile) { DisallowHeapAllocation no_allocation; DisallowHandleAllocation no_handles; DisallowHandleDereference no_deref; - AstNumberingVisitor visitor(stack_limit, zone, eager_literals); + AstNumberingVisitor visitor(stack_limit, zone, eager_literals, + collect_type_profile); return visitor.Renumber(function); } } // namespace internal diff --git a/deps/v8/src/ast/ast-numbering.h b/deps/v8/src/ast/ast-numbering.h index bea441d67b..82987ef593 100644 --- a/deps/v8/src/ast/ast-numbering.h +++ b/deps/v8/src/ast/ast-numbering.h @@ -22,29 +22,33 @@ template <typename T> class ZoneVector; namespace AstNumbering { -// Assign type feedback IDs, bailout IDs, and generator yield IDs to an AST node -// tree; perform catch prediction for TryStatements. If |eager_literals| is +// Assign type feedback IDs, bailout IDs, and generator suspend IDs to an AST +// node tree; perform catch prediction for TryStatements. If |eager_literals| is // non-null, adds any eager inner literal functions into it. bool Renumber( uintptr_t stack_limit, Zone* zone, FunctionLiteral* function, - ThreadedList<ThreadedListZoneEntry<FunctionLiteral*>>* eager_literals); + ThreadedList<ThreadedListZoneEntry<FunctionLiteral*>>* eager_literals, + bool collect_type_profile = false); } -// Some details on yield IDs +// Some details on suspend IDs // ------------------------- // // In order to assist Ignition in generating bytecode for a generator function, -// we assign a unique number (the yield ID) to each Yield node in its AST. We -// also annotate loops with the number of yields they contain (loop.yield_count) -// and the smallest ID of those (loop.first_yield_id), and we annotate the -// function itself with the number of yields it contains (function.yield_count). +// we assign a unique number (the suspend ID) to each Suspend node in its AST. +// We also annotate loops with the number of suspends they contain +// (loop.suspend_count) and the smallest ID of those (loop.first_suspend_id), +// and we annotate the function itself with the number of suspends it contains +// (function.suspend_count). // -// The way in which we choose the IDs is simply by enumerating the Yield nodes. +// The way in which we choose the IDs is simply by enumerating the Suspend +// nodes. // Ignition relies on the following properties: -// - For each loop l and each yield y of l: -// l.first_yield_id <= y.yield_id < l.first_yield_id + l.yield_count -// - For the generator function f itself and each yield y of f: -// 0 <= y.yield_id < f.yield_count +// - For each loop l and each suspend y of l: +// l.first_suspend_id <= +// s.suspend_id < l.first_suspend_id + l.suspend_count +// - For the generator function f itself and each suspend s of f: +// 0 <= s.suspend_id < f.suspend_count } // namespace internal } // namespace v8 diff --git a/deps/v8/src/ast/ast-traversal-visitor.h b/deps/v8/src/ast/ast-traversal-visitor.h index 6d0c386f3b..390ba6db3a 100644 --- a/deps/v8/src/ast/ast-traversal-visitor.h +++ b/deps/v8/src/ast/ast-traversal-visitor.h @@ -357,7 +357,7 @@ void AstTraversalVisitor<Subclass>::VisitAssignment(Assignment* expr) { } template <class Subclass> -void AstTraversalVisitor<Subclass>::VisitYield(Yield* expr) { +void AstTraversalVisitor<Subclass>::VisitSuspend(Suspend* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->generator_object())); RECURSE_EXPRESSION(Visit(expr->expression())); @@ -477,6 +477,13 @@ void AstTraversalVisitor<Subclass>::VisitGetIterator(GetIterator* expr) { } template <class Subclass> +void AstTraversalVisitor<Subclass>::VisitImportCallExpression( + ImportCallExpression* expr) { + PROCESS_EXPRESSION(expr); + RECURSE_EXPRESSION(Visit(expr->argument())); +} + +template <class Subclass> void AstTraversalVisitor<Subclass>::VisitSuperPropertyReference( SuperPropertyReference* expr) { PROCESS_EXPRESSION(expr); diff --git a/deps/v8/src/ast/ast-types.cc b/deps/v8/src/ast/ast-types.cc index 3dde86413a..9e14730c97 100644 --- a/deps/v8/src/ast/ast-types.cc +++ b/deps/v8/src/ast/ast-types.cc @@ -186,7 +186,6 @@ AstType::bitset AstBitsetType::Lub(i::Map* map) { if (map == heap->boolean_map()) return kBoolean; if (map == heap->the_hole_map()) return kHole; DCHECK(map == heap->uninitialized_map() || - map == heap->no_interceptor_result_sentinel_map() || map == heap->termination_exception_map() || map == heap->arguments_marker_map() || map == heap->optimized_out_map() || @@ -209,6 +208,7 @@ AstType::bitset AstBitsetType::Lub(i::Map* map) { case JS_DATE_TYPE: case JS_CONTEXT_EXTENSION_OBJECT_TYPE: case JS_GENERATOR_OBJECT_TYPE: + case JS_ASYNC_GENERATOR_OBJECT_TYPE: case JS_MODULE_NAMESPACE_TYPE: case JS_ARRAY_BUFFER_TYPE: case JS_ARRAY_TYPE: @@ -287,6 +287,7 @@ AstType::bitset AstBitsetType::Lub(i::Map* map) { case PROPERTY_CELL_TYPE: case MODULE_TYPE: case MODULE_INFO_ENTRY_TYPE: + case ASYNC_GENERATOR_REQUEST_TYPE: return kOtherInternal & kTaggedPointer; // Remaining instance types are unsupported for now. If any of them do @@ -311,6 +312,7 @@ AstType::bitset AstBitsetType::Lub(i::Map* map) { 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: case PROTOTYPE_INFO_TYPE: diff --git a/deps/v8/src/ast/ast-value-factory.cc b/deps/v8/src/ast/ast-value-factory.cc index b160c48a20..74613c5eae 100644 --- a/deps/v8/src/ast/ast-value-factory.cc +++ b/deps/v8/src/ast/ast-value-factory.cc @@ -84,21 +84,8 @@ class AstRawStringInternalizationKey : public HashTableKey { const AstRawString* string_; }; -int AstString::length() const { - if (IsRawStringBits::decode(bit_field_)) { - return reinterpret_cast<const AstRawString*>(this)->length(); - } - return reinterpret_cast<const AstConsString*>(this)->length(); -} - -void AstString::Internalize(Isolate* isolate) { - if (IsRawStringBits::decode(bit_field_)) { - return reinterpret_cast<AstRawString*>(this)->Internalize(isolate); - } - return reinterpret_cast<AstConsString*>(this)->Internalize(isolate); -} - void AstRawString::Internalize(Isolate* isolate) { + DCHECK(!has_string_); if (literal_bytes_.length() == 0) { set_string(isolate->factory()->empty_string()); } else { @@ -121,18 +108,26 @@ bool AstRawString::AsArrayIndex(uint32_t* index) const { } bool AstRawString::IsOneByteEqualTo(const char* data) const { - int length = static_cast<int>(strlen(data)); - if (is_one_byte() && literal_bytes_.length() == length) { - const char* token = reinterpret_cast<const char*>(literal_bytes_.start()); - return !strncmp(token, data, length); - } - return false; + if (!is_one_byte()) return false; + + size_t length = static_cast<size_t>(literal_bytes_.length()); + if (length != strlen(data)) return false; + + return 0 == strncmp(reinterpret_cast<const char*>(literal_bytes_.start()), + data, length); +} + +uint16_t AstRawString::FirstCharacter() const { + if (is_one_byte()) return literal_bytes_[0]; + const uint16_t* c = reinterpret_cast<const uint16_t*>(literal_bytes_.start()); + return *c; } bool AstRawString::Compare(void* a, void* b) { const AstRawString* lhs = static_cast<AstRawString*>(a); const AstRawString* rhs = static_cast<AstRawString*>(b); DCHECK_EQ(lhs->hash(), rhs->hash()); + if (lhs->length() != rhs->length()) return false; const unsigned char* l = lhs->raw_data(); const unsigned char* r = rhs->raw_data(); @@ -161,11 +156,20 @@ bool AstRawString::Compare(void* a, void* b) { } void AstConsString::Internalize(Isolate* isolate) { - // AstRawStrings are internalized before AstConsStrings so left and right are - // already internalized. - set_string(isolate->factory() - ->NewConsString(left_->string(), right_->string()) - .ToHandleChecked()); + if (IsEmpty()) { + set_string(isolate->factory()->empty_string()); + return; + } + // AstRawStrings are internalized before AstConsStrings, so + // AstRawString::string() will just work. + Handle<String> tmp(segment_.string->string()); + for (AstConsString::Segment* current = segment_.next; current != nullptr; + current = current->next) { + tmp = isolate->factory() + ->NewConsString(current->string->string(), tmp) + .ToHandleChecked(); + } + set_string(tmp); } bool AstValue::IsPropertyName() const { @@ -285,22 +289,34 @@ const AstRawString* AstValueFactory::GetString(Handle<String> literal) { return result; } - -const AstConsString* AstValueFactory::NewConsString( - const AstString* left, const AstString* right) { - // This Vector will be valid as long as the Collector is alive (meaning that - // the AstRawString will not be moved). - AstConsString* new_string = new (zone_) AstConsString(left, right); - CHECK(new_string != nullptr); - AddString(new_string); +AstConsString* AstValueFactory::NewConsString() { + AstConsString* new_string = new (zone_) AstConsString; + DCHECK_NOT_NULL(new_string); + AddConsString(new_string); return new_string; } +AstConsString* AstValueFactory::NewConsString(const AstRawString* str) { + return NewConsString()->AddString(zone_, str); +} + +AstConsString* AstValueFactory::NewConsString(const AstRawString* str1, + const AstRawString* str2) { + return NewConsString()->AddString(zone_, str1)->AddString(zone_, str2); +} + void AstValueFactory::Internalize(Isolate* isolate) { // Strings need to be internalized before values, because values refer to // strings. - for (AstString* current = strings_; current != nullptr;) { - AstString* next = current->next(); + for (AstRawString* current = strings_; current != nullptr;) { + AstRawString* next = current->next(); + current->Internalize(isolate); + current = next; + } + + // AstConsStrings refer to AstRawStrings. + for (AstConsString* current = cons_strings_; current != nullptr;) { + AstConsString* next = current->next(); current->Internalize(isolate); current = next; } diff --git a/deps/v8/src/ast/ast-value-factory.h b/deps/v8/src/ast/ast-value-factory.h index c1ed7acc57..19452bc325 100644 --- a/deps/v8/src/ast/ast-value-factory.h +++ b/deps/v8/src/ast/ast-value-factory.h @@ -35,123 +35,144 @@ #include "src/isolate.h" #include "src/utils.h" -// AstString, AstValue and AstValueFactory are for storing strings and values -// independent of the V8 heap and internalizing them later. During parsing, -// AstStrings and AstValues are created and stored outside the heap, in -// AstValueFactory. After parsing, the strings and values are internalized -// (moved into the V8 heap). +// Ast(Raw|Cons)String, AstValue and AstValueFactory are for storing strings and +// values independent of the V8 heap and internalizing them later. During +// parsing, they are created and stored outside the heap, in AstValueFactory. +// After parsing, the strings and values are internalized (moved into the V8 +// heap). namespace v8 { namespace internal { -class AstString : public ZoneObject { - public: - explicit AstString(bool is_raw) - : next_(nullptr), bit_field_(IsRawStringBits::encode(is_raw)) {} - - int length() const; - bool IsEmpty() const { return length() == 0; } - - // Puts the string into the V8 heap. - void Internalize(Isolate* isolate); - - // This function can be called after internalizing. - V8_INLINE Handle<String> string() const { - DCHECK_NOT_NULL(string_); - return Handle<String>(string_); - } - - AstString* next() { return next_; } - AstString** next_location() { return &next_; } - - protected: - void set_string(Handle<String> string) { string_ = string.location(); } - // {string_} is stored as String** instead of a Handle<String> so it can be - // stored in a union with {next_}. - union { - AstString* next_; - String** string_; - }; - // Poor-man's virtual dispatch to AstRawString / AstConsString. Takes less - // memory. - class IsRawStringBits : public BitField<bool, 0, 1> {}; - int bit_field_; -}; - - -class AstRawString final : public AstString { +class AstRawString final : public ZoneObject { public: + bool IsEmpty() const { return literal_bytes_.length() == 0; } int length() const { - if (is_one_byte()) return literal_bytes_.length(); - return literal_bytes_.length() / 2; + return is_one_byte() ? literal_bytes_.length() + : literal_bytes_.length() / 2; } - - int byte_length() const { return literal_bytes_.length(); } + bool AsArrayIndex(uint32_t* index) const; + bool IsOneByteEqualTo(const char* data) const; + uint16_t FirstCharacter() const; void Internalize(Isolate* isolate); - bool AsArrayIndex(uint32_t* index) const; - - // The string is not null-terminated, use length() to find out the length. + // Access the physical representation: + bool is_one_byte() const { return is_one_byte_; } + int byte_length() const { return literal_bytes_.length(); } const unsigned char* raw_data() const { return literal_bytes_.start(); } - bool is_one_byte() const { return IsOneByteBits::decode(bit_field_); } - - bool IsOneByteEqualTo(const char* data) const; - uint16_t FirstCharacter() const { - if (is_one_byte()) return literal_bytes_[0]; - const uint16_t* c = - reinterpret_cast<const uint16_t*>(literal_bytes_.start()); - return *c; - } - - static bool Compare(void* a, void* b); - // For storing AstRawStrings in a hash map. uint32_t hash() const { return hash_; } + // This function can be called after internalizing. + V8_INLINE Handle<String> string() const { + DCHECK_NOT_NULL(string_); + DCHECK(has_string_); + return Handle<String>(string_); + } + private: friend class AstRawStringInternalizationKey; friend class AstStringConstants; friend class AstValueFactory; + // Members accessed only by the AstValueFactory & related classes: + static bool Compare(void* a, void* b); AstRawString(bool is_one_byte, const Vector<const byte>& literal_bytes, uint32_t hash) - : AstString(true), hash_(hash), literal_bytes_(literal_bytes) { - bit_field_ |= IsOneByteBits::encode(is_one_byte); + : next_(nullptr), + literal_bytes_(literal_bytes), + hash_(hash), + is_one_byte_(is_one_byte) {} + AstRawString* next() { + DCHECK(!has_string_); + return next_; + } + AstRawString** next_location() { + DCHECK(!has_string_); + return &next_; } - AstRawString() : AstString(true), hash_(0) { - bit_field_ |= IsOneByteBits::encode(true); + void set_string(Handle<String> string) { + DCHECK(!string.is_null()); + DCHECK(!has_string_); + string_ = string.location(); +#ifdef DEBUG + has_string_ = true; +#endif } - class IsOneByteBits : public BitField<bool, IsRawStringBits::kNext, 1> {}; + // {string_} is stored as String** instead of a Handle<String> so it can be + // stored in a union with {next_}. + union { + AstRawString* next_; + String** string_; + }; + Vector<const byte> literal_bytes_; // Memory owned by Zone. uint32_t hash_; - // Points to memory owned by Zone. - Vector<const byte> literal_bytes_; + bool is_one_byte_; +#ifdef DEBUG + // (Debug-only:) Verify the object life-cylce: Some functions may only be + // called after internalization (that is, after a v8::internal::String has + // been set); some only before. + bool has_string_ = false; +#endif }; - -class AstConsString final : public AstString { +class AstConsString final : public ZoneObject { public: - AstConsString(const AstString* left, const AstString* right) - : AstString(false), - length_(left->length() + right->length()), - left_(left), - right_(right) {} + AstConsString* AddString(Zone* zone, const AstRawString* s) { + if (s->IsEmpty()) return this; + if (!IsEmpty()) { + // We're putting the new string to the head of the list, meaning + // the string segments will be in reverse order. + Segment* tmp = new (zone->New(sizeof(Segment))) Segment; + *tmp = segment_; + segment_.next = tmp; + } + segment_.string = s; + return this; + } - int length() const { return length_; } + bool IsEmpty() const { + DCHECK_IMPLIES(segment_.string == nullptr, segment_.next == nullptr); + DCHECK_IMPLIES(segment_.string != nullptr, !segment_.string->IsEmpty()); + return segment_.string == nullptr; + } void Internalize(Isolate* isolate); + V8_INLINE Handle<String> string() const { + DCHECK_NOT_NULL(string_); + return Handle<String>(string_); + } + private: - const int length_; - const AstString* left_; - const AstString* right_; + friend class AstValueFactory; + + AstConsString() : next_(nullptr), segment_({nullptr, nullptr}) {} + + AstConsString* next() const { return next_; } + AstConsString** next_location() { return &next_; } + + // {string_} is stored as String** instead of a Handle<String> so it can be + // stored in a union with {next_}. + void set_string(Handle<String> string) { string_ = string.location(); } + union { + AstConsString* next_; + String** string_; + }; + + struct Segment { + const AstRawString* string; + AstConsString::Segment* next; + }; + Segment segment_; }; enum class AstSymbol : uint8_t { kHomeObjectSymbol }; @@ -310,6 +331,7 @@ class AstValue : public ZoneObject { F(arguments, "arguments") \ F(async, "async") \ F(await, "await") \ + F(boolean, "boolean") \ F(constructor, "constructor") \ F(default, "default") \ F(done, "done") \ @@ -330,11 +352,15 @@ class AstValue : public ZoneObject { F(native, "native") \ F(new_target, ".new.target") \ F(next, "next") \ + F(number, "number") \ + F(object, "object") \ F(proto, "__proto__") \ F(prototype, "prototype") \ F(return, "return") \ F(set_space, "set ") \ F(star_default_star, "*default*") \ + F(string, "string") \ + F(symbol, "symbol") \ F(this, "this") \ F(this_function, ".this_function") \ F(throw, "throw") \ @@ -407,7 +433,10 @@ class AstValueFactory { values_(nullptr), strings_(nullptr), strings_end_(&strings_), + cons_strings_(nullptr), + cons_strings_end_(&cons_strings_), string_constants_(string_constants), + empty_cons_string_(nullptr), zone_(zone), hash_seed_(hash_seed) { #define F(name) name##_ = nullptr; @@ -418,6 +447,7 @@ class AstValueFactory { std::fill(one_character_strings_, one_character_strings_ + arraysize(one_character_strings_), nullptr); + empty_cons_string_ = NewConsString(); } Zone* zone() const { return zone_; } @@ -433,17 +463,20 @@ class AstValueFactory { return GetTwoByteStringInternal(literal); } const AstRawString* GetString(Handle<String> literal); - const AstConsString* NewConsString(const AstString* left, - const AstString* right); + V8_EXPORT_PRIVATE AstConsString* NewConsString(); + AstConsString* NewConsString(const AstRawString* str); + AstConsString* NewConsString(const AstRawString* str1, + const AstRawString* str2); V8_EXPORT_PRIVATE void Internalize(Isolate* isolate); #define F(name, str) \ - const AstRawString* name##_string() { \ + const AstRawString* name##_string() const { \ return string_constants_->name##_string(); \ } STRING_CONSTANTS(F) #undef F + const AstConsString* empty_cons_string() const { return empty_cons_string_; } V8_EXPORT_PRIVATE const AstValue* NewString(const AstRawString* string); // A JavaScript symbol (ECMA-262 edition 6). @@ -467,14 +500,21 @@ class AstValueFactory { values_ = value; return value; } - AstString* AddString(AstString* string) { + AstRawString* AddString(AstRawString* string) { *strings_end_ = string; strings_end_ = string->next_location(); return string; } + AstConsString* AddConsString(AstConsString* string) { + *cons_strings_end_ = string; + cons_strings_end_ = string->next_location(); + return string; + } void ResetStrings() { strings_ = nullptr; strings_end_ = &strings_; + cons_strings_ = nullptr; + cons_strings_end_ = &cons_strings_; } V8_EXPORT_PRIVATE AstRawString* GetOneByteStringInternal( Vector<const uint8_t> literal); @@ -490,11 +530,14 @@ class AstValueFactory { // We need to keep track of strings_ in order since cons strings require their // members to be internalized first. - AstString* strings_; - AstString** strings_end_; + AstRawString* strings_; + AstRawString** strings_end_; + AstConsString* cons_strings_; + AstConsString** cons_strings_end_; // Holds constant string values which are shared across the isolate. const AstStringConstants* string_constants_; + const AstConsString* empty_cons_string_; // Caches for faster access: small numbers, one character lowercase strings // (for minified code). diff --git a/deps/v8/src/ast/ast.cc b/deps/v8/src/ast/ast.cc index 5705c70057..d7d70ae433 100644 --- a/deps/v8/src/ast/ast.cc +++ b/deps/v8/src/ast/ast.cc @@ -51,6 +51,7 @@ static const char* NameForNativeContextIntrinsicIndex(uint32_t idx) { void AstNode::Print() { Print(Isolate::Current()); } void AstNode::Print(Isolate* isolate) { + AllowHandleDereference allow_deref; AstPrinter::PrintOut(isolate, this); } @@ -163,7 +164,7 @@ void Expression::MarkTail() { bool DoExpression::IsAnonymousFunctionDefinition() const { // This is specifically to allow DoExpressions to represent ClassLiterals. return represented_function_ != nullptr && - represented_function_->raw_name()->length() == 0; + represented_function_->raw_name()->IsEmpty(); } bool Statement::IsJump() const { @@ -249,16 +250,16 @@ static void AssignVectorSlots(Expression* expr, FeedbackVectorSpec* spec, FeedbackSlot* out_slot) { Property* property = expr->AsProperty(); LhsKind assign_type = Property::GetAssignType(property); - if ((assign_type == VARIABLE && - expr->AsVariableProxy()->var()->IsUnallocated()) || - assign_type == NAMED_PROPERTY || assign_type == KEYED_PROPERTY) { - // TODO(ishell): consider using ICSlotCache for variables here. - if (assign_type == KEYED_PROPERTY) { - *out_slot = spec->AddKeyedStoreICSlot(language_mode); + // TODO(ishell): consider using ICSlotCache for variables here. + if (assign_type == VARIABLE && + expr->AsVariableProxy()->var()->IsUnallocated()) { + *out_slot = spec->AddStoreGlobalICSlot(language_mode); - } else { - *out_slot = spec->AddStoreICSlot(language_mode); - } + } else if (assign_type == NAMED_PROPERTY) { + *out_slot = spec->AddStoreICSlot(language_mode); + + } else if (assign_type == KEYED_PROPERTY) { + *out_slot = spec->AddKeyedStoreICSlot(language_mode); } } @@ -681,8 +682,8 @@ bool ObjectLiteral::IsFastCloningSupported() const { // literals don't support copy-on-write (COW) elements for now. // TODO(mvstanton): make object literals support COW elements. return fast_elements() && has_shallow_properties() && - properties_count() <= ConstructorBuiltinsAssembler:: - kMaximumClonedShallowObjectProperties; + properties_count() <= + ConstructorBuiltins::kMaximumClonedShallowObjectProperties; } ElementsKind ArrayLiteral::constant_elements_kind() const { @@ -786,7 +787,7 @@ void ArrayLiteral::BuildConstantElements(Isolate* isolate) { bool ArrayLiteral::IsFastCloningSupported() const { return depth() <= 1 && values()->length() <= - ConstructorBuiltinsAssembler::kMaximumClonedShallowArrayElements; + ConstructorBuiltins::kMaximumClonedShallowArrayElements; } void ArrayLiteral::RewindSpreads() { @@ -883,6 +884,30 @@ void BinaryOperation::AssignFeedbackSlots(FeedbackVectorSpec* spec, } } +static bool IsCommutativeOperationWithSmiLiteral(Token::Value op) { + // Add is not commutative due to potential for string addition. + return op == Token::MUL || op == Token::BIT_AND || op == Token::BIT_OR || + op == Token::BIT_XOR; +} + +// Check for the pattern: x + 1. +static bool MatchSmiLiteralOperation(Expression* left, Expression* right, + Expression** expr, Smi** literal) { + if (right->IsSmiLiteral()) { + *expr = left; + *literal = right->AsLiteral()->AsSmiLiteral(); + return true; + } + return false; +} + +bool BinaryOperation::IsSmiLiteralOperation(Expression** subexpr, + Smi** literal) { + return MatchSmiLiteralOperation(left_, right_, subexpr, literal) || + (IsCommutativeOperationWithSmiLiteral(op()) && + MatchSmiLiteralOperation(right_, left_, subexpr, literal)); +} + static bool IsTypeof(Expression* expr) { UnaryOperation* maybe_unary = expr->AsUnaryOperation(); return maybe_unary != NULL && maybe_unary->op() == Token::TYPEOF; @@ -904,24 +929,21 @@ void CompareOperation::AssignFeedbackSlots(FeedbackVectorSpec* spec, } // Check for the pattern: typeof <expression> equals <string literal>. -static bool MatchLiteralCompareTypeof(Expression* left, - Token::Value op, - Expression* right, - Expression** expr, - Handle<String>* check) { +static bool MatchLiteralCompareTypeof(Expression* left, Token::Value op, + Expression* right, Expression** expr, + Literal** literal) { if (IsTypeof(left) && right->IsStringLiteral() && Token::IsEqualityOp(op)) { *expr = left->AsUnaryOperation()->expression(); - *check = Handle<String>::cast(right->AsLiteral()->value()); + *literal = right->AsLiteral(); return true; } return false; } - bool CompareOperation::IsLiteralCompareTypeof(Expression** expr, - Handle<String>* check) { - return MatchLiteralCompareTypeof(left_, op(), right_, expr, check) || - MatchLiteralCompareTypeof(right_, op(), left_, expr, check); + Literal** literal) { + return MatchLiteralCompareTypeof(left_, op(), right_, expr, literal) || + MatchLiteralCompareTypeof(right_, op(), left_, expr, literal); } diff --git a/deps/v8/src/ast/ast.h b/deps/v8/src/ast/ast.h index 90e94bb87e..9d7b4de82c 100644 --- a/deps/v8/src/ast/ast.h +++ b/deps/v8/src/ast/ast.h @@ -91,7 +91,7 @@ namespace internal { V(Conditional) \ V(VariableProxy) \ V(Literal) \ - V(Yield) \ + V(Suspend) \ V(Throw) \ V(CallRuntime) \ V(UnaryOperation) \ @@ -105,7 +105,8 @@ namespace internal { V(EmptyParentheses) \ V(GetIterator) \ V(DoExpression) \ - V(RewritableExpression) + V(RewritableExpression) \ + V(ImportCallExpression) #define AST_NODE_LIST(V) \ DECLARATION_NODE_LIST(V) \ @@ -563,11 +564,11 @@ class IterationStatement : public BreakableStatement { Statement* body() const { return body_; } void set_body(Statement* s) { body_ = s; } - int yield_count() const { return yield_count_; } - int first_yield_id() const { return first_yield_id_; } - void set_yield_count(int yield_count) { yield_count_ = yield_count; } - void set_first_yield_id(int first_yield_id) { - first_yield_id_ = first_yield_id; + int suspend_count() const { return suspend_count_; } + int first_suspend_id() const { return first_suspend_id_; } + void set_suspend_count(int suspend_count) { suspend_count_ = suspend_count; } + void set_first_suspend_id(int first_suspend_id) { + first_suspend_id_ = first_suspend_id; } static int num_ids() { return parent_num_ids() + 1; } @@ -581,8 +582,8 @@ class IterationStatement : public BreakableStatement { NodeType type) : BreakableStatement(labels, TARGET_FOR_ANONYMOUS, pos, type), body_(NULL), - yield_count_(0), - first_yield_id_(0) {} + suspend_count_(0), + first_suspend_id_(0) {} static int parent_num_ids() { return BreakableStatement::num_ids(); } void Initialize(Statement* body) { body_ = body; } @@ -594,8 +595,8 @@ class IterationStatement : public BreakableStatement { Statement* body_; Label continue_target_; - int yield_count_; - int first_yield_id_; + int suspend_count_; + int first_suspend_id_; }; @@ -1101,7 +1102,6 @@ class TryStatement : public Statement { class TryCatchStatement final : public TryStatement { public: Scope* scope() { return scope_; } - Variable* variable() { return variable_; } Block* catch_block() const { return catch_block_; } void set_catch_block(Block* b) { catch_block_ = b; } @@ -1122,18 +1122,15 @@ class TryCatchStatement final : public TryStatement { private: friend class AstNodeFactory; - TryCatchStatement(Block* try_block, Scope* scope, Variable* variable, - Block* catch_block, + TryCatchStatement(Block* try_block, Scope* scope, Block* catch_block, HandlerTable::CatchPrediction catch_prediction, int pos) : TryStatement(try_block, pos, kTryCatchStatement), scope_(scope), - variable_(variable), catch_block_(catch_block) { catch_prediction_ = catch_prediction; } Scope* scope_; - Variable* variable_; Block* catch_block_; }; @@ -1205,6 +1202,11 @@ class Literal final : public Expression { return value_->AsString(); } + Smi* AsSmiLiteral() { + DCHECK(IsSmiLiteral()); + return raw_value()->AsSmi(); + } + bool ToBooleanIsTrue() const { return raw_value()->BooleanValue(); } bool ToBooleanIsFalse() const { return !raw_value()->BooleanValue(); } @@ -2138,6 +2140,11 @@ class BinaryOperation final : public Expression { TypeFeedbackId BinaryOperationFeedbackId() const { return TypeFeedbackId(local_id(1)); } + + // Returns true if one side is a Smi literal, returning the other side's + // sub-expression in |subexpr| and the literal Smi in |literal|. + bool IsSmiLiteralOperation(Expression** subexpr, Smi** literal); + Maybe<int> fixed_right_arg() const { return has_fixed_right_arg_ ? Just(fixed_right_arg_value_) : Nothing<int>(); } @@ -2279,7 +2286,7 @@ class CompareOperation final : public Expression { FeedbackSlot CompareOperationFeedbackSlot() const { return feedback_slot_; } // Match special cases. - bool IsLiteralCompareTypeof(Expression** expr, Handle<String>* check); + bool IsLiteralCompareTypeof(Expression** expr, Literal** literal); bool IsLiteralCompareUndefined(Expression** expr); bool IsLiteralCompareNull(Expression** expr); @@ -2493,10 +2500,16 @@ class RewritableExpression final : public Expression { : public BitField<bool, Expression::kNextBitFieldIndex, 1> {}; }; +// There are several types of Suspend node: +// +// Yield +// YieldStar +// Await +// // Our Yield is different from the JS yield in that it "returns" its argument as // is, without wrapping it in an iterator result object. Such wrapping, if // desired, must be done beforehand (see the parser). -class Yield final : public Expression { +class Suspend final : public Expression { public: enum OnException { kOnExceptionThrow, kOnExceptionRethrow }; @@ -2508,30 +2521,59 @@ class Yield final : public Expression { bool rethrow_on_exception() const { return on_exception() == kOnExceptionRethrow; } - int yield_id() const { return yield_id_; } + + int suspend_id() const { return suspend_id_; } + SuspendFlags flags() const { return FlagsField::decode(bit_field_); } + SuspendFlags suspend_type() const { + return flags() & SuspendFlags::kSuspendTypeMask; + } + SuspendFlags generator_type() const { + return flags() & SuspendFlags::kGeneratorTypeMask; + } + bool is_yield() const { return suspend_type() == SuspendFlags::kYield; } + bool is_yield_star() const { + return suspend_type() == SuspendFlags::kYieldStar; + } + bool is_await() const { return suspend_type() == SuspendFlags::kAwait; } + bool is_async_generator() const { + return generator_type() == SuspendFlags::kAsyncGenerator; + } + inline bool IsNonInitialAsyncGeneratorYield() const { + // Return true if is_async_generator() && !is_await() && yield_id() > 0 + return suspend_id() > 0 && (flags() & SuspendFlags::kAsyncGeneratorAwait) == + SuspendFlags::kAsyncGenerator; + } void set_generator_object(Expression* e) { generator_object_ = e; } void set_expression(Expression* e) { expression_ = e; } - void set_yield_id(int yield_id) { yield_id_ = yield_id; } + void set_suspend_id(int id) { suspend_id_ = id; } + void set_suspend_type(SuspendFlags type) { + DCHECK_EQ(0, static_cast<int>(type & ~SuspendFlags::kSuspendTypeMask)); + bit_field_ = FlagsField::update(bit_field_, type); + } private: friend class AstNodeFactory; - Yield(Expression* generator_object, Expression* expression, int pos, - OnException on_exception) - : Expression(pos, kYield), - yield_id_(-1), + Suspend(Expression* generator_object, Expression* expression, int pos, + OnException on_exception, SuspendFlags flags) + : Expression(pos, kSuspend), + suspend_id_(-1), generator_object_(generator_object), expression_(expression) { - bit_field_ |= OnExceptionField::encode(on_exception); + bit_field_ |= + OnExceptionField::encode(on_exception) | FlagsField::encode(flags); } - int yield_id_; + int suspend_id_; Expression* generator_object_; Expression* expression_; class OnExceptionField : public BitField<OnException, Expression::kNextBitFieldIndex, 1> {}; + class FlagsField + : public BitField<SuspendFlags, OnExceptionField::kNext, + static_cast<int>(SuspendFlags::kBitWidth)> {}; }; @@ -2566,8 +2608,8 @@ class FunctionLiteral final : public Expression { enum EagerCompileHint { kShouldEagerCompile, kShouldLazyCompile }; Handle<String> name() const { return raw_name_->string(); } - const AstString* raw_name() const { return raw_name_; } - void set_raw_name(const AstString* name) { raw_name_ = name; } + const AstConsString* raw_name() const { return raw_name_; } + void set_raw_name(const AstConsString* name) { raw_name_ = name; } DeclarationScope* scope() const { return scope_; } ZoneList<Statement*>* body() const { return body_; } void set_function_token_position(int pos) { function_token_position_ = pos; } @@ -2593,7 +2635,11 @@ class FunctionLiteral final : public Expression { static bool NeedsHomeObject(Expression* expr); - int expected_property_count() { return expected_property_count_; } + int expected_property_count() { + // Not valid for lazy functions. + DCHECK_NOT_NULL(body_); + return expected_property_count_; + } int parameter_count() { return parameter_count_; } int function_length() { return function_length_; } @@ -2626,7 +2672,7 @@ class FunctionLiteral final : public Expression { raw_inferred_name_ = NULL; } - void set_raw_inferred_name(const AstString* raw_inferred_name) { + void set_raw_inferred_name(const AstConsString* raw_inferred_name) { DCHECK(raw_inferred_name != NULL); raw_inferred_name_ = raw_inferred_name; DCHECK(inferred_name_.is_null()); @@ -2637,6 +2683,8 @@ class FunctionLiteral final : public Expression { void set_pretenure() { bit_field_ = Pretenure::update(bit_field_, true); } bool has_duplicate_parameters() const { + // Not valid for lazy functions. + DCHECK_NOT_NULL(body_); return HasDuplicateParameters::decode(bit_field_); } @@ -2682,8 +2730,8 @@ class FunctionLiteral final : public Expression { return is_anonymous_expression(); } - int yield_count() { return yield_count_; } - void set_yield_count(int yield_count) { yield_count_ = yield_count; } + int suspend_count() { return suspend_count_; } + void set_suspend_count(int suspend_count) { suspend_count_ = suspend_count; } int return_position() { return std::max(start_position(), end_position() - (has_braces_ ? 1 : 0)); @@ -2697,7 +2745,7 @@ class FunctionLiteral final : public Expression { private: friend class AstNodeFactory; - FunctionLiteral(Zone* zone, const AstString* name, + FunctionLiteral(Zone* zone, const AstRawString* name, AstValueFactory* ast_value_factory, DeclarationScope* scope, ZoneList<Statement*>* body, int expected_property_count, int parameter_count, int function_length, @@ -2710,12 +2758,12 @@ class FunctionLiteral final : public Expression { parameter_count_(parameter_count), function_length_(function_length), function_token_position_(kNoSourcePosition), - yield_count_(0), + suspend_count_(0), has_braces_(has_braces), - raw_name_(name), + raw_name_(ast_value_factory->NewConsString(name)), scope_(scope), body_(body), - raw_inferred_name_(ast_value_factory->empty_string()), + raw_inferred_name_(ast_value_factory->empty_cons_string()), ast_properties_(zone), function_literal_id_(function_literal_id) { bit_field_ |= FunctionTypeBits::encode(function_type) | @@ -2725,6 +2773,7 @@ class FunctionLiteral final : public Expression { ShouldNotBeUsedOnceHintField::encode(false) | DontOptimizeReasonField::encode(kNoReason); if (eager_compile_hint == kShouldEagerCompile) SetShouldEagerCompile(); + DCHECK_EQ(body == nullptr, expected_property_count < 0); } class FunctionTypeBits @@ -2741,13 +2790,13 @@ class FunctionLiteral final : public Expression { int parameter_count_; int function_length_; int function_token_position_; - int yield_count_; + int suspend_count_; bool has_braces_; - const AstString* raw_name_; + const AstConsString* raw_name_; DeclarationScope* scope_; ZoneList<Statement*>* body_; - const AstString* raw_inferred_name_; + const AstConsString* raw_inferred_name_; Handle<String> inferred_name_; AstProperties ast_properties_; int function_literal_id_; @@ -2925,6 +2974,21 @@ class SuperCallReference final : public Expression { VariableProxy* this_function_var_; }; +// This AST Node is used to represent a dynamic import call -- +// import(argument). +class ImportCallExpression final : public Expression { + public: + Expression* argument() const { return argument_; } + void set_argument(Expression* argument) { argument_ = argument; } + + private: + friend class AstNodeFactory; + + ImportCallExpression(Expression* argument, int pos) + : Expression(pos, kImportCallExpression), argument_(argument) {} + + Expression* argument_; +}; // This class is produced when parsing the () in arrow functions without any // arguments and is not actually a valid expression. @@ -3245,38 +3309,33 @@ class AstNodeFactory final BASE_EMBEDDED { } TryCatchStatement* NewTryCatchStatement(Block* try_block, Scope* scope, - Variable* variable, Block* catch_block, int pos) { - return new (zone_) TryCatchStatement( - try_block, scope, variable, catch_block, HandlerTable::CAUGHT, pos); + return new (zone_) TryCatchStatement(try_block, scope, catch_block, + HandlerTable::CAUGHT, pos); } TryCatchStatement* NewTryCatchStatementForReThrow(Block* try_block, Scope* scope, - Variable* variable, Block* catch_block, int pos) { - return new (zone_) TryCatchStatement( - try_block, scope, variable, catch_block, HandlerTable::UNCAUGHT, pos); + return new (zone_) TryCatchStatement(try_block, scope, catch_block, + HandlerTable::UNCAUGHT, pos); } TryCatchStatement* NewTryCatchStatementForDesugaring(Block* try_block, Scope* scope, - Variable* variable, Block* catch_block, int pos) { - return new (zone_) TryCatchStatement( - try_block, scope, variable, catch_block, HandlerTable::DESUGARING, pos); + return new (zone_) TryCatchStatement(try_block, scope, catch_block, + HandlerTable::DESUGARING, pos); } TryCatchStatement* NewTryCatchStatementForAsyncAwait(Block* try_block, Scope* scope, - Variable* variable, Block* catch_block, int pos) { - return new (zone_) - TryCatchStatement(try_block, scope, variable, catch_block, - HandlerTable::ASYNC_AWAIT, pos); + return new (zone_) TryCatchStatement(try_block, scope, catch_block, + HandlerTable::ASYNC_AWAIT, pos); } TryFinallyStatement* NewTryFinallyStatement(Block* try_block, @@ -3481,10 +3540,12 @@ class AstNodeFactory final BASE_EMBEDDED { return assign; } - Yield* NewYield(Expression* generator_object, Expression* expression, int pos, - Yield::OnException on_exception) { + Suspend* NewSuspend(Expression* generator_object, Expression* expression, + int pos, Suspend::OnException on_exception, + SuspendFlags flags) { if (!expression) expression = NewUndefinedLiteral(pos); - return new (zone_) Yield(generator_object, expression, pos, on_exception); + return new (zone_) + Suspend(generator_object, expression, pos, on_exception, flags); } Throw* NewThrow(Expression* exception, int pos) { @@ -3578,6 +3639,10 @@ class AstNodeFactory final BASE_EMBEDDED { return new (zone_) GetIterator(iterable, hint, pos); } + ImportCallExpression* NewImportCallExpression(Expression* args, int pos) { + return new (zone_) ImportCallExpression(args, pos); + } + Zone* zone() const { return zone_; } void set_zone(Zone* zone) { zone_ = zone; } diff --git a/deps/v8/src/ast/context-slot-cache.h b/deps/v8/src/ast/context-slot-cache.h index 4345a65a3d..b4e3590919 100644 --- a/deps/v8/src/ast/context-slot-cache.h +++ b/deps/v8/src/ast/context-slot-cache.h @@ -38,7 +38,7 @@ class ContextSlotCache { for (int i = 0; i < kLength; ++i) { keys_[i].data = NULL; keys_[i].name = NULL; - values_[i] = kNotFound; + values_[i] = static_cast<uint32_t>(kNotFound); } } diff --git a/deps/v8/src/ast/modules.h b/deps/v8/src/ast/modules.h index ce8aba8d70..1eb6f44796 100644 --- a/deps/v8/src/ast/modules.h +++ b/deps/v8/src/ast/modules.h @@ -214,8 +214,9 @@ class ModuleDescriptor : public ZoneObject { int AddModuleRequest(const AstRawString* specifier) { DCHECK_NOT_NULL(specifier); + int module_requests_count = static_cast<int>(module_requests_.size()); auto it = module_requests_ - .insert(std::make_pair(specifier, module_requests_.size())) + .insert(std::make_pair(specifier, module_requests_count)) .first; return it->second; } diff --git a/deps/v8/src/ast/prettyprinter.cc b/deps/v8/src/ast/prettyprinter.cc index 725a8a7e7e..21ce932a08 100644 --- a/deps/v8/src/ast/prettyprinter.cc +++ b/deps/v8/src/ast/prettyprinter.cc @@ -254,9 +254,7 @@ void CallPrinter::VisitAssignment(Assignment* node) { Find(node->value()); } - -void CallPrinter::VisitYield(Yield* node) { Find(node->expression()); } - +void CallPrinter::VisitSuspend(Suspend* node) { Find(node->expression()); } void CallPrinter::VisitThrow(Throw* node) { Find(node->exception()); } @@ -372,8 +370,23 @@ void CallPrinter::VisitEmptyParentheses(EmptyParentheses* node) { } void CallPrinter::VisitGetIterator(GetIterator* node) { - Print("GetIterator("); + // Because CallPrinter is used by RenderCallSite() in runtime-internal.cc, + // and the GetIterator node results in a Call, either to a [@@iterator] or + // [@@asyncIterator]. It's unknown which call this error refers to, so we + // assume it's the first call. + bool was_found = !found_ && node->position() == position_; + if (was_found) { + found_ = true; + } Find(node->iterable(), true); + Print(node->hint() == IteratorType::kNormal ? "[Symbol.iterator]" + : "[Symbol.asyncIterator]"); + if (was_found) done_ = true; +} + +void CallPrinter::VisitImportCallExpression(ImportCallExpression* node) { + Print("ImportCall("); + Find(node->argument(), true); Print(")"); } @@ -623,7 +636,8 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info, } else { EmbeddedVector<char, 256> buf; int pos = - SNPrintF(buf, "%s (mode = %s", info, VariableMode2String(var->mode())); + SNPrintF(buf, "%s (%p) (mode = %s", info, reinterpret_cast<void*>(var), + VariableMode2String(var->mode())); SNPrintF(buf + pos, ")"); PrintLiteralIndented(buf.start(), value, true); } @@ -649,8 +663,8 @@ const char* AstPrinter::PrintProgram(FunctionLiteral* program) { { IndentedScope indent(this, "FUNC", program->position()); PrintIndented("KIND"); Print(" %d\n", program->kind()); - PrintIndented("YIELD COUNT"); - Print(" %d\n", program->yield_count()); + PrintIndented("SUSPEND COUNT"); + Print(" %d\n", program->suspend_count()); PrintLiteralIndented("NAME", program->name(), true); PrintLiteralIndented("INFERRED NAME", program->inferred_name(), true); PrintParameters(program->scope()); @@ -801,8 +815,8 @@ void AstPrinter::VisitCaseClause(CaseClause* clause) { void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) { IndentedScope indent(this, "DO", node->position()); - PrintIndented("YIELD COUNT"); - Print(" %d\n", node->yield_count()); + PrintIndented("SUSPEND COUNT"); + Print(" %d\n", node->suspend_count()); PrintLabelsIndented(node->labels()); PrintIndentedVisit("BODY", node->body()); PrintIndentedVisit("COND", node->cond()); @@ -811,8 +825,8 @@ void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) { void AstPrinter::VisitWhileStatement(WhileStatement* node) { IndentedScope indent(this, "WHILE", node->position()); - PrintIndented("YIELD COUNT"); - Print(" %d\n", node->yield_count()); + PrintIndented("SUSPEND COUNT"); + Print(" %d\n", node->suspend_count()); PrintLabelsIndented(node->labels()); PrintIndentedVisit("COND", node->cond()); PrintIndentedVisit("BODY", node->body()); @@ -821,8 +835,8 @@ void AstPrinter::VisitWhileStatement(WhileStatement* node) { void AstPrinter::VisitForStatement(ForStatement* node) { IndentedScope indent(this, "FOR", node->position()); - PrintIndented("YIELD COUNT"); - Print(" %d\n", node->yield_count()); + PrintIndented("SUSPEND COUNT"); + Print(" %d\n", node->suspend_count()); PrintLabelsIndented(node->labels()); if (node->init()) PrintIndentedVisit("INIT", node->init()); if (node->cond()) PrintIndentedVisit("COND", node->cond()); @@ -833,8 +847,8 @@ void AstPrinter::VisitForStatement(ForStatement* node) { void AstPrinter::VisitForInStatement(ForInStatement* node) { IndentedScope indent(this, "FOR IN", node->position()); - PrintIndented("YIELD COUNT"); - Print(" %d\n", node->yield_count()); + PrintIndented("SUSPEND COUNT"); + Print(" %d\n", node->suspend_count()); PrintIndentedVisit("FOR", node->each()); PrintIndentedVisit("IN", node->enumerable()); PrintIndentedVisit("BODY", node->body()); @@ -843,8 +857,8 @@ void AstPrinter::VisitForInStatement(ForInStatement* node) { void AstPrinter::VisitForOfStatement(ForOfStatement* node) { IndentedScope indent(this, "FOR OF", node->position()); - PrintIndented("YIELD COUNT"); - Print(" %d\n", node->yield_count()); + PrintIndented("SUSPEND COUNT"); + Print(" %d\n", node->suspend_count()); PrintIndentedVisit("INIT", node->assign_iterator()); PrintIndentedVisit("NEXT", node->next_result()); PrintIndentedVisit("DONE", node->result_done()); @@ -856,9 +870,8 @@ void AstPrinter::VisitForOfStatement(ForOfStatement* node) { void AstPrinter::VisitTryCatchStatement(TryCatchStatement* node) { IndentedScope indent(this, "TRY CATCH", node->position()); PrintTryStatement(node); - PrintLiteralWithModeIndented("CATCHVAR", - node->variable(), - node->variable()->name()); + PrintLiteralWithModeIndented("CATCHVAR", node->scope()->catch_variable(), + node->scope()->catch_variable()->name()); PrintIndentedVisit("CATCH", node->catch_block()); } @@ -1095,10 +1108,9 @@ void AstPrinter::VisitAssignment(Assignment* node) { Visit(node->value()); } - -void AstPrinter::VisitYield(Yield* node) { +void AstPrinter::VisitSuspend(Suspend* node) { EmbeddedVector<char, 128> buf; - SNPrintF(buf, "YIELD id %d", node->yield_id()); + SNPrintF(buf, "SUSPEND id %d", node->suspend_id()); IndentedScope indent(this, buf.start(), node->position()); Visit(node->expression()); } @@ -1146,14 +1158,8 @@ void AstPrinter::VisitCallNew(CallNew* node) { void AstPrinter::VisitCallRuntime(CallRuntime* node) { EmbeddedVector<char, 128> buf; - if (node->is_jsruntime()) { - SNPrintF( - buf, "CALL RUNTIME %s code = %p", node->debug_name(), - static_cast<void*>(isolate_->context()->get(node->context_index()))); - } else { - SNPrintF(buf, "CALL RUNTIME %s", node->debug_name()); - } - + SNPrintF(buf, "CALL RUNTIME %s%s", node->debug_name(), + node->is_jsruntime() ? " (JS function)" : ""); IndentedScope indent(this, buf.start(), node->position()); PrintArguments(node->arguments()); } @@ -1203,6 +1209,11 @@ void AstPrinter::VisitGetIterator(GetIterator* node) { Visit(node->iterable()); } +void AstPrinter::VisitImportCallExpression(ImportCallExpression* node) { + IndentedScope indent(this, "IMPORT-CALL", node->position()); + Visit(node->argument()); +} + void AstPrinter::VisitThisFunction(ThisFunction* node) { IndentedScope indent(this, "THIS-FUNCTION", node->position()); } diff --git a/deps/v8/src/ast/scopes.cc b/deps/v8/src/ast/scopes.cc index 225793c7bb..99be5cd343 100644 --- a/deps/v8/src/ast/scopes.cc +++ b/deps/v8/src/ast/scopes.cc @@ -112,11 +112,12 @@ void SloppyBlockFunctionMap::Delegate::set_statement(Statement* statement) { } SloppyBlockFunctionMap::SloppyBlockFunctionMap(Zone* zone) - : ZoneHashMap(8, ZoneAllocationPolicy(zone)) {} + : ZoneHashMap(8, ZoneAllocationPolicy(zone)), count_(0) {} -void SloppyBlockFunctionMap::Declare( - Zone* zone, const AstRawString* name, - SloppyBlockFunctionMap::Delegate* delegate) { +void SloppyBlockFunctionMap::Declare(Zone* zone, const AstRawString* name, + Scope* scope, + SloppyBlockFunctionStatement* statement) { + auto* delegate = new (zone) Delegate(scope, statement, count_++); // AstRawStrings are unambiguous, i.e., the same string is always represented // by the same AstRawString*. Entry* p = @@ -155,14 +156,22 @@ Scope::Snapshot::Snapshot(Scope* scope) top_inner_scope_(scope->inner_scope_), top_unresolved_(scope->unresolved_), top_local_(scope->GetClosureScope()->locals_.end()), - top_decl_(scope->GetClosureScope()->decls_.end()) {} + top_decl_(scope->GetClosureScope()->decls_.end()), + outer_scope_calls_eval_(scope->scope_calls_eval_) { + // Reset in order to record eval calls during this Snapshot's lifetime. + outer_scope_->scope_calls_eval_ = false; +} + +Scope::Snapshot::~Snapshot() { + // Restore previous calls_eval bit if needed. + if (outer_scope_calls_eval_) { + outer_scope_->scope_calls_eval_ = true; + } +} DeclarationScope::DeclarationScope(Zone* zone, AstValueFactory* ast_value_factory) - : Scope(zone), - function_kind_(kNormalFunction), - params_(4, zone), - sloppy_block_function_map_(zone) { + : Scope(zone), function_kind_(kNormalFunction), params_(4, zone) { DCHECK_EQ(scope_type_, SCRIPT_SCOPE); SetDefaults(); @@ -176,8 +185,7 @@ DeclarationScope::DeclarationScope(Zone* zone, Scope* outer_scope, FunctionKind function_kind) : Scope(zone, outer_scope, scope_type), function_kind_(function_kind), - params_(4, zone), - sloppy_block_function_map_(zone) { + params_(4, zone) { DCHECK_NE(scope_type, SCRIPT_SCOPE); SetDefaults(); asm_function_ = outer_scope_->IsAsmModule(); @@ -193,10 +201,11 @@ ModuleScope::ModuleScope(DeclarationScope* script_scope, DeclareThis(ast_value_factory); } -ModuleScope::ModuleScope(Isolate* isolate, Handle<ScopeInfo> scope_info, +ModuleScope::ModuleScope(Handle<ScopeInfo> scope_info, AstValueFactory* avfactory) : DeclarationScope(avfactory->zone(), MODULE_SCOPE, scope_info) { Zone* zone = avfactory->zone(); + Isolate* isolate = scope_info->GetIsolate(); Handle<ModuleInfo> module_info(scope_info->ModuleDescriptorInfo(), isolate); set_language_mode(STRICT); @@ -254,20 +263,22 @@ Scope::Scope(Zone* zone, ScopeType scope_type, Handle<ScopeInfo> scope_info) set_language_mode(scope_info->language_mode()); num_heap_slots_ = scope_info->ContextLength(); DCHECK_LE(Context::MIN_CONTEXT_SLOTS, num_heap_slots_); + // We don't really need to use the preparsed scope data; this is just to + // shorten the recursion in SetMustUsePreParsedScopeData. + must_use_preparsed_scope_data_ = true; } DeclarationScope::DeclarationScope(Zone* zone, ScopeType scope_type, Handle<ScopeInfo> scope_info) : Scope(zone, scope_type, scope_info), function_kind_(scope_info->function_kind()), - params_(0, zone), - sloppy_block_function_map_(zone) { + params_(0, zone) { DCHECK_NE(scope_type, SCRIPT_SCOPE); SetDefaults(); } Scope::Scope(Zone* zone, const AstRawString* catch_variable_name, - Handle<ScopeInfo> scope_info) + MaybeAssignedFlag maybe_assigned, Handle<ScopeInfo> scope_info) : zone_(zone), outer_scope_(nullptr), variables_(zone), @@ -280,7 +291,8 @@ Scope::Scope(Zone* zone, const AstRawString* catch_variable_name, // Cache the catch variable, even though it's also available via the // scope_info, as the parser expects that a catch scope always has the catch // variable as first and only variable. - Variable* variable = Declare(zone, catch_variable_name, VAR); + Variable* variable = Declare(zone, catch_variable_name, VAR, NORMAL_VARIABLE, + kCreatedInitialized, maybe_assigned); AllocateHeapSlot(variable); } @@ -293,6 +305,7 @@ void DeclarationScope::SetDefaults() { has_arguments_parameter_ = false; scope_uses_super_property_ = false; has_rest_ = false; + sloppy_block_function_map_ = nullptr; receiver_ = nullptr; new_target_ = nullptr; function_ = nullptr; @@ -300,6 +313,7 @@ void DeclarationScope::SetDefaults() { rare_data_ = nullptr; should_eager_compile_ = false; was_lazily_parsed_ = false; + is_skipped_function_ = false; #ifdef DEBUG DeclarationScope* outer_declaration_scope = outer_scope_ ? outer_scope_->GetDeclarationScope() : nullptr; @@ -336,6 +350,8 @@ void Scope::SetDefaults() { force_context_allocation_ = false; is_declaration_scope_ = false; + + must_use_preparsed_scope_data_ = false; } bool Scope::HasSimpleParameters() { @@ -369,8 +385,7 @@ bool Scope::IsAsmFunction() const { return is_function_scope() && AsDeclarationScope()->asm_function(); } -Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone, - ScopeInfo* scope_info, +Scope* Scope::DeserializeScopeChain(Zone* zone, ScopeInfo* scope_info, DeclarationScope* script_scope, AstValueFactory* ast_value_factory, DeserializationMode deserialization_mode) { @@ -415,15 +430,20 @@ Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone, outer_scope = new (zone) Scope(zone, BLOCK_SCOPE, handle(scope_info)); } } else if (scope_info->scope_type() == MODULE_SCOPE) { - outer_scope = new (zone) - ModuleScope(isolate, handle(scope_info), ast_value_factory); + outer_scope = + new (zone) ModuleScope(handle(scope_info), ast_value_factory); } else { DCHECK_EQ(scope_info->scope_type(), CATCH_SCOPE); DCHECK_EQ(scope_info->LocalCount(), 1); - String* name = scope_info->LocalName(0); - outer_scope = new (zone) - Scope(zone, ast_value_factory->GetString(handle(name, isolate)), - handle(scope_info)); + DCHECK_EQ(scope_info->ContextLocalCount(), 1); + DCHECK_EQ(scope_info->ContextLocalMode(0), VAR); + DCHECK_EQ(scope_info->ContextLocalInitFlag(0), kCreatedInitialized); + String* name = scope_info->ContextLocalName(0); + MaybeAssignedFlag maybe_assigned = + scope_info->ContextLocalMaybeAssignedFlag(0); + outer_scope = + new (zone) Scope(zone, ast_value_factory->GetString(handle(name)), + maybe_assigned, handle(scope_info)); } if (deserialization_mode == DeserializationMode::kScopesOnly) { outer_scope->scope_info_ = Handle<ScopeInfo>::null(); @@ -469,9 +489,12 @@ int Scope::num_parameters() const { void DeclarationScope::DeclareSloppyBlockFunction( const AstRawString* name, Scope* scope, SloppyBlockFunctionStatement* statement) { - auto* delegate = - new (zone()) SloppyBlockFunctionMap::Delegate(scope, statement); - sloppy_block_function_map_.Declare(zone(), name, delegate); + if (sloppy_block_function_map_ == nullptr) { + sloppy_block_function_map_ = + new (zone()->New(sizeof(SloppyBlockFunctionMap))) + SloppyBlockFunctionMap(zone()); + } + sloppy_block_function_map_->Declare(zone(), name, scope, statement); } void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { @@ -481,12 +504,19 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { DCHECK(HasSimpleParameters() || is_block_scope() || is_being_lazily_parsed_); DCHECK_EQ(factory == nullptr, is_being_lazily_parsed_); - bool has_simple_parameters = HasSimpleParameters(); + SloppyBlockFunctionMap* map = sloppy_block_function_map(); + if (map == nullptr) return; + + const bool has_simple_parameters = HasSimpleParameters(); + + // The declarations need to be added in the order they were seen, + // so accumulate declared names sorted by index. + ZoneMap<int, const AstRawString*> names_to_declare(zone()); + // For each variable which is used as a function declaration in a sloppy // block, - SloppyBlockFunctionMap* map = sloppy_block_function_map(); for (ZoneHashMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) { - AstRawString* name = static_cast<AstRawString*>(p->key); + const AstRawString* name = static_cast<AstRawString*>(p->key); // If the variable wouldn't conflict with a lexical declaration // or parameter, @@ -509,7 +539,7 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { } } - Variable* created_variable = nullptr; + bool declaration_queued = false; // Write in assignments to var for each block-scoped function declaration auto delegates = static_cast<SloppyBlockFunctionMap::Delegate*>(p->value); @@ -543,50 +573,59 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { if (!should_hoist) continue; - // Declare a var-style binding for the function in the outer scope + if (!declaration_queued) { + declaration_queued = true; + names_to_declare.insert({delegate->index(), name}); + } + if (factory) { DCHECK(!is_being_lazily_parsed_); - if (created_variable == nullptr) { - VariableProxy* proxy = - factory->NewVariableProxy(name, NORMAL_VARIABLE); - auto declaration = - factory->NewVariableDeclaration(proxy, this, kNoSourcePosition); - // Based on the preceding check, it doesn't matter what we pass as - // allow_harmony_restrictive_generators and - // sloppy_mode_block_scope_function_redefinition. - bool ok = true; - created_variable = DeclareVariable( - declaration, VAR, Variable::DefaultInitializationFlag(VAR), false, - nullptr, &ok); - CHECK(ok); // Based on the preceding check, this should not fail - } - Expression* assignment = factory->NewAssignment( Token::ASSIGN, NewUnresolved(factory, name), delegate->scope()->NewUnresolved(factory, name), kNoSourcePosition); Statement* statement = factory->NewExpressionStatement(assignment, kNoSourcePosition); delegate->set_statement(statement); - } else { - DCHECK(is_being_lazily_parsed_); - if (created_variable == nullptr) { - created_variable = DeclareVariableName(name, VAR); - if (created_variable != kDummyPreParserVariable && - created_variable != kDummyPreParserLexicalVariable) { - DCHECK(FLAG_preparser_scope_analysis); - created_variable->set_maybe_assigned(); - } - } + } + } + } + + if (names_to_declare.empty()) return; + + for (const auto& index_and_name : names_to_declare) { + const AstRawString* name = index_and_name.second; + if (factory) { + DCHECK(!is_being_lazily_parsed_); + VariableProxy* proxy = factory->NewVariableProxy(name, NORMAL_VARIABLE); + auto declaration = + factory->NewVariableDeclaration(proxy, this, kNoSourcePosition); + // Based on the preceding checks, it doesn't matter what we pass as + // allow_harmony_restrictive_generators and + // sloppy_mode_block_scope_function_redefinition. + bool ok = true; + DeclareVariable(declaration, VAR, + Variable::DefaultInitializationFlag(VAR), false, nullptr, + &ok); + DCHECK(ok); + } else { + DCHECK(is_being_lazily_parsed_); + Variable* var = DeclareVariableName(name, VAR); + if (var != kDummyPreParserVariable && + var != kDummyPreParserLexicalVariable) { + DCHECK(FLAG_preparser_scope_analysis); + var->set_maybe_assigned(); } } } } -void DeclarationScope::Analyze(ParseInfo* info, AnalyzeMode mode) { - RuntimeCallTimerScope runtimeTimer(info->isolate(), +void DeclarationScope::Analyze(ParseInfo* info, Isolate* isolate, + AnalyzeMode mode) { + RuntimeCallTimerScope runtimeTimer(isolate, &RuntimeCallStats::CompileScopeAnalysis); DCHECK(info->literal() != NULL); DeclarationScope* scope = info->literal()->scope(); + DCHECK(scope->scope_info_.is_null()); Handle<ScopeInfo> outer_scope_info; if (info->maybe_outer_scope_info().ToHandle(&outer_scope_info)) { @@ -595,7 +634,7 @@ void DeclarationScope::Analyze(ParseInfo* info, AnalyzeMode mode) { DeclarationScope(info->zone(), info->ast_value_factory()); info->set_script_scope(script_scope); scope->ReplaceOuterScope(Scope::DeserializeScopeChain( - info->isolate(), info->zone(), *outer_scope_info, script_scope, + info->zone(), *outer_scope_info, script_scope, info->ast_value_factory(), Scope::DeserializationMode::kIncludingVariables)); } else { @@ -622,13 +661,19 @@ void DeclarationScope::Analyze(ParseInfo* info, AnalyzeMode mode) { // The outer scope is never lazy. scope->set_should_eager_compile(); - scope->AllocateVariables(info, mode); + if (scope->must_use_preparsed_scope_data_) { + DCHECK(FLAG_preparser_scope_analysis); + DCHECK_NOT_NULL(info->preparsed_scope_data()); + DCHECK_EQ(scope->scope_type_, ScopeType::FUNCTION_SCOPE); + info->preparsed_scope_data()->RestoreData(scope); + } + + scope->AllocateVariables(info, isolate, mode); // Ensuring that the outer script scope has a scope info avoids having // special case for native contexts vs other contexts. if (info->script_scope()->scope_info_.is_null()) { - info->script_scope()->scope_info_ = - handle(ScopeInfo::Empty(info->isolate())); + info->script_scope()->scope_info_ = handle(ScopeInfo::Empty(isolate)); } #ifdef DEBUG @@ -722,6 +767,16 @@ Variable* DeclarationScope::DeclarePromiseVar(const AstRawString* name) { return result; } +Variable* DeclarationScope::DeclareAsyncGeneratorAwaitVar( + const AstRawString* name) { + DCHECK(is_function_scope()); + DCHECK_NULL(async_generator_await_var()); + Variable* result = EnsureRareData()->promise = NewTemporary(name); + DCHECK_NULL(promise_var()); // promise is alias for generator await var + result->set_is_used(); + return result; +} + bool Scope::HasBeenRemoved() const { if (sibling() == this) { DCHECK_NULL(inner_scope_); @@ -778,7 +833,9 @@ Scope* Scope::FinalizeBlockScope() { unresolved_ = nullptr; } - PropagateUsageFlagsToScope(outer_scope_); + if (scope_calls_eval_) outer_scope()->scope_calls_eval_ = true; + if (inner_scope_calls_eval_) outer_scope()->inner_scope_calls_eval_ = true; + // This block does not need a context. num_heap_slots_ = 0; @@ -820,10 +877,15 @@ void Scope::Snapshot::Reparent(DeclarationScope* new_parent) const { for (; inner_scope->sibling() != top_inner_scope_; inner_scope = inner_scope->sibling()) { inner_scope->outer_scope_ = new_parent; + if (inner_scope->inner_scope_calls_eval_) { + new_parent->inner_scope_calls_eval_ = true; + } DCHECK_NE(inner_scope, new_parent); } inner_scope->outer_scope_ = new_parent; - + if (inner_scope->inner_scope_calls_eval_) { + new_parent->inner_scope_calls_eval_ = true; + } new_parent->inner_scope_ = new_parent->sibling_; inner_scope->sibling_ = nullptr; // Reset the sibling rather than the inner_scope_ since we @@ -860,6 +922,15 @@ void Scope::Snapshot::Reparent(DeclarationScope* new_parent) const { } outer_closure->locals_.Rewind(top_local_); outer_closure->decls_.Rewind(top_decl_); + + // Move eval calls since Snapshot's creation into new_parent. + if (outer_scope_->scope_calls_eval_) { + new_parent->scope_calls_eval_ = true; + new_parent->inner_scope_calls_eval_ = true; + } + // Reset the outer_scope's eval state. It will be restored to its + // original value as necessary in the destructor of this class. + outer_scope_->scope_calls_eval_ = false; } void Scope::ReplaceOuterScope(Scope* outer) { @@ -871,15 +942,6 @@ void Scope::ReplaceOuterScope(Scope* outer) { outer_scope_ = outer; } - -void Scope::PropagateUsageFlagsToScope(Scope* other) { - DCHECK_NOT_NULL(other); - DCHECK(!already_resolved_); - DCHECK(!other->already_resolved_); - if (calls_eval()) other->RecordEvalCall(); - if (inner_scope_calls_eval_) other->inner_scope_calls_eval_ = true; -} - Variable* Scope::LookupInScopeInfo(const AstRawString* name) { Handle<String> name_handle = name->string(); // The Scope is backed up by ScopeInfo. This means it cannot operate in a @@ -946,7 +1008,7 @@ Variable* Scope::Lookup(const AstRawString* name) { Variable* DeclarationScope::DeclareParameter( const AstRawString* name, VariableMode mode, bool is_optional, bool is_rest, - bool* is_duplicate, AstValueFactory* ast_value_factory) { + bool* is_duplicate, AstValueFactory* ast_value_factory, int position) { DCHECK(!already_resolved_); DCHECK(is_function_scope() || is_module_scope()); DCHECK(!has_rest_); @@ -963,6 +1025,7 @@ Variable* DeclarationScope::DeclareParameter( *is_duplicate = IsDeclaredParameter(name); } has_rest_ = is_rest; + var->set_initializer_position(position); params_.Add(var, zone()); if (name == ast_value_factory->arguments_string()) { has_arguments_parameter_ = true; @@ -1071,12 +1134,14 @@ Variable* Scope::DeclareVariable( // will be a permitted duplicate. FunctionKind function_kind = declaration->AsFunctionDeclaration()->fun()->kind(); - duplicate_allowed = - GetDeclarationScope()->sloppy_block_function_map()->Lookup( - const_cast<AstRawString*>(name), name->hash()) != nullptr && - !IsAsyncFunction(function_kind) && - !(allow_harmony_restrictive_generators && - IsGeneratorFunction(function_kind)); + SloppyBlockFunctionMap* map = + GetDeclarationScope()->sloppy_block_function_map(); + duplicate_allowed = map != nullptr && + map->Lookup(const_cast<AstRawString*>(name), + name->hash()) != nullptr && + !IsAsyncFunction(function_kind) && + !(allow_harmony_restrictive_generators && + IsGeneratorFunction(function_kind)); } if (duplicate_allowed) { *sloppy_mode_block_scope_function_redefinition = true; @@ -1264,7 +1329,8 @@ Declaration* Scope::CheckLexDeclarationsConflictingWith( return nullptr; } -void DeclarationScope::AllocateVariables(ParseInfo* info, AnalyzeMode mode) { +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. if (is_module_scope()) AsModuleScope()->AllocateModuleVariables(); @@ -1275,16 +1341,16 @@ void DeclarationScope::AllocateVariables(ParseInfo* info, AnalyzeMode mode) { MaybeHandle<ScopeInfo> outer_scope; if (outer_scope_ != nullptr) outer_scope = outer_scope_->scope_info_; - AllocateScopeInfosRecursively(info->isolate(), outer_scope); + AllocateScopeInfosRecursively(isolate, outer_scope); if (mode == AnalyzeMode::kDebugger) { - AllocateDebuggerScopeInfos(info->isolate(), outer_scope); + AllocateDebuggerScopeInfos(isolate, outer_scope); } // The debugger expects all shared function infos to contain a scope info. // Since the top-most scope will end up in a shared function info, make sure // it has one, even if it doesn't need a scope info. // TODO(jochen|yangguo): Remove this requirement. if (scope_info_.is_null()) { - scope_info_ = ScopeInfo::Create(info->isolate(), zone(), this, outer_scope); + scope_info_ = ScopeInfo::Create(isolate, zone(), this, outer_scope); } } @@ -1439,12 +1505,12 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory, locals_.Clear(); inner_scope_ = nullptr; unresolved_ = nullptr; + sloppy_block_function_map_ = nullptr; if (aborted) { // Prepare scope for use in the outer zone. zone_ = ast_value_factory->zone(); variables_.Reset(ZoneAllocationPolicy(zone_)); - sloppy_block_function_map_.Reset(ZoneAllocationPolicy(zone_)); if (!IsArrowFunction(function_kind_)) { DeclareDefaultFunctionVariables(ast_value_factory); } @@ -1452,7 +1518,6 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory, // Make sure this scope isn't used for allocation anymore. zone_ = nullptr; variables_.Invalidate(); - sloppy_block_function_map_.Invalidate(); } #ifdef DEBUG @@ -1487,11 +1552,10 @@ void DeclarationScope::AnalyzePartially( arguments_ = nullptr; } - if (FLAG_preparser_scope_analysis) { - // Decide context allocation for the locals and parameters and store the - // info away. - AllocateVariablesRecursively(); - CollectVariableData(preparsed_scope_data); + if (FLAG_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); } } #ifdef DEBUG @@ -1564,7 +1628,7 @@ void PrintVar(int indent, Variable* var) { PrintF(".%p", reinterpret_cast<void*>(var)); else PrintName(var->raw_name()); - PrintF("; // "); + PrintF("; // (%p) ", reinterpret_cast<void*>(var)); PrintLocation(var); bool comma = !var->IsUnallocated(); if (var->has_forced_context_allocation()) { @@ -1637,7 +1701,8 @@ void Scope::Print(int n) { function = AsDeclarationScope()->function_var(); } - PrintF(" { // (%d, %d)\n", start_position(), end_position()); + PrintF(" { // (%p) (%d, %d)\n", reinterpret_cast<void*>(this), + start_position(), end_position()); if (is_hidden()) { Indent(n1, "// is hidden\n"); } @@ -2269,17 +2334,6 @@ void Scope::AllocateDebuggerScopeInfos(Isolate* isolate, } } -void Scope::CollectVariableData(PreParsedScopeData* data) { - PreParsedScopeData::ScopeScope scope_scope(data, scope_type(), - start_position(), end_position()); - for (Variable* local : locals_) { - scope_scope.MaybeAddVariable(local); - } - for (Scope* inner = inner_scope_; inner != nullptr; inner = inner->sibling_) { - inner->CollectVariableData(data); - } -} - int Scope::StackLocalCount() const { Variable* function = is_function_scope() ? AsDeclarationScope()->function_var() : nullptr; diff --git a/deps/v8/src/ast/scopes.h b/deps/v8/src/ast/scopes.h index 119d77c5c8..c7de9e88ee 100644 --- a/deps/v8/src/ast/scopes.h +++ b/deps/v8/src/ast/scopes.h @@ -53,22 +53,27 @@ class SloppyBlockFunctionMap : public ZoneHashMap { public: class Delegate : public ZoneObject { public: - explicit Delegate(Scope* scope, - SloppyBlockFunctionStatement* statement = nullptr) - : scope_(scope), statement_(statement), next_(nullptr) {} + Delegate(Scope* scope, SloppyBlockFunctionStatement* statement, int index) + : scope_(scope), statement_(statement), next_(nullptr), index_(index) {} void set_statement(Statement* statement); void set_next(Delegate* next) { next_ = next; } Delegate* next() const { return next_; } Scope* scope() const { return scope_; } + int index() const { return index_; } private: Scope* scope_; SloppyBlockFunctionStatement* statement_; Delegate* next_; + int index_; }; explicit SloppyBlockFunctionMap(Zone* zone); - void Declare(Zone* zone, const AstRawString* name, Delegate* delegate); + void Declare(Zone* zone, const AstRawString* name, Scope* scope, + SloppyBlockFunctionStatement* statement); + + private: + int count_; }; enum class AnalyzeMode { kRegular, kDebugger }; @@ -112,6 +117,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { class Snapshot final BASE_EMBEDDED { public: explicit Snapshot(Scope* scope); + ~Snapshot(); void Reparent(DeclarationScope* new_parent) const; @@ -121,12 +127,12 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { VariableProxy* top_unresolved_; ThreadedList<Variable>::Iterator top_local_; ThreadedList<Declaration>::Iterator top_decl_; + const bool outer_scope_calls_eval_; }; enum class DeserializationMode { kIncludingVariables, kScopesOnly }; - static Scope* DeserializeScopeChain(Isolate* isolate, Zone* zone, - ScopeInfo* scope_info, + static Scope* DeserializeScopeChain(Zone* zone, ScopeInfo* scope_info, DeclarationScope* script_scope, AstValueFactory* ast_value_factory, DeserializationMode deserialization_mode); @@ -146,12 +152,22 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { // Assumes outer_scope_ is non-null. void ReplaceOuterScope(Scope* outer_scope); - // Propagates any eagerly-gathered scope usage flags (such as calls_eval()) - // to the passed-in scope. - void PropagateUsageFlagsToScope(Scope* other); - Zone* zone() const { return zone_; } + void SetMustUsePreParsedScopeData() { + if (must_use_preparsed_scope_data_) { + return; + } + must_use_preparsed_scope_data_ = true; + if (outer_scope_) { + outer_scope_->SetMustUsePreParsedScopeData(); + } + } + + bool must_use_preparsed_scope_data() const { + return must_use_preparsed_scope_data_; + } + // --------------------------------------------------------------------------- // Declarations @@ -357,10 +373,10 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { // The scope immediately surrounding this scope, or NULL. Scope* outer_scope() const { return outer_scope_; } - const AstRawString* catch_variable_name() const { + Variable* catch_variable() const { DCHECK(is_catch_scope()); DCHECK_EQ(1, num_var()); - return static_cast<AstRawString*>(variables_.Start()->key); + return static_cast<Variable*>(variables_.Start()->value); } // --------------------------------------------------------------------------- @@ -546,12 +562,15 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { // Temporary workaround that allows masking of 'this' in debug-evalute scopes. bool is_debug_evaluate_scope_ : 1; + // True if one of the inner scopes or the scope itself calls eval. bool inner_scope_calls_eval_ : 1; bool force_context_allocation_ : 1; // True if it holds 'var' declarations. bool is_declaration_scope_ : 1; + bool must_use_preparsed_scope_data_ : 1; + // Create a non-local variable with a given name. // These variables are looked up dynamically at runtime. Variable* NonLocal(const AstRawString* name, VariableMode mode); @@ -590,14 +609,12 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { void AllocateDebuggerScopeInfos(Isolate* isolate, MaybeHandle<ScopeInfo> outer_scope); - void CollectVariableData(PreParsedScopeData* data); - // Construct a scope based on the scope info. Scope(Zone* zone, ScopeType type, Handle<ScopeInfo> scope_info); // Construct a catch scope with a binding for the name. Scope(Zone* zone, const AstRawString* catch_variable_name, - Handle<ScopeInfo> scope_info); + MaybeAssignedFlag maybe_assigned, Handle<ScopeInfo> scope_info); void AddInnerScope(Scope* inner_scope) { inner_scope->sibling_ = inner_scope_; @@ -686,13 +703,14 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { // Ignition without ScopeInfo. Variable* DeclareGeneratorObjectVar(const AstRawString* name); Variable* DeclarePromiseVar(const AstRawString* name); + Variable* DeclareAsyncGeneratorAwaitVar(const AstRawString* name); // Declare a parameter in this scope. When there are duplicated // parameters the rightmost one 'wins'. However, the implementation // expects all parameters to be declared and from left to right. Variable* DeclareParameter(const AstRawString* name, VariableMode mode, bool is_optional, bool is_rest, bool* is_duplicate, - AstValueFactory* ast_value_factory); + AstValueFactory* ast_value_factory, int position); // Declares that a parameter with the name exists. Creates a Variable and // returns it if FLAG_preparser_scope_analysis is on. @@ -738,9 +756,16 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { Variable* promise_var() const { DCHECK(is_function_scope()); DCHECK(IsAsyncFunction(function_kind_)); + if (IsAsyncGeneratorFunction(function_kind_)) return nullptr; return GetRareVariable(RareVariable::kPromise); } + Variable* async_generator_await_var() const { + DCHECK(is_function_scope()); + DCHECK(IsAsyncGeneratorFunction(function_kind_)); + return GetRareVariable(RareVariable::kAsyncGeneratorAwaitResult); + } + // Parameters. The left-most parameter has index 0. // Only valid for function and module scopes. Variable* parameter(int index) const { @@ -805,13 +830,13 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { void HoistSloppyBlockFunctions(AstNodeFactory* factory); SloppyBlockFunctionMap* sloppy_block_function_map() { - return &sloppy_block_function_map_; + return sloppy_block_function_map_; } // Compute top scope and allocate variables. For lazy compilation the top // scope only contains the single lazily compiled function, so this // doesn't re-allocate variables repeatedly. - static void Analyze(ParseInfo* info, AnalyzeMode mode); + static void Analyze(ParseInfo* info, Isolate* isolate, AnalyzeMode mode); // To be called during parsing. Do just enough scope analysis that we can // discard the Scope for lazily compiled functions. In particular, this @@ -848,6 +873,11 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { void ResetAfterPreparsing(AstValueFactory* ast_value_factory, bool aborted); + bool is_skipped_function() const { return is_skipped_function_; } + void set_is_skipped_function(bool is_skipped_function) { + is_skipped_function_ = is_skipped_function; + } + private: void AllocateParameter(Variable* var, int index); @@ -859,7 +889,7 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { // In the case of code compiled and run using 'eval', the context // parameter is the context in which eval was called. In all other // cases the context parameter is an empty handle. - void AllocateVariables(ParseInfo* info, AnalyzeMode mode); + void AllocateVariables(ParseInfo* info, Isolate* isolate, AnalyzeMode mode); void SetDefaults(); @@ -884,11 +914,12 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { #if DEBUG bool is_being_lazily_parsed_ : 1; #endif + bool is_skipped_function_ : 1; // Parameter list in source order. ZoneList<Variable*> params_; // Map of function names to lists of functions defined in sloppy blocks - SloppyBlockFunctionMap sloppy_block_function_map_; + SloppyBlockFunctionMap* sloppy_block_function_map_; // Convenience variable. Variable* receiver_; // Function variable, if any; function scopes only. @@ -912,7 +943,8 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { enum class RareVariable { kThisFunction = offsetof(RareData, this_function), kGeneratorObject = offsetof(RareData, generator_object), - kPromise = offsetof(RareData, promise) + kPromise = offsetof(RareData, promise), + kAsyncGeneratorAwaitResult = kPromise }; V8_INLINE RareData* EnsureRareData() { @@ -950,8 +982,7 @@ class ModuleScope final : public DeclarationScope { // The generated ModuleDescriptor does not preserve all information. In // particular, its module_requests map will be empty because we no longer need // the map after parsing. - ModuleScope(Isolate* isolate, Handle<ScopeInfo> scope_info, - AstValueFactory* ast_value_factory); + ModuleScope(Handle<ScopeInfo> scope_info, AstValueFactory* ast_value_factory); ModuleDescriptor* module() const { DCHECK_NOT_NULL(module_descriptor_); diff --git a/deps/v8/src/ast/variables.h b/deps/v8/src/ast/variables.h index b7d9226b1c..3eaa105168 100644 --- a/deps/v8/src/ast/variables.h +++ b/deps/v8/src/ast/variables.h @@ -100,6 +100,12 @@ class Variable final : public ZoneObject { int index() const { return index_; } + bool IsReceiver() const { + DCHECK(IsParameter()); + + return index_ == -1; + } + bool IsExport() const { DCHECK_EQ(location(), VariableLocation::MODULE); DCHECK_NE(index(), 0); |