diff options
Diffstat (limited to 'deps/v8/src/ast')
-rw-r--r-- | deps/v8/src/ast/ast-expression-rewriter.cc | 6 | ||||
-rw-r--r-- | deps/v8/src/ast/ast-function-literal-id-reindexer.cc | 29 | ||||
-rw-r--r-- | deps/v8/src/ast/ast-function-literal-id-reindexer.h | 36 | ||||
-rw-r--r-- | deps/v8/src/ast/ast-literal-reindexer.cc | 4 | ||||
-rw-r--r-- | deps/v8/src/ast/ast-numbering.cc | 119 | ||||
-rw-r--r-- | deps/v8/src/ast/ast-numbering.h | 15 | ||||
-rw-r--r-- | deps/v8/src/ast/ast-traversal-visitor.h | 8 | ||||
-rw-r--r-- | deps/v8/src/ast/ast-types.cc | 7 | ||||
-rw-r--r-- | deps/v8/src/ast/ast-value-factory.cc | 45 | ||||
-rw-r--r-- | deps/v8/src/ast/ast-value-factory.h | 129 | ||||
-rw-r--r-- | deps/v8/src/ast/ast.cc | 226 | ||||
-rw-r--r-- | deps/v8/src/ast/ast.h | 353 | ||||
-rw-r--r-- | deps/v8/src/ast/compile-time-value.cc | 4 | ||||
-rw-r--r-- | deps/v8/src/ast/compile-time-value.h | 4 | ||||
-rw-r--r-- | deps/v8/src/ast/modules.cc | 2 | ||||
-rw-r--r-- | deps/v8/src/ast/prettyprinter.cc | 53 | ||||
-rw-r--r-- | deps/v8/src/ast/prettyprinter.h | 4 | ||||
-rw-r--r-- | deps/v8/src/ast/scopeinfo.cc | 975 | ||||
-rw-r--r-- | deps/v8/src/ast/scopes.cc | 511 | ||||
-rw-r--r-- | deps/v8/src/ast/scopes.h | 118 | ||||
-rw-r--r-- | deps/v8/src/ast/variables.cc | 1 |
21 files changed, 1070 insertions, 1579 deletions
diff --git a/deps/v8/src/ast/ast-expression-rewriter.cc b/deps/v8/src/ast/ast-expression-rewriter.cc index d0db9eab66..f46e21b410 100644 --- a/deps/v8/src/ast/ast-expression-rewriter.cc +++ b/deps/v8/src/ast/ast-expression-rewriter.cc @@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "src/ast/ast.h" #include "src/ast/ast-expression-rewriter.h" +#include "src/ast/ast.h" +#include "src/objects-inl.h" namespace v8 { namespace internal { @@ -372,6 +373,9 @@ void AstExpressionRewriter::VisitEmptyParentheses(EmptyParentheses* node) { NOTHING(); } +void AstExpressionRewriter::VisitGetIterator(GetIterator* node) { + AST_REWRITE_PROPERTY(Expression, node, iterable); +} void AstExpressionRewriter::VisitDoExpression(DoExpression* node) { REWRITE_THIS(node); diff --git a/deps/v8/src/ast/ast-function-literal-id-reindexer.cc b/deps/v8/src/ast/ast-function-literal-id-reindexer.cc new file mode 100644 index 0000000000..5cb1e87d23 --- /dev/null +++ b/deps/v8/src/ast/ast-function-literal-id-reindexer.cc @@ -0,0 +1,29 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/ast/ast-function-literal-id-reindexer.h" +#include "src/objects-inl.h" + +#include "src/ast/ast.h" + +namespace v8 { +namespace internal { + +AstFunctionLiteralIdReindexer::AstFunctionLiteralIdReindexer(size_t stack_limit, + int delta) + : AstTraversalVisitor(stack_limit), delta_(delta) {} + +AstFunctionLiteralIdReindexer::~AstFunctionLiteralIdReindexer() {} + +void AstFunctionLiteralIdReindexer::Reindex(Expression* pattern) { + Visit(pattern); +} + +void AstFunctionLiteralIdReindexer::VisitFunctionLiteral(FunctionLiteral* lit) { + AstTraversalVisitor::VisitFunctionLiteral(lit); + lit->set_function_literal_id(lit->function_literal_id() + delta_); +} + +} // namespace internal +} // namespace v8 diff --git a/deps/v8/src/ast/ast-function-literal-id-reindexer.h b/deps/v8/src/ast/ast-function-literal-id-reindexer.h new file mode 100644 index 0000000000..837595f41b --- /dev/null +++ b/deps/v8/src/ast/ast-function-literal-id-reindexer.h @@ -0,0 +1,36 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_AST_AST_FUNCTION_LITERAL_ID_REINDEXER +#define V8_AST_AST_FUNCTION_LITERAL_ID_REINDEXER + +#include "src/ast/ast-traversal-visitor.h" +#include "src/base/macros.h" + +namespace v8 { +namespace internal { + +// Changes the ID of all FunctionLiterals in the given Expression by adding the +// given delta. +class AstFunctionLiteralIdReindexer final + : public AstTraversalVisitor<AstFunctionLiteralIdReindexer> { + public: + AstFunctionLiteralIdReindexer(size_t stack_limit, int delta); + ~AstFunctionLiteralIdReindexer(); + + void Reindex(Expression* pattern); + + // AstTraversalVisitor implementation. + void VisitFunctionLiteral(FunctionLiteral* lit); + + private: + int delta_; + + DISALLOW_COPY_AND_ASSIGN(AstFunctionLiteralIdReindexer); +}; + +} // namespace internal +} // namespace v8 + +#endif // V8_AST_AST_FUNCTION_LITERAL_ID_REINDEXER diff --git a/deps/v8/src/ast/ast-literal-reindexer.cc b/deps/v8/src/ast/ast-literal-reindexer.cc index 81a5225fdc..67e180fe42 100644 --- a/deps/v8/src/ast/ast-literal-reindexer.cc +++ b/deps/v8/src/ast/ast-literal-reindexer.cc @@ -6,6 +6,7 @@ #include "src/ast/ast.h" #include "src/ast/scopes.h" +#include "src/objects-inl.h" namespace v8 { namespace internal { @@ -186,6 +187,9 @@ void AstLiteralReindexer::VisitSpread(Spread* node) { void AstLiteralReindexer::VisitEmptyParentheses(EmptyParentheses* node) {} +void AstLiteralReindexer::VisitGetIterator(GetIterator* node) { + Visit(node->iterable()); +} void AstLiteralReindexer::VisitForInStatement(ForInStatement* node) { Visit(node->each()); diff --git a/deps/v8/src/ast/ast-numbering.cc b/deps/v8/src/ast/ast-numbering.cc index 82f9767281..25aa9d7a5a 100644 --- a/deps/v8/src/ast/ast-numbering.cc +++ b/deps/v8/src/ast/ast-numbering.cc @@ -6,22 +6,26 @@ #include "src/ast/ast.h" #include "src/ast/scopes.h" +#include "src/compiler.h" +#include "src/objects-inl.h" namespace v8 { namespace internal { class AstNumberingVisitor final : public AstVisitor<AstNumberingVisitor> { public: - AstNumberingVisitor(Isolate* isolate, Zone* zone) - : isolate_(isolate), - zone_(zone), + AstNumberingVisitor(uintptr_t stack_limit, Zone* zone, + Compiler::EagerInnerFunctionLiterals* eager_literals) + : zone_(zone), + eager_literals_(eager_literals), next_id_(BailoutId::FirstUsable().ToInt()), yield_count_(0), properties_(zone), slot_cache_(zone), + disable_crankshaft_reason_(kNoReason), dont_optimize_reason_(kNoReason), catch_prediction_(HandlerTable::UNCAUGHT) { - InitializeAstVisitor(isolate); + InitializeAstVisitor(stack_limit); } bool Renumber(FunctionLiteral* node); @@ -55,25 +59,28 @@ class AstNumberingVisitor final : public AstVisitor<AstNumberingVisitor> { dont_optimize_reason_ = reason; DisableSelfOptimization(); } - void DisableCrankshaft(BailoutReason reason) { - properties_.flags() |= AstProperties::kDontCrankshaft; + void DisableFullCodegenAndCrankshaft(BailoutReason reason) { + disable_crankshaft_reason_ = reason; + properties_.flags() |= AstProperties::kMustUseIgnitionTurbo; } template <typename Node> void ReserveFeedbackSlots(Node* node) { - node->AssignFeedbackVectorSlots(isolate_, properties_.get_spec(), - &slot_cache_); + node->AssignFeedbackVectorSlots(properties_.get_spec(), &slot_cache_); } BailoutReason dont_optimize_reason() const { return dont_optimize_reason_; } - Isolate* isolate_; + Zone* zone() const { return zone_; } + Zone* zone_; + Compiler::EagerInnerFunctionLiterals* eager_literals_; int next_id_; int yield_count_; AstProperties properties_; // The slot cache allows us to reuse certain feedback vector slots. FeedbackVectorSlotCache slot_cache_; + BailoutReason disable_crankshaft_reason_; BailoutReason dont_optimize_reason_; HandlerTable::CatchPrediction catch_prediction_; @@ -122,6 +129,7 @@ void AstNumberingVisitor::VisitNativeFunctionLiteral( IncrementNodeCount(); DisableOptimization(kNativeFunctionLiteral); node->set_base_id(ReserveIdRange(NativeFunctionLiteral::num_ids())); + ReserveFeedbackSlots(node); } @@ -149,10 +157,11 @@ void AstNumberingVisitor::VisitVariableProxyReference(VariableProxy* node) { IncrementNodeCount(); switch (node->var()->location()) { case VariableLocation::LOOKUP: - DisableCrankshaft(kReferenceToAVariableWhichRequiresDynamicLookup); + DisableFullCodegenAndCrankshaft( + kReferenceToAVariableWhichRequiresDynamicLookup); break; case VariableLocation::MODULE: - DisableCrankshaft(kReferenceToModuleVariable); + DisableFullCodegenAndCrankshaft(kReferenceToModuleVariable); break; default: break; @@ -176,7 +185,7 @@ void AstNumberingVisitor::VisitThisFunction(ThisFunction* node) { void AstNumberingVisitor::VisitSuperPropertyReference( SuperPropertyReference* node) { IncrementNodeCount(); - DisableCrankshaft(kSuperReference); + DisableFullCodegenAndCrankshaft(kSuperReference); node->set_base_id(ReserveIdRange(SuperPropertyReference::num_ids())); Visit(node->this_var()); Visit(node->home_object()); @@ -185,7 +194,7 @@ void AstNumberingVisitor::VisitSuperPropertyReference( void AstNumberingVisitor::VisitSuperCallReference(SuperCallReference* node) { IncrementNodeCount(); - DisableCrankshaft(kSuperReference); + DisableFullCodegenAndCrankshaft(kSuperReference); node->set_base_id(ReserveIdRange(SuperCallReference::num_ids())); Visit(node->this_var()); Visit(node->new_target_var()); @@ -282,8 +291,7 @@ void AstNumberingVisitor::VisitCallRuntime(CallRuntime* node) { void AstNumberingVisitor::VisitWithStatement(WithStatement* node) { IncrementNodeCount(); - DisableCrankshaft(kWithStatement); - node->set_base_id(ReserveIdRange(WithStatement::num_ids())); + DisableFullCodegenAndCrankshaft(kWithStatement); Visit(node->expression()); Visit(node->statement()); } @@ -313,7 +321,7 @@ void AstNumberingVisitor::VisitWhileStatement(WhileStatement* node) { void AstNumberingVisitor::VisitTryCatchStatement(TryCatchStatement* node) { IncrementNodeCount(); - DisableCrankshaft(kTryCatchStatement); + DisableFullCodegenAndCrankshaft(kTryCatchStatement); { const HandlerTable::CatchPrediction old_prediction = catch_prediction_; // This node uses its own prediction, unless it's "uncaught", in which case @@ -332,7 +340,7 @@ void AstNumberingVisitor::VisitTryCatchStatement(TryCatchStatement* node) { void AstNumberingVisitor::VisitTryFinallyStatement(TryFinallyStatement* node) { IncrementNodeCount(); - DisableCrankshaft(kTryFinallyStatement); + DisableFullCodegenAndCrankshaft(kTryFinallyStatement); // We can't know whether the finally block will override ("catch") an // exception thrown in the try block, so we just adopt the outer prediction. node->set_catch_prediction(catch_prediction_); @@ -393,14 +401,25 @@ void AstNumberingVisitor::VisitCompareOperation(CompareOperation* node) { ReserveFeedbackSlots(node); } - -void AstNumberingVisitor::VisitSpread(Spread* node) { UNREACHABLE(); } - +void AstNumberingVisitor::VisitSpread(Spread* node) { + IncrementNodeCount(); + // We can only get here from super calls currently. + DisableFullCodegenAndCrankshaft(kSuperReference); + node->set_base_id(ReserveIdRange(Spread::num_ids())); + Visit(node->expression()); +} void AstNumberingVisitor::VisitEmptyParentheses(EmptyParentheses* node) { UNREACHABLE(); } +void AstNumberingVisitor::VisitGetIterator(GetIterator* node) { + IncrementNodeCount(); + DisableFullCodegenAndCrankshaft(kGetIterator); + node->set_base_id(ReserveIdRange(GetIterator::num_ids())); + Visit(node->iterable()); + ReserveFeedbackSlots(node); +} void AstNumberingVisitor::VisitForInStatement(ForInStatement* node) { IncrementNodeCount(); @@ -417,7 +436,7 @@ void AstNumberingVisitor::VisitForInStatement(ForInStatement* node) { void AstNumberingVisitor::VisitForOfStatement(ForOfStatement* node) { IncrementNodeCount(); - DisableCrankshaft(kForOfStatement); + 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_); @@ -484,8 +503,8 @@ void AstNumberingVisitor::VisitForStatement(ForStatement* node) { void AstNumberingVisitor::VisitClassLiteral(ClassLiteral* node) { IncrementNodeCount(); - DisableCrankshaft(kClassLiteral); - node->set_base_id(ReserveIdRange(node->num_ids())); + DisableFullCodegenAndCrankshaft(kClassLiteral); + node->set_base_id(ReserveIdRange(ClassLiteral::num_ids())); if (node->extends()) Visit(node->extends()); if (node->constructor()) Visit(node->constructor()); if (node->class_variable_proxy()) { @@ -504,7 +523,7 @@ void AstNumberingVisitor::VisitObjectLiteral(ObjectLiteral* node) { for (int i = 0; i < node->properties()->length(); i++) { VisitLiteralProperty(node->properties()->at(i)); } - node->BuildConstantProperties(isolate_); + node->InitDepthAndFlags(); // Mark all computed expressions that are bound to a key that // is shadowed by a later occurrence of the same key. For the // marked expressions, no store code will be is emitted. @@ -513,7 +532,8 @@ void AstNumberingVisitor::VisitObjectLiteral(ObjectLiteral* node) { } void AstNumberingVisitor::VisitLiteralProperty(LiteralProperty* node) { - if (node->is_computed_name()) DisableCrankshaft(kComputedPropertyName); + if (node->is_computed_name()) + DisableFullCodegenAndCrankshaft(kComputedPropertyName); Visit(node->key()); Visit(node->value()); } @@ -524,12 +544,15 @@ void AstNumberingVisitor::VisitArrayLiteral(ArrayLiteral* node) { for (int i = 0; i < node->values()->length(); i++) { Visit(node->values()->at(i)); } - node->BuildConstantElements(isolate_); + node->InitDepthAndFlags(); ReserveFeedbackSlots(node); } void AstNumberingVisitor::VisitCall(Call* node) { + if (node->is_possibly_eval()) { + DisableFullCodegenAndCrankshaft(kFunctionCallsEval); + } IncrementNodeCount(); ReserveFeedbackSlots(node); node->set_base_id(ReserveIdRange(Call::num_ids())); @@ -569,8 +592,13 @@ void AstNumberingVisitor::VisitArguments(ZoneList<Expression*>* arguments) { void AstNumberingVisitor::VisitFunctionLiteral(FunctionLiteral* node) { IncrementNodeCount(); node->set_base_id(ReserveIdRange(FunctionLiteral::num_ids())); + if (eager_literals_ && node->ShouldEagerCompile()) { + eager_literals_->Add(new (zone()) + ThreadedListZoneEntry<FunctionLiteral*>(node)); + } // We don't recurse into the declarations or body of the function literal: // you have to separately Renumber() each FunctionLiteral that you compile. + ReserveFeedbackSlots(node); } @@ -584,22 +612,26 @@ void AstNumberingVisitor::VisitRewritableExpression( bool AstNumberingVisitor::Renumber(FunctionLiteral* node) { DeclarationScope* scope = node->scope(); - if (scope->new_target_var()) DisableCrankshaft(kSuperReference); - if (scope->calls_eval()) DisableCrankshaft(kFunctionCallsEval); - if (scope->arguments() != NULL && !scope->arguments()->IsStackAllocated()) { - DisableCrankshaft(kContextAllocatedArguments); + if (scope->new_target_var() != nullptr || + scope->this_function_var() != nullptr) { + DisableFullCodegenAndCrankshaft(kSuperReference); + } + + if (scope->arguments() != nullptr && + !scope->arguments()->IsStackAllocated()) { + DisableFullCodegenAndCrankshaft(kContextAllocatedArguments); } if (scope->rest_parameter() != nullptr) { - DisableCrankshaft(kRestParameter); + DisableFullCodegenAndCrankshaft(kRestParameter); } - if (IsGeneratorFunction(node->kind()) || IsAsyncFunction(node->kind())) { - DisableCrankshaft(kGenerator); + if (IsResumableFunction(node->kind())) { + DisableFullCodegenAndCrankshaft(kGenerator); } if (IsClassConstructor(node->kind())) { - DisableCrankshaft(kClassConstructorFunction); + DisableFullCodegenAndCrankshaft(kClassConstructorFunction); } VisitDeclarations(scope->declarations()); @@ -608,13 +640,26 @@ bool AstNumberingVisitor::Renumber(FunctionLiteral* node) { node->set_ast_properties(&properties_); node->set_dont_optimize_reason(dont_optimize_reason()); node->set_yield_count(yield_count_); + + if (FLAG_trace_opt) { + if (disable_crankshaft_reason_ != kNoReason) { + PrintF("[enforcing Ignition and TurboFan for %s because: %s\n", + node->debug_name()->ToCString().get(), + GetBailoutReason(disable_crankshaft_reason_)); + } + } + return !HasStackOverflow(); } +bool AstNumbering::Renumber( + uintptr_t stack_limit, Zone* zone, FunctionLiteral* function, + Compiler::EagerInnerFunctionLiterals* eager_literals) { + DisallowHeapAllocation no_allocation; + DisallowHandleAllocation no_handles; + DisallowHandleDereference no_deref; -bool AstNumbering::Renumber(Isolate* isolate, Zone* zone, - FunctionLiteral* function) { - AstNumberingVisitor visitor(isolate, zone); + AstNumberingVisitor visitor(stack_limit, zone, eager_literals); 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 73278950cd..bea441d67b 100644 --- a/deps/v8/src/ast/ast-numbering.h +++ b/deps/v8/src/ast/ast-numbering.h @@ -5,6 +5,8 @@ #ifndef V8_AST_AST_NUMBERING_H_ #define V8_AST_AST_NUMBERING_H_ +#include <stdint.h> + namespace v8 { namespace internal { @@ -12,11 +14,20 @@ namespace internal { class FunctionLiteral; class Isolate; class Zone; +template <typename T> +class ThreadedList; +template <typename T> +class ThreadedListZoneEntry; +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. -bool Renumber(Isolate* isolate, Zone* zone, FunctionLiteral* function); +// 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); } // Some details on yield IDs diff --git a/deps/v8/src/ast/ast-traversal-visitor.h b/deps/v8/src/ast/ast-traversal-visitor.h index d93e02ffe0..6d0c386f3b 100644 --- a/deps/v8/src/ast/ast-traversal-visitor.h +++ b/deps/v8/src/ast/ast-traversal-visitor.h @@ -288,7 +288,7 @@ void AstTraversalVisitor<Subclass>::VisitFunctionLiteral( DeclarationScope* scope = expr->scope(); RECURSE_EXPRESSION(VisitDeclarations(scope->declarations())); // A lazily parsed function literal won't have a body. - if (expr->scope()->is_lazily_parsed()) return; + if (expr->scope()->was_lazily_parsed()) return; RECURSE_EXPRESSION(VisitStatements(expr->body())); } @@ -471,6 +471,12 @@ void AstTraversalVisitor<Subclass>::VisitEmptyParentheses( } template <class Subclass> +void AstTraversalVisitor<Subclass>::VisitGetIterator(GetIterator* expr) { + PROCESS_EXPRESSION(expr); + RECURSE_EXPRESSION(Visit(expr->iterable())); +} + +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 49551dd7fa..83879215fc 100644 --- a/deps/v8/src/ast/ast-types.cc +++ b/deps/v8/src/ast/ast-types.cc @@ -7,6 +7,7 @@ #include "src/ast/ast-types.h" #include "src/handles-inl.h" +#include "src/objects-inl.h" #include "src/ostreams.h" namespace v8 { @@ -209,7 +210,6 @@ AstType::bitset AstBitsetType::Lub(i::Map* map) { case JS_CONTEXT_EXTENSION_OBJECT_TYPE: case JS_GENERATOR_OBJECT_TYPE: case JS_MODULE_NAMESPACE_TYPE: - case JS_FIXED_ARRAY_ITERATOR_TYPE: case JS_ARRAY_BUFFER_TYPE: case JS_ARRAY_TYPE: case JS_REGEXP_TYPE: // TODO(rossberg): there should be a RegExp type. @@ -259,6 +259,7 @@ AstType::bitset AstBitsetType::Lub(i::Map* map) { case JS_WEAK_MAP_TYPE: case JS_WEAK_SET_TYPE: + case JS_PROMISE_CAPABILITY_TYPE: case JS_PROMISE_TYPE: case JS_BOUND_FUNCTION_TYPE: DCHECK(!map->is_undetectable()); @@ -304,8 +305,6 @@ AstType::bitset AstBitsetType::Lub(i::Map* map) { case PROMISE_REACTION_JOB_INFO_TYPE: case FUNCTION_TEMPLATE_INFO_TYPE: case OBJECT_TEMPLATE_INFO_TYPE: - case SIGNATURE_INFO_TYPE: - case TYPE_SWITCH_INFO_TYPE: case ALLOCATION_MEMENTO_TYPE: case TYPE_FEEDBACK_INFO_TYPE: case ALIASED_ARGUMENTS_ENTRY_TYPE: @@ -315,8 +314,10 @@ AstType::bitset AstBitsetType::Lub(i::Map* map) { case CELL_TYPE: case WEAK_CELL_TYPE: case PROTOTYPE_INFO_TYPE: + case TUPLE2_TYPE: case TUPLE3_TYPE: case CONTEXT_EXTENSION_TYPE: + case CONSTANT_ELEMENTS_PAIR_TYPE: UNREACHABLE(); return kNone; } diff --git a/deps/v8/src/ast/ast-value-factory.cc b/deps/v8/src/ast/ast-value-factory.cc index ed2976f52a..4add57955f 100644 --- a/deps/v8/src/ast/ast-value-factory.cc +++ b/deps/v8/src/ast/ast-value-factory.cc @@ -28,6 +28,8 @@ #include "src/ast/ast-value-factory.h" #include "src/api.h" +#include "src/char-predicates-inl.h" +#include "src/objects-inl.h" #include "src/objects.h" #include "src/utils.h" @@ -219,9 +221,17 @@ void AstValue::Internalize(Isolate* isolate) { } } - AstRawString* AstValueFactory::GetOneByteStringInternal( Vector<const uint8_t> literal) { + if (literal.length() == 1 && IsInRange(literal[0], 'a', 'z')) { + int key = literal[0] - 'a'; + if (one_character_strings_[key] == nullptr) { + uint32_t hash = StringHasher::HashSequentialString<uint8_t>( + literal.start(), literal.length(), hash_seed_); + one_character_strings_[key] = GetString(hash, true, literal); + } + return one_character_strings_[key]; + } uint32_t hash = StringHasher::HashSequentialString<uint8_t>( literal.start(), literal.length(), hash_seed_); return GetString(hash, true, literal); @@ -260,39 +270,6 @@ const AstConsString* AstValueFactory::NewConsString( return new_string; } -const AstRawString* AstValueFactory::ConcatStrings(const AstRawString* left, - const AstRawString* right) { - int left_length = left->length(); - int right_length = right->length(); - const unsigned char* left_data = left->raw_data(); - const unsigned char* right_data = right->raw_data(); - if (left->is_one_byte() && right->is_one_byte()) { - uint8_t* buffer = zone_->NewArray<uint8_t>(left_length + right_length); - memcpy(buffer, left_data, left_length); - memcpy(buffer + left_length, right_data, right_length); - Vector<const uint8_t> literal(buffer, left_length + right_length); - return GetOneByteStringInternal(literal); - } else { - uint16_t* buffer = zone_->NewArray<uint16_t>(left_length + right_length); - if (left->is_one_byte()) { - for (int i = 0; i < left_length; ++i) { - buffer[i] = left_data[i]; - } - } else { - memcpy(buffer, left_data, 2 * left_length); - } - if (right->is_one_byte()) { - for (int i = 0; i < right_length; ++i) { - buffer[i + left_length] = right_data[i]; - } - } else { - memcpy(buffer + left_length, right_data, 2 * right_length); - } - Vector<const uint16_t> literal(buffer, left_length + right_length); - return GetTwoByteStringInternal(literal); - } -} - void AstValueFactory::Internalize(Isolate* isolate) { // Strings need to be internalized before values, because values refer to // strings. diff --git a/deps/v8/src/ast/ast-value-factory.h b/deps/v8/src/ast/ast-value-factory.h index 4ce480fe57..fd9ed71167 100644 --- a/deps/v8/src/ast/ast-value-factory.h +++ b/deps/v8/src/ast/ast-value-factory.h @@ -30,6 +30,7 @@ #include "src/api.h" #include "src/base/hashmap.h" +#include "src/conversions.h" #include "src/globals.h" #include "src/utils.h" @@ -110,8 +111,9 @@ class AstRawString final : public AstString { } private: - friend class AstValueFactory; friend class AstRawStringInternalizationKey; + friend class AstStringConstants; + friend class AstValueFactory; AstRawString(bool is_one_byte, const Vector<const byte>& literal_bytes, uint32_t hash) @@ -158,10 +160,7 @@ class AstValue : public ZoneObject { return type_ == STRING; } - bool IsNumber() const { - return type_ == NUMBER || type_ == NUMBER_WITH_DOT || type_ == SMI || - type_ == SMI_WITH_DOT; - } + bool IsNumber() const { return IsSmi() || IsHeapNumber(); } bool ContainsDot() const { return type_ == NUMBER_WITH_DOT || type_ == SMI_WITH_DOT; @@ -173,19 +172,30 @@ class AstValue : public ZoneObject { } double AsNumber() const { - if (type_ == NUMBER || type_ == NUMBER_WITH_DOT) - return number_; - if (type_ == SMI || type_ == SMI_WITH_DOT) - return smi_; + if (IsHeapNumber()) return number_; + if (IsSmi()) return smi_; UNREACHABLE(); return 0; } Smi* AsSmi() const { - CHECK(type_ == SMI || type_ == SMI_WITH_DOT); + CHECK(IsSmi()); return Smi::FromInt(smi_); } + bool ToUint32(uint32_t* value) const { + if (IsSmi()) { + int num = smi_; + if (num < 0) return false; + *value = static_cast<uint32_t>(num); + return true; + } + if (IsHeapNumber()) { + return DoubleToUint32IfEqualToSelf(number_, value); + } + return false; + } + bool EqualsString(const AstRawString* string) const { return type_ == STRING && string_ == string; } @@ -195,6 +205,9 @@ 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 IsFalse() const { return type_ == BOOLEAN && !bool_; } bool IsTrue() const { return type_ == BOOLEAN && bool_; } bool IsUndefined() const { return type_ == UNDEFINED; } @@ -280,7 +293,6 @@ class AstValue : public ZoneObject { }; }; - // For generating constants. #define STRING_CONSTANTS(F) \ F(anonymous_function, "(anonymous function)") \ @@ -291,7 +303,6 @@ class AstValue : public ZoneObject { F(default, "default") \ F(done, "done") \ F(dot, ".") \ - F(dot_class_field_init, ".class-field-init") \ F(dot_for, ".for") \ F(dot_generator_object, ".generator_object") \ F(dot_iterator, ".iterator") \ @@ -304,6 +315,7 @@ class AstValue : public ZoneObject { F(get_space, "get ") \ F(length, "length") \ F(let, "let") \ + F(name, "name") \ F(native, "native") \ F(new_target, ".new.target") \ F(next, "next") \ @@ -320,6 +332,45 @@ class AstValue : public ZoneObject { F(use_strict, "use strict") \ F(value, "value") +class AstStringConstants final { + public: + AstStringConstants(Isolate* isolate, uint32_t hash_seed) + : zone_(isolate->allocator(), ZONE_NAME), hash_seed_(hash_seed) { + DCHECK(ThreadId::Current().Equals(isolate->thread_id())); +#define F(name, str) \ + { \ + const char* data = str; \ + Vector<const uint8_t> literal(reinterpret_cast<const uint8_t*>(data), \ + static_cast<int>(strlen(data))); \ + uint32_t hash = StringHasher::HashSequentialString<uint8_t>( \ + literal.start(), literal.length(), hash_seed_); \ + name##_string_ = new (&zone_) AstRawString(true, literal, hash); \ + /* The Handle returned by the factory is located on the roots */ \ + /* array, not on the temporary HandleScope, so this is safe. */ \ + name##_string_->set_string(isolate->factory()->name##_string()); \ + } + STRING_CONSTANTS(F) +#undef F + } + +#define F(name, str) \ + AstRawString* name##_string() { return name##_string_; } + STRING_CONSTANTS(F) +#undef F + + uint32_t hash_seed() const { return hash_seed_; } + + private: + Zone zone_; + uint32_t hash_seed_; + +#define F(name, str) AstRawString* name##_string_; + STRING_CONSTANTS(F) +#undef F + + DISALLOW_COPY_AND_ASSIGN(AstStringConstants); +}; + #define OTHER_CONSTANTS(F) \ F(true_value) \ F(false_value) \ @@ -329,21 +380,24 @@ class AstValue : public ZoneObject { class AstValueFactory { public: - AstValueFactory(Zone* zone, uint32_t hash_seed) + AstValueFactory(Zone* zone, AstStringConstants* string_constants, + uint32_t hash_seed) : string_table_(AstRawStringCompare), values_(nullptr), - smis_(), strings_(nullptr), strings_end_(&strings_), + string_constants_(string_constants), zone_(zone), hash_seed_(hash_seed) { -#define F(name, str) name##_string_ = NULL; - STRING_CONSTANTS(F) -#undef F -#define F(name) name##_ = NULL; +#define F(name) name##_ = nullptr; OTHER_CONSTANTS(F) #undef F + DCHECK_EQ(hash_seed, string_constants->hash_seed()); std::fill(smis_, smis_ + arraysize(smis_), nullptr); + std::fill(one_character_strings_, + one_character_strings_ + arraysize(one_character_strings_), + nullptr); + InitializeStringConstants(); } Zone* zone() const { return zone_; } @@ -361,20 +415,12 @@ class AstValueFactory { const AstRawString* GetString(Handle<String> literal); const AstConsString* NewConsString(const AstString* left, const AstString* right); - const AstRawString* ConcatStrings(const AstRawString* left, - const AstRawString* right); void Internalize(Isolate* isolate); -#define F(name, str) \ - const AstRawString* name##_string() { \ - if (name##_string_ == NULL) { \ - const char* data = str; \ - name##_string_ = GetOneByteString( \ - Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), \ - static_cast<int>(strlen(data)))); \ - } \ - return name##_string_; \ +#define F(name, str) \ + const AstRawString* name##_string() { \ + return string_constants_->name##_string(); \ } STRING_CONSTANTS(F) #undef F @@ -415,6 +461,17 @@ class AstValueFactory { AstRawString* GetString(uint32_t hash, bool is_one_byte, Vector<const byte> literal_bytes); + void InitializeStringConstants() { +#define F(name, str) \ + AstRawString* raw_string_##name = string_constants_->name##_string(); \ + base::HashMap::Entry* entry_##name = string_table_.LookupOrInsert( \ + raw_string_##name, raw_string_##name->hash()); \ + DCHECK(entry_##name->value == nullptr); \ + entry_##name->value = reinterpret_cast<void*>(1); + STRING_CONSTANTS(F) +#undef F + } + static bool AstRawStringCompare(void* a, void* b); // All strings are copied here, one after another (no NULLs inbetween). @@ -423,19 +480,23 @@ class AstValueFactory { // they can be internalized later). AstValue* values_; - AstValue* smis_[kMaxCachedSmi + 1]; // We need to keep track of strings_ in order since cons strings require their // members to be internalized first. AstString* strings_; AstString** strings_end_; + + // Holds constant string values which are shared across the isolate. + AstStringConstants* string_constants_; + + // Caches for faster access: small numbers, one character lowercase strings + // (for minified code). + AstValue* smis_[kMaxCachedSmi + 1]; + AstRawString* one_character_strings_[26]; + Zone* zone_; uint32_t hash_seed_; -#define F(name, str) const AstRawString* name##_string_; - STRING_CONSTANTS(F) -#undef F - #define F(name) AstValue* name##_; OTHER_CONSTANTS(F) #undef F diff --git a/deps/v8/src/ast/ast.cc b/deps/v8/src/ast/ast.cc index fc8bd8a5bd..c63f90ecf1 100644 --- a/deps/v8/src/ast/ast.cc +++ b/deps/v8/src/ast/ast.cc @@ -10,6 +10,7 @@ #include "src/ast/prettyprinter.h" #include "src/ast/scopes.h" #include "src/base/hashmap.h" +#include "src/builtins/builtins-constructor.h" #include "src/builtins/builtins.h" #include "src/code-stubs.h" #include "src/contexts.h" @@ -28,6 +29,8 @@ namespace internal { #ifdef DEBUG +void AstNode::Print() { Print(Isolate::Current()); } + void AstNode::Print(Isolate* isolate) { AstPrinter::PrintOut(isolate, this); } @@ -70,6 +73,10 @@ bool Expression::IsSmiLiteral() const { return IsLiteral() && AsLiteral()->raw_value()->IsSmi(); } +bool Expression::IsNumberLiteral() const { + return IsLiteral() && AsLiteral()->raw_value()->IsNumber(); +} + bool Expression::IsStringLiteral() const { return IsLiteral() && AsLiteral()->raw_value()->IsString(); } @@ -197,9 +204,7 @@ void VariableProxy::BindTo(Variable* var) { var->set_is_used(); } - -void VariableProxy::AssignFeedbackVectorSlots(Isolate* isolate, - FeedbackVectorSpec* spec, +void VariableProxy::AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) { if (UsesVariableFeedbackSlot()) { // VariableProxies that point to the same Variable within a function can @@ -211,7 +216,7 @@ void VariableProxy::AssignFeedbackVectorSlots(Isolate* isolate, static_cast<int>(reinterpret_cast<intptr_t>(entry->value))); return; } - variable_feedback_slot_ = spec->AddLoadGlobalICSlot(var()->name()); + variable_feedback_slot_ = spec->AddLoadGlobalICSlot(); cache->Put(var(), variable_feedback_slot_); } else { variable_feedback_slot_ = spec->AddLoadICSlot(); @@ -235,8 +240,7 @@ static void AssignVectorSlots(Expression* expr, FeedbackVectorSpec* spec, } } -void ForInStatement::AssignFeedbackVectorSlots(Isolate* isolate, - FeedbackVectorSpec* spec, +void ForInStatement::AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) { AssignVectorSlots(each(), spec, &each_slot_); for_in_feedback_slot_ = spec->AddGeneralSlot(); @@ -253,15 +257,12 @@ Assignment::Assignment(Token::Value op, Expression* target, Expression* value, StoreModeField::encode(STANDARD_STORE) | TokenField::encode(op); } -void Assignment::AssignFeedbackVectorSlots(Isolate* isolate, - FeedbackVectorSpec* spec, +void Assignment::AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) { AssignVectorSlots(target(), spec, &slot_); } - -void CountOperation::AssignFeedbackVectorSlots(Isolate* isolate, - FeedbackVectorSpec* spec, +void CountOperation::AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) { AssignVectorSlots(expression(), spec, &slot_); // Assign a slot to collect feedback about binary operations. Used only in @@ -346,6 +347,16 @@ ObjectLiteralProperty::ObjectLiteralProperty(AstValueFactory* ast_value_factory, } } +FeedbackVectorSlot LiteralProperty::GetStoreDataPropertySlot() const { + int offset = FunctionLiteral::NeedsHomeObject(value_) ? 1 : 0; + return GetSlot(offset); +} + +void LiteralProperty::SetStoreDataPropertySlot(FeedbackVectorSlot slot) { + int offset = FunctionLiteral::NeedsHomeObject(value_) ? 1 : 0; + return SetSlot(slot, offset); +} + bool LiteralProperty::NeedsSetFunctionName() const { return is_computed_name_ && (value_->IsAnonymousFunctionDefinition() || @@ -360,12 +371,14 @@ ClassLiteralProperty::ClassLiteralProperty(Expression* key, Expression* value, kind_(kind), is_static_(is_static) {} -void ClassLiteral::AssignFeedbackVectorSlots(Isolate* isolate, - FeedbackVectorSpec* spec, +void ClassLiteral::AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) { // This logic that computes the number of slots needed for vector store - // ICs must mirror FullCodeGenerator::VisitClassLiteral. - prototype_slot_ = spec->AddLoadICSlot(); + // ICs must mirror BytecodeGenerator::VisitClassLiteral. + if (FunctionLiteral::NeedsHomeObject(constructor())) { + home_object_slot_ = spec->AddStoreICSlot(); + } + if (NeedsProxySlot()) { proxy_slot_ = spec->AddStoreICSlot(); } @@ -376,6 +389,8 @@ void ClassLiteral::AssignFeedbackVectorSlots(Isolate* isolate, if (FunctionLiteral::NeedsHomeObject(value)) { property->SetSlot(spec->AddStoreICSlot()); } + property->SetStoreDataPropertySlot( + spec->AddStoreDataPropertyInLiteralICSlot()); } } @@ -392,8 +407,7 @@ void ObjectLiteral::Property::set_emit_store(bool emit_store) { bool ObjectLiteral::Property::emit_store() const { return emit_store_; } -void ObjectLiteral::AssignFeedbackVectorSlots(Isolate* isolate, - FeedbackVectorSpec* spec, +void ObjectLiteral::AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) { // This logic that computes the number of slots needed for vector store // ics must mirror FullCodeGenerator::VisitObjectLiteral. @@ -406,6 +420,7 @@ void ObjectLiteral::AssignFeedbackVectorSlots(Isolate* isolate, Literal* key = property->key()->AsLiteral(); Expression* value = property->value(); switch (property->kind()) { + case ObjectLiteral::Property::SPREAD: case ObjectLiteral::Property::CONSTANT: UNREACHABLE(); case ObjectLiteral::Property::MATERIALIZED_LITERAL: @@ -413,7 +428,7 @@ void ObjectLiteral::AssignFeedbackVectorSlots(Isolate* isolate, case ObjectLiteral::Property::COMPUTED: // It is safe to use [[Put]] here because the boilerplate already // contains computed properties with an uninitialized value. - if (key->value()->IsInternalizedString()) { + if (key->IsStringLiteral()) { if (property->emit_store()) { property->SetSlot(spec->AddStoreICSlot()); if (FunctionLiteral::NeedsHomeObject(value)) { @@ -450,6 +465,8 @@ void ObjectLiteral::AssignFeedbackVectorSlots(Isolate* isolate, property->SetSlot(spec->AddStoreICSlot()); } } + property->SetStoreDataPropertySlot( + spec->AddStoreDataPropertyInLiteralICSlot()); } } @@ -491,13 +508,8 @@ bool ObjectLiteral::IsBoilerplateProperty(ObjectLiteral::Property* property) { property->kind() != ObjectLiteral::Property::PROTOTYPE; } - -void ObjectLiteral::BuildConstantProperties(Isolate* isolate) { - if (!constant_properties_.is_null()) return; - - // Allocate a fixed array to hold all the constant properties. - Handle<FixedArray> constant_properties = isolate->factory()->NewFixedArray( - boilerplate_properties_ * 2, TENURED); +void ObjectLiteral::InitDepthAndFlags() { + if (depth_ > 0) return; int position = 0; // Accumulate the value in local variables and store it at the end. @@ -521,50 +533,43 @@ void ObjectLiteral::BuildConstantProperties(Isolate* isolate) { MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral(); if (m_literal != NULL) { - m_literal->BuildConstants(isolate); + m_literal->InitDepthAndFlags(); if (m_literal->depth() >= depth_acc) depth_acc = m_literal->depth() + 1; } - // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined - // value for COMPUTED properties, the real value is filled in at - // runtime. The enumeration order is maintained. - Handle<Object> key = property->key()->AsLiteral()->value(); - Handle<Object> value = GetBoilerplateValue(property->value(), isolate); + const AstValue* key = property->key()->AsLiteral()->raw_value(); + Expression* value = property->value(); + + bool is_compile_time_value = CompileTimeValue::IsCompileTimeValue(value); // Ensure objects that may, at any point in time, contain fields with double // representation are always treated as nested objects. This is true for - // computed fields (value is undefined), and smi and double literals - // (value->IsNumber()). + // computed fields, and smi and double literals. // TODO(verwaest): Remove once we can store them inline. if (FLAG_track_double_fields && - (value->IsNumber() || value->IsUninitialized(isolate))) { + (value->IsNumberLiteral() || !is_compile_time_value)) { bit_field_ = MayStoreDoublesField::update(bit_field_, true); } - is_simple = is_simple && !value->IsUninitialized(isolate); + is_simple = is_simple && is_compile_time_value; // Keep track of the number of elements in the object literal and // the largest element index. If the largest element index is // much larger than the number of elements, creating an object // literal with fast elements will be a waste of space. uint32_t element_index = 0; - if (key->IsString() && String::cast(*key)->AsArrayIndex(&element_index)) { + if (key->IsString() && key->AsString()->AsArrayIndex(&element_index)) { max_element_index = Max(element_index, max_element_index); elements++; - key = isolate->factory()->NewNumberFromUint(element_index); - } else if (key->ToArrayIndex(&element_index)) { + } else if (key->ToUint32(&element_index) && element_index != kMaxUInt32) { max_element_index = Max(element_index, max_element_index); elements++; - } else if (key->IsNumber()) { - key = isolate->factory()->NumberToString(key); } - // Add name, value pair to the fixed array. - constant_properties->set(position++, *key); - constant_properties->set(position++, *value); + // Increment the position for the key and the value. + position += 2; } - constant_properties_ = constant_properties; bit_field_ = FastElementsField::update( bit_field_, (max_element_index <= 32) || ((2 * elements) >= max_element_index)); @@ -574,6 +579,91 @@ void ObjectLiteral::BuildConstantProperties(Isolate* isolate) { set_depth(depth_acc); } +void ObjectLiteral::BuildConstantProperties(Isolate* isolate) { + if (!constant_properties_.is_null()) return; + + // Allocate a fixed array to hold all the constant properties. + Handle<FixedArray> constant_properties = + isolate->factory()->NewFixedArray(boilerplate_properties_ * 2, TENURED); + + int position = 0; + for (int i = 0; i < properties()->length(); i++) { + ObjectLiteral::Property* property = properties()->at(i); + if (!IsBoilerplateProperty(property)) { + continue; + } + + if (static_cast<uint32_t>(position) == boilerplate_properties_ * 2) { + DCHECK(property->is_computed_name()); + break; + } + DCHECK(!property->is_computed_name()); + + MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral(); + if (m_literal != NULL) { + m_literal->BuildConstants(isolate); + } + + // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined + // value for COMPUTED properties, the real value is filled in at + // runtime. The enumeration order is maintained. + Handle<Object> key = property->key()->AsLiteral()->value(); + Handle<Object> value = GetBoilerplateValue(property->value(), isolate); + + uint32_t element_index = 0; + if (key->IsString() && String::cast(*key)->AsArrayIndex(&element_index)) { + key = isolate->factory()->NewNumberFromUint(element_index); + } else if (key->IsNumber() && !key->ToArrayIndex(&element_index)) { + key = isolate->factory()->NumberToString(key); + } + + // Add name, value pair to the fixed array. + constant_properties->set(position++, *key); + constant_properties->set(position++, *value); + } + + constant_properties_ = constant_properties; +} + +bool ObjectLiteral::IsFastCloningSupported() const { + // The FastCloneShallowObject builtin doesn't copy elements, and object + // 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; +} + +void ArrayLiteral::InitDepthAndFlags() { + DCHECK_LT(first_spread_index_, 0); + + if (depth_ > 0) return; + + int constants_length = values()->length(); + + // Fill in the literals. + bool is_simple = true; + int depth_acc = 1; + int array_index = 0; + for (; array_index < constants_length; array_index++) { + Expression* element = values()->at(array_index); + DCHECK(!element->IsSpread()); + MaterializedLiteral* m_literal = element->AsMaterializedLiteral(); + if (m_literal != NULL) { + m_literal->InitDepthAndFlags(); + if (m_literal->depth() + 1 > depth_acc) { + depth_acc = m_literal->depth() + 1; + } + } + + if (!CompileTimeValue::IsCompileTimeValue(element)) { + is_simple = false; + } + } + + set_is_simple(is_simple); + set_depth(depth_acc); +} void ArrayLiteral::BuildConstantElements(Isolate* isolate) { DCHECK_LT(first_spread_index_, 0); @@ -586,8 +676,6 @@ void ArrayLiteral::BuildConstantElements(Isolate* isolate) { isolate->factory()->NewFixedArrayWithHoles(constants_length); // Fill in the literals. - bool is_simple = true; - int depth_acc = 1; bool is_holey = false; int array_index = 0; for (; array_index < constants_length; array_index++) { @@ -596,9 +684,6 @@ void ArrayLiteral::BuildConstantElements(Isolate* isolate) { MaterializedLiteral* m_literal = element->AsMaterializedLiteral(); if (m_literal != NULL) { m_literal->BuildConstants(isolate); - if (m_literal->depth() + 1 > depth_acc) { - depth_acc = m_literal->depth() + 1; - } } // New handle scope here, needs to be after BuildContants(). @@ -611,7 +696,6 @@ void ArrayLiteral::BuildConstantElements(Isolate* isolate) { if (boilerplate_value->IsUninitialized(isolate)) { boilerplate_value = handle(Smi::kZero, isolate); - is_simple = false; } kind = GetMoreGeneralElementsKind(kind, @@ -623,7 +707,7 @@ void ArrayLiteral::BuildConstantElements(Isolate* isolate) { // Simple and shallow arrays can be lazily copied, we transform the // elements array to a copy-on-write array. - if (is_simple && depth_acc == 1 && array_index > 0 && + if (is_simple() && depth() == 1 && array_index > 0 && IsFastSmiOrObjectElementsKind(kind)) { fixed_array->set_map(isolate->heap()->fixed_cow_array_map()); } @@ -637,20 +721,20 @@ void ArrayLiteral::BuildConstantElements(Isolate* isolate) { accessor->CopyElements(fixed_array, from_kind, elements, constants_length); } - // Remember both the literal's constant values as well as the ElementsKind - // in a 2-element FixedArray. - Handle<FixedArray> literals = isolate->factory()->NewFixedArray(2, TENURED); - literals->set(0, Smi::FromInt(kind)); - literals->set(1, *elements); + // Remember both the literal's constant values as well as the ElementsKind. + Handle<ConstantElementsPair> literals = + isolate->factory()->NewConstantElementsPair(kind, elements); constant_elements_ = literals; - set_is_simple(is_simple); - set_depth(depth_acc); } +bool ArrayLiteral::IsFastCloningSupported() const { + return depth() <= 1 && + values()->length() <= + ConstructorBuiltinsAssembler::kMaximumClonedShallowArrayElements; +} -void ArrayLiteral::AssignFeedbackVectorSlots(Isolate* isolate, - FeedbackVectorSpec* spec, +void ArrayLiteral::AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) { // This logic that computes the number of slots needed for vector store // ics must mirror FullCodeGenerator::VisitArrayLiteral. @@ -678,6 +762,16 @@ Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression, return isolate->factory()->uninitialized_value(); } +void MaterializedLiteral::InitDepthAndFlags() { + if (IsArrayLiteral()) { + return AsArrayLiteral()->InitDepthAndFlags(); + } + if (IsObjectLiteral()) { + return AsObjectLiteral()->InitDepthAndFlags(); + } + DCHECK(IsRegExpLiteral()); + DCHECK_LE(1, depth()); // Depth should be initialized. +} void MaterializedLiteral::BuildConstants(Isolate* isolate) { if (IsArrayLiteral()) { @@ -687,7 +781,6 @@ void MaterializedLiteral::BuildConstants(Isolate* isolate) { return AsObjectLiteral()->BuildConstantProperties(isolate); } DCHECK(IsRegExpLiteral()); - DCHECK(depth() >= 1); // Depth should be initialized. } @@ -711,8 +804,7 @@ void BinaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { } void BinaryOperation::AssignFeedbackVectorSlots( - Isolate* isolate, FeedbackVectorSpec* spec, - FeedbackVectorSlotCache* cache) { + FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) { // Feedback vector slot is only used by interpreter for binary operations. // Full-codegen uses AstId to record type feedback. switch (op()) { @@ -733,8 +825,7 @@ static bool IsTypeof(Expression* expr) { } void CompareOperation::AssignFeedbackVectorSlots( - Isolate* isolate, FeedbackVectorSpec* spec, - FeedbackVectorSlotCache* cache_) { + FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache_) { // Feedback vector slot is only used by interpreter for binary operations. // Full-codegen uses AstId to record type feedback. switch (op()) { @@ -892,7 +983,7 @@ bool Expression::IsMonomorphic() const { } } -void Call::AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, +void Call::AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) { ic_slot_ = spec->AddCallICSlot(); } @@ -931,8 +1022,7 @@ CaseClause::CaseClause(Expression* label, ZoneList<Statement*>* statements, statements_(statements), compare_type_(AstType::None()) {} -void CaseClause::AssignFeedbackVectorSlots(Isolate* isolate, - FeedbackVectorSpec* spec, +void CaseClause::AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) { type_feedback_slot_ = spec->AddInterpreterCompareICSlot(); } diff --git a/deps/v8/src/ast/ast.h b/deps/v8/src/ast/ast.h index 99e0672a4c..af561e0a3f 100644 --- a/deps/v8/src/ast/ast.h +++ b/deps/v8/src/ast/ast.h @@ -5,6 +5,7 @@ #ifndef V8_AST_AST_H_ #define V8_AST_AST_H_ +#include "src/assembler.h" #include "src/ast/ast-types.h" #include "src/ast/ast-value-factory.h" #include "src/ast/modules.h" @@ -102,6 +103,7 @@ namespace internal { V(SuperCallReference) \ V(CaseClause) \ V(EmptyParentheses) \ + V(GetIterator) \ V(DoExpression) \ V(RewritableExpression) @@ -154,7 +156,7 @@ class AstProperties final BASE_EMBEDDED { enum Flag { kNoFlags = 0, kDontSelfOptimize = 1 << 0, - kDontCrankshaft = 1 << 1 + kMustUseIgnitionTurbo = 1 << 1 }; typedef base::Flags<Flag> Flags; @@ -190,6 +192,7 @@ class AstNode: public ZoneObject { int position() const { return position_; } #ifdef DEBUG + void Print(); void Print(Isolate* isolate); #endif // DEBUG @@ -317,6 +320,9 @@ class Expression : public AstNode { // True iff the expression is a literal represented as a smi. bool IsSmiLiteral() const; + // True iff the expression is a literal represented as a number. + bool IsNumberLiteral() const; + // True iff the expression is a string literal. bool IsStringLiteral() const; @@ -466,9 +472,6 @@ class Block final : public BreakableStatement { class IgnoreCompletionField : public BitField<bool, BreakableStatement::kNextBitFieldIndex, 1> {}; - - protected: - static const uint8_t kNextBitFieldIndex = IgnoreCompletionField::kNext; }; @@ -484,9 +487,6 @@ class DoExpression final : public Expression { } bool IsAnonymousFunctionDefinition() const; - protected: - static const uint8_t kNextBitFieldIndex = Expression::kNextBitFieldIndex; - private: friend class AstNodeFactory; @@ -518,8 +518,6 @@ class Declaration : public AstNode { Declaration(VariableProxy* proxy, Scope* scope, int pos, NodeType type) : AstNode(pos, type), proxy_(proxy), scope_(scope), next_(nullptr) {} - static const uint8_t kNextBitFieldIndex = AstNode::kNextBitFieldIndex; - private: VariableProxy* proxy_; // Nested scope from which the declaration originated. @@ -734,7 +732,7 @@ class ForInStatement final : public ForEachStatement { void set_subject(Expression* e) { subject_ = e; } // Type feedback information. - void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, + void AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache); FeedbackVectorSlot EachFeedbackSlot() const { return each_slot_; } FeedbackVectorSlot ForInFeedbackSlot() { @@ -778,9 +776,6 @@ class ForInStatement final : public ForEachStatement { class ForInTypeField : public BitField<ForInType, ForEachStatement::kNextBitFieldIndex, 1> {}; - - protected: - static const uint8_t kNextBitFieldIndex = ForInTypeField::kNext; }; @@ -826,12 +821,6 @@ class ForOfStatement final : public ForEachStatement { void set_result_done(Expression* e) { result_done_ = e; } void set_assign_each(Expression* e) { assign_each_ = e; } - BailoutId ContinueId() const { return EntryId(); } - BailoutId StackCheckId() const { return BackEdgeId(); } - - static int num_ids() { return parent_num_ids() + 1; } - BailoutId BackEdgeId() const { return BailoutId(local_id(0)); } - private: friend class AstNodeFactory; @@ -842,8 +831,6 @@ class ForOfStatement final : public ForEachStatement { next_result_(NULL), result_done_(NULL), assign_each_(NULL) {} - static int parent_num_ids() { return ForEachStatement::num_ids(); } - int local_id(int n) const { return base_id() + parent_num_ids() + n; } Variable* iterator_; Expression* assign_iterator_; @@ -930,30 +917,16 @@ class WithStatement final : public Statement { Statement* statement() const { return statement_; } void set_statement(Statement* s) { statement_ = s; } - void set_base_id(int id) { base_id_ = id; } - static int num_ids() { return parent_num_ids() + 2; } - BailoutId ToObjectId() const { return BailoutId(local_id(0)); } - BailoutId EntryId() const { return BailoutId(local_id(1)); } - private: friend class AstNodeFactory; WithStatement(Scope* scope, Expression* expression, Statement* statement, int pos) : Statement(pos, kWithStatement), - base_id_(BailoutId::None().ToInt()), scope_(scope), expression_(expression), statement_(statement) {} - static int parent_num_ids() { return 0; } - int base_id() const { - DCHECK(!BailoutId(base_id_).IsNone()); - return base_id_; - } - int local_id(int n) const { return base_id() + parent_num_ids() + n; } - - int base_id_; Scope* scope_; Expression* expression_; Statement* statement_; @@ -981,7 +954,7 @@ class CaseClause final : public Expression { // CaseClause will have both a slot in the feedback vector and the // TypeFeedbackId to record the type information. TypeFeedbackId is used by // full codegen and the feedback vector slot is used by interpreter. - void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, + void AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache); FeedbackVectorSlot CompareOperationFeedbackSlot() { @@ -1212,22 +1185,15 @@ class SloppyBlockFunctionStatement final : public Statement { public: Statement* statement() const { return statement_; } void set_statement(Statement* statement) { statement_ = statement; } - Scope* scope() const { return scope_; } - SloppyBlockFunctionStatement* next() { return next_; } - void set_next(SloppyBlockFunctionStatement* next) { next_ = next; } private: friend class AstNodeFactory; - SloppyBlockFunctionStatement(Statement* statement, Scope* scope) + explicit SloppyBlockFunctionStatement(Statement* statement) : Statement(kNoSourcePosition, kSloppyBlockFunctionStatement), - statement_(statement), - scope_(scope), - next_(nullptr) {} + statement_(statement) {} Statement* statement_; - Scope* const scope_; - SloppyBlockFunctionStatement* next_; }; @@ -1317,6 +1283,9 @@ class MaterializedLiteral : public Expression { depth_ = depth; } + // Populate the depth field and any flags the literal has. + void InitDepthAndFlags(); + // Populate the constant properties/elements fixed array. void BuildConstants(Isolate* isolate); friend class ArrayLiteral; @@ -1347,11 +1316,15 @@ class LiteralProperty : public ZoneObject { return slots_[offset]; } + FeedbackVectorSlot GetStoreDataPropertySlot() const; + void SetSlot(FeedbackVectorSlot slot, int offset = 0) { DCHECK_LT(offset, static_cast<int>(arraysize(slots_))); slots_[offset] = slot; } + void SetStoreDataPropertySlot(FeedbackVectorSlot slot); + bool NeedsSetFunctionName() const; protected: @@ -1374,8 +1347,9 @@ class ObjectLiteralProperty final : public LiteralProperty { COMPUTED, // Property with computed value (execution time). MATERIALIZED_LITERAL, // Property value is a materialized literal. GETTER, - SETTER, // Property is an accessor function. - PROTOTYPE // Property is __proto__. + SETTER, // Property is an accessor function. + PROTOTYPE, // Property is __proto__. + SPREAD }; Kind kind() const { return kind_; } @@ -1412,6 +1386,7 @@ class ObjectLiteral final : public MaterializedLiteral { typedef ObjectLiteralProperty Property; Handle<FixedArray> constant_properties() const { + DCHECK(!constant_properties_.is_null()); return constant_properties_; } int properties_count() const { return boilerplate_properties_; } @@ -1428,6 +1403,17 @@ class ObjectLiteral final : public MaterializedLiteral { // Decide if a property should be in the object boilerplate. static bool IsBoilerplateProperty(Property* property); + // Populate the depth field and flags. + void InitDepthAndFlags(); + + // Get the constant properties fixed array, populating it if necessary. + Handle<FixedArray> GetOrBuildConstantProperties(Isolate* isolate) { + if (constant_properties_.is_null()) { + BuildConstantProperties(isolate); + } + return constant_properties(); + } + // Populate the constant properties fixed array. void BuildConstantProperties(Isolate* isolate); @@ -1436,6 +1422,9 @@ class ObjectLiteral final : public MaterializedLiteral { // marked expressions, no store code is emitted. void CalculateEmitStore(Zone* zone); + // Determines whether the {FastCloneShallowObject} builtin can be used. + bool IsFastCloningSupported() const; + // Assemble bitfield of flags for the CreateObjectLiteral helper. int ComputeFlags(bool disable_mementos = false) const { int flags = fast_elements() ? kFastElements : kNoFlags; @@ -1465,22 +1454,15 @@ class ObjectLiteral final : public MaterializedLiteral { BailoutId CreateLiteralId() const { return BailoutId(local_id(0)); } // Return an AST id for a property that is used in simulate instructions. - BailoutId GetIdForPropertyName(int i) { - return BailoutId(local_id(2 * i + 1)); - } - BailoutId GetIdForPropertySet(int i) { - return BailoutId(local_id(2 * i + 2)); - } + BailoutId GetIdForPropertySet(int i) { return BailoutId(local_id(i + 1)); } // Unlike other AST nodes, this number of bailout IDs allocated for an // ObjectLiteral can vary, so num_ids() is not a static method. - int num_ids() const { - return parent_num_ids() + 1 + 2 * properties()->length(); - } + int num_ids() const { return parent_num_ids() + 1 + properties()->length(); } // Object literals need one feedback slot for each non-trivial value, as well // as some slots for home objects. - void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, + void AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache); private: @@ -1500,7 +1482,6 @@ class ObjectLiteral final : public MaterializedLiteral { int local_id(int n) const { return base_id() + parent_num_ids() + n; } uint32_t boilerplate_properties_; - FeedbackVectorSlot slot_; Handle<FixedArray> constant_properties_; ZoneList<Property*>* properties_; @@ -1510,9 +1491,6 @@ class ObjectLiteral final : public MaterializedLiteral { }; class MayStoreDoublesField : public BitField<bool, HasElementsField::kNext, 1> {}; - - protected: - static const uint8_t kNextBitFieldIndex = MayStoreDoublesField::kNext; }; @@ -1565,11 +1543,11 @@ class RegExpLiteral final : public MaterializedLiteral { // for minimizing the work when constructing it at runtime. class ArrayLiteral final : public MaterializedLiteral { public: - Handle<FixedArray> constant_elements() const { return constant_elements_; } + Handle<ConstantElementsPair> constant_elements() const { + return constant_elements_; + } ElementsKind constant_elements_kind() const { - DCHECK_EQ(2, constant_elements_->length()); - return static_cast<ElementsKind>( - Smi::cast(constant_elements_->get(0))->value()); + return static_cast<ElementsKind>(constant_elements()->elements_kind()); } ZoneList<Expression*>* values() const { return values_; } @@ -1583,9 +1561,23 @@ class ArrayLiteral final : public MaterializedLiteral { // ArrayLiteral can vary, so num_ids() is not a static method. int num_ids() const { return parent_num_ids() + 1 + values()->length(); } + // Populate the depth field and flags. + void InitDepthAndFlags(); + + // Get the constant elements fixed array, populating it if necessary. + Handle<ConstantElementsPair> GetOrBuildConstantElements(Isolate* isolate) { + if (constant_elements_.is_null()) { + BuildConstantElements(isolate); + } + return constant_elements(); + } + // Populate the constant elements fixed array. void BuildConstantElements(Isolate* isolate); + // Determines whether the {FastCloneShallowArray} builtin can be used. + bool IsFastCloningSupported() const; + // Assemble bitfield of flags for the CreateArrayLiteral helper. int ComputeFlags(bool disable_mementos = false) const { int flags = depth() == 1 ? kShallowElements : kNoFlags; @@ -1614,7 +1606,7 @@ class ArrayLiteral final : public MaterializedLiteral { kDisableMementos = 1 << 1 }; - void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, + void AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache); FeedbackVectorSlot LiteralFeedbackSlot() const { return literal_slot_; } @@ -1632,7 +1624,7 @@ class ArrayLiteral final : public MaterializedLiteral { int first_spread_index_; FeedbackVectorSlot literal_slot_; - Handle<FixedArray> constant_elements_; + Handle<ConstantElementsPair> constant_elements_; ZoneList<Expression*>* values_; }; @@ -1663,6 +1655,9 @@ class VariableProxy final : public Expression { bool is_assigned() const { return IsAssignedField::decode(bit_field_); } void set_is_assigned() { bit_field_ = IsAssignedField::update(bit_field_, true); + if (is_resolved()) { + var()->set_maybe_assigned(); + } } bool is_resolved() const { return IsResolvedField::decode(bit_field_); } @@ -1690,7 +1685,7 @@ class VariableProxy final : public Expression { return var()->IsUnallocated() || var()->IsLookupSlot(); } - void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, + void AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache); FeedbackVectorSlot VariableFeedbackSlot() { return variable_feedback_slot_; } @@ -1786,7 +1781,7 @@ class Property final : public Expression { bool IsSuperAccess() { return obj()->IsSuperPropertyReference(); } - void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, + void AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) { FeedbackVectorSlotKind kind = key()->IsPropertyName() ? FeedbackVectorSlotKind::LOAD_IC @@ -1844,7 +1839,7 @@ class Call final : public Expression { void set_expression(Expression* e) { expression_ = e; } // Type feedback information. - void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, + void AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache); FeedbackVectorSlot CallFeedbackICSlot() const { return ic_slot_; } @@ -1876,11 +1871,9 @@ class Call final : public Expression { allocation_site_ = site; } - static int num_ids() { return parent_num_ids() + 4; } + static int num_ids() { return parent_num_ids() + 2; } BailoutId ReturnId() const { return BailoutId(local_id(0)); } - BailoutId EvalId() const { return BailoutId(local_id(1)); } - BailoutId LookupId() const { return BailoutId(local_id(2)); } - BailoutId CallId() const { return BailoutId(local_id(3)); } + BailoutId CallId() const { return BailoutId(local_id(1)); } bool is_uninitialized() const { return IsUninitializedField::decode(bit_field_); @@ -1964,7 +1957,7 @@ class CallNew final : public Expression { void set_expression(Expression* e) { expression_ = e; } // Type feedback information. - void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, + void AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache) { // CallNew stores feedback in the exact same way as Call. We can // piggyback on the type feedback infrastructure for calls. @@ -2138,7 +2131,7 @@ class BinaryOperation final : public Expression { // BinaryOperation will have both a slot in the feedback vector and the // TypeFeedbackId to record the type information. TypeFeedbackId is used // by full codegen and the feedback vector slot is used by interpreter. - void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, + void AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache); FeedbackVectorSlot BinaryOperationFeedbackSlot() const { @@ -2231,7 +2224,7 @@ class CountOperation final : public Expression { return binary_operation_slot_; } - void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, + void AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache); FeedbackVectorSlot CountSlot() const { return slot_; } @@ -2283,7 +2276,7 @@ class CompareOperation final : public Expression { // CompareOperation will have both a slot in the feedback vector and the // TypeFeedbackId to record the type information. TypeFeedbackId is used // by full codegen and the feedback vector slot is used by interpreter. - void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, + void AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache); FeedbackVectorSlot CompareOperationFeedbackSlot() const { @@ -2429,7 +2422,7 @@ class Assignment final : public Expression { bit_field_ = StoreModeField::update(bit_field_, mode); } - void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, + void AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache); FeedbackVectorSlot AssignmentSlot() const { return slot_; } @@ -2571,6 +2564,8 @@ class FunctionLiteral final : public Expression { kAccessorOrMethod }; + enum IdType { kIdTypeInvalid = -1, kIdTypeTopLevel = 0 }; + enum ParameterFlag { kNoDuplicateParameters, kHasDuplicateParameters }; enum EagerCompileHint { kShouldEagerCompile, kShouldLazyCompile }; @@ -2594,6 +2589,18 @@ class FunctionLiteral final : public Expression { } LanguageMode language_mode() const; + void AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, + FeedbackVectorSlotCache* cache) { + // The + 1 is because we need an array with room for the literals + // as well as the feedback vector. + literal_feedback_slot_ = + spec->AddCreateClosureSlot(materialized_literal_count_ + 1); + } + + FeedbackVectorSlot LiteralFeedbackSlot() const { + return literal_feedback_slot_; + } + static bool NeedsHomeObject(Expression* expr); int materialized_literal_count() { return materialized_literal_count_; } @@ -2644,8 +2651,6 @@ class FunctionLiteral final : public Expression { return HasDuplicateParameters::decode(bit_field_); } - bool is_function() const { return IsFunction::decode(bit_field_); } - // This is used as a heuristic on when to eagerly compile a function // literal. We consider the following constructs as hints that the // function will be called immediately: @@ -2691,25 +2696,15 @@ class FunctionLiteral final : public Expression { int yield_count() { return yield_count_; } void set_yield_count(int yield_count) { yield_count_ = yield_count; } - bool requires_class_field_init() { - return RequiresClassFieldInit::decode(bit_field_); - } - void set_requires_class_field_init(bool requires_class_field_init) { - bit_field_ = - RequiresClassFieldInit::update(bit_field_, requires_class_field_init); - } - bool is_class_field_initializer() { - return IsClassFieldInitializer::decode(bit_field_); - } - void set_is_class_field_initializer(bool is_class_field_initializer) { - bit_field_ = - IsClassFieldInitializer::update(bit_field_, is_class_field_initializer); - } - int return_position() { return std::max(start_position(), end_position() - (has_braces_ ? 1 : 0)); } + int function_literal_id() const { return function_literal_id_; } + void set_function_literal_id(int function_literal_id) { + function_literal_id_ = function_literal_id; + } + private: friend class AstNodeFactory; @@ -2720,7 +2715,7 @@ class FunctionLiteral final : public Expression { int function_length, FunctionType function_type, ParameterFlag has_duplicate_parameters, EagerCompileHint eager_compile_hint, int position, - bool is_function, bool has_braces) + bool has_braces, int function_literal_id) : Expression(position, kFunctionLiteral), materialized_literal_count_(materialized_literal_count), expected_property_count_(expected_property_count), @@ -2733,16 +2728,14 @@ class FunctionLiteral final : public Expression { scope_(scope), body_(body), raw_inferred_name_(ast_value_factory->empty_string()), - ast_properties_(zone) { - bit_field_ |= - FunctionTypeBits::encode(function_type) | Pretenure::encode(false) | - HasDuplicateParameters::encode(has_duplicate_parameters == - kHasDuplicateParameters) | - IsFunction::encode(is_function) | - RequiresClassFieldInit::encode(false) | - ShouldNotBeUsedOnceHintField::encode(false) | - DontOptimizeReasonField::encode(kNoReason) | - IsClassFieldInitializer::encode(false); + ast_properties_(zone), + function_literal_id_(function_literal_id) { + bit_field_ |= FunctionTypeBits::encode(function_type) | + Pretenure::encode(false) | + HasDuplicateParameters::encode(has_duplicate_parameters == + kHasDuplicateParameters) | + ShouldNotBeUsedOnceHintField::encode(false) | + DontOptimizeReasonField::encode(kNoReason); if (eager_compile_hint == kShouldEagerCompile) SetShouldEagerCompile(); } @@ -2750,15 +2743,11 @@ class FunctionLiteral final : public Expression { : public BitField<FunctionType, Expression::kNextBitFieldIndex, 2> {}; class Pretenure : public BitField<bool, FunctionTypeBits::kNext, 1> {}; class HasDuplicateParameters : public BitField<bool, Pretenure::kNext, 1> {}; - class IsFunction : public BitField<bool, HasDuplicateParameters::kNext, 1> {}; class ShouldNotBeUsedOnceHintField - : public BitField<bool, IsFunction::kNext, 1> {}; - class RequiresClassFieldInit - : public BitField<bool, ShouldNotBeUsedOnceHintField::kNext, 1> {}; - class IsClassFieldInitializer - : public BitField<bool, RequiresClassFieldInit::kNext, 1> {}; + : public BitField<bool, HasDuplicateParameters::kNext, 1> {}; class DontOptimizeReasonField - : public BitField<BailoutReason, IsClassFieldInitializer::kNext, 8> {}; + : public BitField<BailoutReason, ShouldNotBeUsedOnceHintField::kNext, 8> { + }; int materialized_literal_count_; int expected_property_count_; @@ -2774,6 +2763,8 @@ class FunctionLiteral final : public Expression { const AstString* raw_inferred_name_; Handle<String> inferred_name_; AstProperties ast_properties_; + int function_literal_id_; + FeedbackVectorSlot literal_feedback_slot_; }; // Property is used for passing information @@ -2808,27 +2799,16 @@ class ClassLiteral final : public Expression { ZoneList<Property*>* properties() const { return properties_; } int start_position() const { return position(); } int end_position() const { return end_position_; } - - VariableProxy* static_initializer_proxy() const { - return static_initializer_proxy_; + bool has_name_static_property() const { + return HasNameStaticProperty::decode(bit_field_); } - void set_static_initializer_proxy(VariableProxy* proxy) { - static_initializer_proxy_ = proxy; + bool has_static_computed_names() const { + return HasStaticComputedNames::decode(bit_field_); } - BailoutId CreateLiteralId() const { return BailoutId(local_id(0)); } - BailoutId PrototypeId() { return BailoutId(local_id(1)); } - - // Return an AST id for a property that is used in simulate instructions. - BailoutId GetIdForProperty(int i) { return BailoutId(local_id(i + 2)); } - - // Unlike other AST nodes, this number of bailout IDs allocated for an - // ClassLiteral can vary, so num_ids() is not a static method. - int num_ids() const { return parent_num_ids() + 2 + properties()->length(); } - // Object literals need one feedback slot for each non-trivial value, as well // as some slots for home objects. - void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, + void AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, FeedbackVectorSlotCache* cache); bool NeedsProxySlot() const { @@ -2836,7 +2816,7 @@ class ClassLiteral final : public Expression { class_variable_proxy()->var()->IsUnallocated(); } - FeedbackVectorSlot PrototypeSlot() const { return prototype_slot_; } + FeedbackVectorSlot HomeObjectSlot() const { return home_object_slot_; } FeedbackVectorSlot ProxySlot() const { return proxy_slot_; } private: @@ -2844,26 +2824,30 @@ class ClassLiteral final : public Expression { ClassLiteral(VariableProxy* class_variable_proxy, Expression* extends, FunctionLiteral* constructor, ZoneList<Property*>* properties, - int start_position, int end_position) + int start_position, int end_position, + bool has_name_static_property, bool has_static_computed_names) : Expression(start_position, kClassLiteral), end_position_(end_position), class_variable_proxy_(class_variable_proxy), extends_(extends), constructor_(constructor), - properties_(properties), - static_initializer_proxy_(nullptr) {} - - static int parent_num_ids() { return Expression::num_ids(); } - int local_id(int n) const { return base_id() + parent_num_ids() + n; } + properties_(properties) { + bit_field_ |= HasNameStaticProperty::encode(has_name_static_property) | + HasStaticComputedNames::encode(has_static_computed_names); + } int end_position_; - FeedbackVectorSlot prototype_slot_; + FeedbackVectorSlot home_object_slot_; FeedbackVectorSlot proxy_slot_; VariableProxy* class_variable_proxy_; Expression* extends_; FunctionLiteral* constructor_; ZoneList<Property*>* properties_; - VariableProxy* static_initializer_proxy_; + + class HasNameStaticProperty + : public BitField<bool, Expression::kNextBitFieldIndex, 1> {}; + class HasStaticComputedNames + : public BitField<bool, HasNameStaticProperty::kNext, 1> {}; }; @@ -2871,6 +2855,19 @@ class NativeFunctionLiteral final : public Expression { public: Handle<String> name() const { return name_->string(); } v8::Extension* extension() const { return extension_; } + FeedbackVectorSlot LiteralFeedbackSlot() const { + return literal_feedback_slot_; + } + + void AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, + FeedbackVectorSlotCache* cache) { + // 0 is a magic number here. It means we are holding the literals + // array for a native function literal, which needs to be + // the empty literals array. + // TODO(mvstanton): The FeedbackVectorSlotCache can be adapted + // to always return the same slot for this case. + literal_feedback_slot_ = spec->AddCreateClosureSlot(0); + } private: friend class AstNodeFactory; @@ -2883,6 +2880,7 @@ class NativeFunctionLiteral final : public Expression { const AstRawString* name_; v8::Extension* extension_; + FeedbackVectorSlot literal_feedback_slot_; }; @@ -2955,7 +2953,43 @@ class EmptyParentheses final : public Expression { explicit EmptyParentheses(int pos) : Expression(pos, kEmptyParentheses) {} }; +// Represents the spec operation `GetIterator()` +// (defined at https://tc39.github.io/ecma262/#sec-getiterator). Ignition +// desugars this into a LoadIC / JSLoadNamed, CallIC, and a type-check to +// validate return value of the Symbol.iterator() call. +class GetIterator final : public Expression { + public: + Expression* iterable() const { return iterable_; } + void set_iterable(Expression* iterable) { iterable_ = iterable; } + + static int num_ids() { return parent_num_ids(); } + + void AssignFeedbackVectorSlots(FeedbackVectorSpec* spec, + FeedbackVectorSlotCache* cache) { + iterator_property_feedback_slot_ = + spec->AddSlot(FeedbackVectorSlotKind::LOAD_IC); + iterator_call_feedback_slot_ = + spec->AddSlot(FeedbackVectorSlotKind::CALL_IC); + } + + FeedbackVectorSlot IteratorPropertyFeedbackSlot() const { + return iterator_property_feedback_slot_; + } + + FeedbackVectorSlot IteratorCallFeedbackSlot() const { + return iterator_call_feedback_slot_; + } + + private: + friend class AstNodeFactory; + explicit GetIterator(Expression* iterable, int pos) + : Expression(pos, kGetIterator), iterable_(iterable) {} + + Expression* iterable_; + FeedbackVectorSlot iterator_property_feedback_slot_; + FeedbackVectorSlot iterator_call_feedback_slot_; +}; // ---------------------------------------------------------------------------- // Basic visitor @@ -3217,15 +3251,6 @@ class AstNodeFactory final BASE_EMBEDDED { try_block, scope, variable, catch_block, HandlerTable::UNCAUGHT, pos); } - TryCatchStatement* NewTryCatchStatementForPromiseReject(Block* try_block, - Scope* scope, - Variable* variable, - Block* catch_block, - int pos) { - return new (zone_) TryCatchStatement( - try_block, scope, variable, catch_block, HandlerTable::PROMISE, pos); - } - TryCatchStatement* NewTryCatchStatementForDesugaring(Block* try_block, Scope* scope, Variable* variable, @@ -3258,9 +3283,9 @@ class AstNodeFactory final BASE_EMBEDDED { return new (zone_) EmptyStatement(pos); } - SloppyBlockFunctionStatement* NewSloppyBlockFunctionStatement(Scope* scope) { - return new (zone_) SloppyBlockFunctionStatement( - NewEmptyStatement(kNoSourcePosition), scope); + SloppyBlockFunctionStatement* NewSloppyBlockFunctionStatement() { + return new (zone_) + SloppyBlockFunctionStatement(NewEmptyStatement(kNoSourcePosition)); } CaseClause* NewCaseClause( @@ -3437,9 +3462,13 @@ class AstNodeFactory final BASE_EMBEDDED { Expression* value, int pos) { DCHECK(Token::IsAssignmentOp(op)); + + if (op != Token::INIT && target->IsVariableProxy()) { + target->AsVariableProxy()->set_is_assigned(); + } + Assignment* assign = new (zone_) Assignment(op, target, value, pos); if (assign->is_compound()) { - DCHECK(Token::IsAssignmentOp(op)); assign->binary_operation_ = NewBinaryOperation(assign->binary_op(), target, value, pos + 1); } @@ -3463,12 +3492,12 @@ class AstNodeFactory final BASE_EMBEDDED { FunctionLiteral::ParameterFlag has_duplicate_parameters, FunctionLiteral::FunctionType function_type, FunctionLiteral::EagerCompileHint eager_compile_hint, int position, - bool has_braces) { + bool has_braces, int function_literal_id) { return new (zone_) FunctionLiteral( zone_, name, ast_value_factory_, scope, body, materialized_literal_count, expected_property_count, parameter_count, function_length, function_type, has_duplicate_parameters, - eager_compile_hint, position, true, has_braces); + eager_compile_hint, position, has_braces, function_literal_id); } // Creates a FunctionLiteral representing a top-level script, the @@ -3483,7 +3512,8 @@ class AstNodeFactory final BASE_EMBEDDED { body, materialized_literal_count, expected_property_count, parameter_count, parameter_count, FunctionLiteral::kAnonymousExpression, FunctionLiteral::kNoDuplicateParameters, - FunctionLiteral::kShouldLazyCompile, 0, false, true); + FunctionLiteral::kShouldLazyCompile, 0, true, + FunctionLiteral::kIdTypeTopLevel); } ClassLiteral::Property* NewClassLiteralProperty( @@ -3496,9 +3526,12 @@ class AstNodeFactory final BASE_EMBEDDED { ClassLiteral* NewClassLiteral(VariableProxy* proxy, Expression* extends, FunctionLiteral* constructor, ZoneList<ClassLiteral::Property*>* properties, - int start_position, int end_position) { - return new (zone_) ClassLiteral(proxy, extends, constructor, properties, - start_position, end_position); + 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); } NativeFunctionLiteral* NewNativeFunctionLiteral(const AstRawString* name, @@ -3534,6 +3567,10 @@ class AstNodeFactory final BASE_EMBEDDED { return new (zone_) EmptyParentheses(pos); } + GetIterator* NewGetIterator(Expression* iterable, int pos) { + return new (zone_) GetIterator(iterable, pos); + } + Zone* zone() const { return zone_; } void set_zone(Zone* zone) { zone_ = zone; } diff --git a/deps/v8/src/ast/compile-time-value.cc b/deps/v8/src/ast/compile-time-value.cc index eda536b716..27dd29fee0 100644 --- a/deps/v8/src/ast/compile-time-value.cc +++ b/deps/v8/src/ast/compile-time-value.cc @@ -48,8 +48,8 @@ CompileTimeValue::LiteralType CompileTimeValue::GetLiteralType( return static_cast<LiteralType>(literal_type->value()); } -Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) { - return Handle<FixedArray>(FixedArray::cast(value->get(kElementsSlot))); +Handle<HeapObject> CompileTimeValue::GetElements(Handle<FixedArray> value) { + return Handle<HeapObject>(HeapObject::cast(value->get(kElementsSlot))); } } // namespace internal diff --git a/deps/v8/src/ast/compile-time-value.h b/deps/v8/src/ast/compile-time-value.h index 27351b79cc..d61443e583 100644 --- a/deps/v8/src/ast/compile-time-value.h +++ b/deps/v8/src/ast/compile-time-value.h @@ -31,8 +31,8 @@ class CompileTimeValue : public AllStatic { // Get the type of a compile time value returned by GetValue(). static LiteralType GetLiteralType(Handle<FixedArray> value); - // Get the elements array of a compile time value returned by GetValue(). - static Handle<FixedArray> GetElements(Handle<FixedArray> value); + // Get the elements of a compile time value returned by GetValue(). + static Handle<HeapObject> GetElements(Handle<FixedArray> value); private: static const int kLiteralTypeSlot = 0; diff --git a/deps/v8/src/ast/modules.cc b/deps/v8/src/ast/modules.cc index 339d64c580..41ce9e03da 100644 --- a/deps/v8/src/ast/modules.cc +++ b/deps/v8/src/ast/modules.cc @@ -5,6 +5,8 @@ #include "src/ast/modules.h" #include "src/ast/ast-value-factory.h" #include "src/ast/scopes.h" +#include "src/objects-inl.h" +#include "src/objects/module-info.h" namespace v8 { namespace internal { diff --git a/deps/v8/src/ast/prettyprinter.cc b/deps/v8/src/ast/prettyprinter.cc index a3fc50ae57..463ae26c4d 100644 --- a/deps/v8/src/ast/prettyprinter.cc +++ b/deps/v8/src/ast/prettyprinter.cc @@ -10,18 +10,19 @@ #include "src/ast/scopes.h" #include "src/base/platform/platform.h" #include "src/globals.h" +#include "src/objects-inl.h" namespace v8 { namespace internal { -CallPrinter::CallPrinter(Isolate* isolate, bool is_builtin) +CallPrinter::CallPrinter(Isolate* isolate, bool is_user_js) : builder_(isolate) { isolate_ = isolate; position_ = 0; num_prints_ = 0; found_ = false; done_ = false; - is_builtin_ = is_builtin; + is_user_js_ = is_user_js; InitializeAstVisitor(isolate); } @@ -239,11 +240,11 @@ void CallPrinter::VisitArrayLiteral(ArrayLiteral* node) { void CallPrinter::VisitVariableProxy(VariableProxy* node) { - if (is_builtin_) { - // Variable names of builtins are meaningless due to minification. - Print("(var)"); - } else { + if (is_user_js_) { PrintLiteral(node->name(), false); + } else { + // Variable names of non-user code are meaningless due to minification. + Print("(var)"); } } @@ -279,9 +280,9 @@ void CallPrinter::VisitProperty(Property* node) { void CallPrinter::VisitCall(Call* node) { bool was_found = !found_ && node->position() == position_; if (was_found) { - // Bail out if the error is caused by a direct call to a variable in builtin - // code. The variable name is meaningless due to minification. - if (is_builtin_ && node->expression()->IsVariableProxy()) { + // Bail out if the error is caused by a direct call to a variable in + // non-user JS code. The variable name is meaningless due to minification. + if (!is_user_js_ && node->expression()->IsVariableProxy()) { done_ = true; return; } @@ -297,9 +298,9 @@ void CallPrinter::VisitCall(Call* node) { void CallPrinter::VisitCallNew(CallNew* node) { bool was_found = !found_ && node->position() == position_; if (was_found) { - // Bail out if the error is caused by a direct call to a variable in builtin - // code. The variable name is meaningless due to minification. - if (is_builtin_ && node->expression()->IsVariableProxy()) { + // Bail out if the error is caused by a direct call to a variable in + // non-user JS code. The variable name is meaningless due to minification. + if (!is_user_js_ && node->expression()->IsVariableProxy()) { done_ = true; return; } @@ -370,6 +371,11 @@ void CallPrinter::VisitEmptyParentheses(EmptyParentheses* node) { UNREACHABLE(); } +void CallPrinter::VisitGetIterator(GetIterator* node) { + Print("GetIterator("); + Find(node->iterable(), true); + Print(")"); +} void CallPrinter::VisitThisFunction(ThisFunction* node) {} @@ -874,15 +880,16 @@ void AstPrinter::PrintTryStatement(TryStatement* node) { case HandlerTable::CAUGHT: prediction = "CAUGHT"; break; - case HandlerTable::PROMISE: - prediction = "PROMISE"; - break; case HandlerTable::DESUGARING: prediction = "DESUGARING"; break; case HandlerTable::ASYNC_AWAIT: prediction = "ASYNC_AWAIT"; break; + case HandlerTable::PROMISE: + // Catch prediction resulting in promise rejections aren't + // parsed by the parser. + UNREACHABLE(); } Print(" %s\n", prediction); } @@ -1019,6 +1026,9 @@ void AstPrinter::PrintObjectProperties( case ObjectLiteral::Property::SETTER: prop_kind = "SETTER"; break; + case ObjectLiteral::Property::SPREAD: + prop_kind = "SPREAD"; + break; } EmbeddedVector<char, 128> buf; SNPrintF(buf, "PROPERTY - %s", prop_kind); @@ -1136,7 +1146,14 @@ void AstPrinter::VisitCallNew(CallNew* node) { void AstPrinter::VisitCallRuntime(CallRuntime* node) { EmbeddedVector<char, 128> buf; - SNPrintF(buf, "CALL RUNTIME %s", node->debug_name()); + 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()); + } + IndentedScope indent(this, buf.start(), node->position()); PrintArguments(node->arguments()); } @@ -1181,6 +1198,10 @@ void AstPrinter::VisitEmptyParentheses(EmptyParentheses* node) { IndentedScope indent(this, "()", node->position()); } +void AstPrinter::VisitGetIterator(GetIterator* node) { + IndentedScope indent(this, "GET-ITERATOR", node->position()); + Visit(node->iterable()); +} void AstPrinter::VisitThisFunction(ThisFunction* node) { IndentedScope indent(this, "THIS-FUNCTION", node->position()); diff --git a/deps/v8/src/ast/prettyprinter.h b/deps/v8/src/ast/prettyprinter.h index b56c834893..fdc079ca07 100644 --- a/deps/v8/src/ast/prettyprinter.h +++ b/deps/v8/src/ast/prettyprinter.h @@ -15,7 +15,7 @@ namespace internal { class CallPrinter final : public AstVisitor<CallPrinter> { public: - explicit CallPrinter(Isolate* isolate, bool is_builtin); + explicit CallPrinter(Isolate* isolate, bool is_user_js); // The following routine prints the node with position |position| into a // string. @@ -38,7 +38,7 @@ class CallPrinter final : public AstVisitor<CallPrinter> { int position_; // position of ast node to print bool found_; bool done_; - bool is_builtin_; + bool is_user_js_; DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); diff --git a/deps/v8/src/ast/scopeinfo.cc b/deps/v8/src/ast/scopeinfo.cc deleted file mode 100644 index 3a3ea03189..0000000000 --- a/deps/v8/src/ast/scopeinfo.cc +++ /dev/null @@ -1,975 +0,0 @@ -// Copyright 2011 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <stdlib.h> - -#include "src/ast/context-slot-cache.h" -#include "src/ast/scopes.h" -#include "src/ast/variables.h" -#include "src/bootstrapper.h" - -namespace v8 { -namespace internal { - -// An entry in ModuleVariableEntries consists of several slots: -enum ModuleVariableEntryOffset { - kModuleVariableNameOffset, - kModuleVariableIndexOffset, - kModuleVariablePropertiesOffset, - kModuleVariableEntryLength // Sentinel value. -}; - -#ifdef DEBUG -bool ScopeInfo::Equals(ScopeInfo* other) const { - if (length() != other->length()) return false; - for (int index = 0; index < length(); ++index) { - Object* entry = get(index); - Object* other_entry = other->get(index); - if (entry->IsSmi()) { - if (entry != other_entry) return false; - } else { - if (HeapObject::cast(entry)->map()->instance_type() != - HeapObject::cast(other_entry)->map()->instance_type()) { - return false; - } - if (entry->IsString()) { - if (!String::cast(entry)->Equals(String::cast(other_entry))) { - return false; - } - } else if (entry->IsScopeInfo()) { - if (!ScopeInfo::cast(entry)->Equals(ScopeInfo::cast(other_entry))) { - return false; - } - } else if (entry->IsModuleInfo()) { - if (!ModuleInfo::cast(entry)->Equals(ModuleInfo::cast(other_entry))) { - return false; - } - } else { - UNREACHABLE(); - return false; - } - } - } - return true; -} -#endif - -Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope, - MaybeHandle<ScopeInfo> outer_scope) { - // Collect variables. - int stack_local_count = 0; - int context_local_count = 0; - int module_vars_count = 0; - // Stack allocated block scope variables are allocated in the parent - // declaration scope, but are recorded in the block scope's scope info. First - // slot index indicates at which offset a particular scope starts in the - // parent declaration scope. - int first_slot_index = 0; - for (Variable* var : *scope->locals()) { - switch (var->location()) { - case VariableLocation::LOCAL: - if (stack_local_count == 0) first_slot_index = var->index(); - stack_local_count++; - break; - case VariableLocation::CONTEXT: - context_local_count++; - break; - case VariableLocation::MODULE: - module_vars_count++; - break; - default: - break; - } - } - DCHECK(module_vars_count == 0 || scope->is_module_scope()); - - // Make sure we allocate the correct amount. - DCHECK_EQ(scope->ContextLocalCount(), context_local_count); - - // Determine use and location of the "this" binding if it is present. - VariableAllocationInfo receiver_info; - if (scope->is_declaration_scope() && - scope->AsDeclarationScope()->has_this_declaration()) { - Variable* var = scope->AsDeclarationScope()->receiver(); - if (!var->is_used()) { - receiver_info = UNUSED; - } else if (var->IsContextSlot()) { - receiver_info = CONTEXT; - } else { - DCHECK(var->IsParameter()); - receiver_info = STACK; - } - } else { - receiver_info = NONE; - } - - bool has_new_target = - scope->is_declaration_scope() && - scope->AsDeclarationScope()->new_target_var() != nullptr; - - // Determine use and location of the function variable if it is present. - VariableAllocationInfo function_name_info; - if (scope->is_function_scope() && - scope->AsDeclarationScope()->function_var() != nullptr) { - Variable* var = scope->AsDeclarationScope()->function_var(); - if (!var->is_used()) { - function_name_info = UNUSED; - } else if (var->IsContextSlot()) { - function_name_info = CONTEXT; - } else { - DCHECK(var->IsStackLocal()); - function_name_info = STACK; - } - } else { - function_name_info = NONE; - } - - const bool has_function_name = function_name_info != NONE; - const bool has_receiver = receiver_info == STACK || receiver_info == CONTEXT; - const int parameter_count = scope->num_parameters(); - const bool has_outer_scope_info = !outer_scope.is_null(); - const int length = kVariablePartIndex + parameter_count + - (1 + stack_local_count) + 2 * context_local_count + - (has_receiver ? 1 : 0) + (has_function_name ? 2 : 0) + - (has_outer_scope_info ? 1 : 0) + - (scope->is_module_scope() - ? 2 + kModuleVariableEntryLength * module_vars_count - : 0); - - Factory* factory = isolate->factory(); - Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length); - - bool has_simple_parameters = false; - bool asm_module = false; - bool asm_function = false; - FunctionKind function_kind = kNormalFunction; - if (scope->is_function_scope()) { - DeclarationScope* function_scope = scope->AsDeclarationScope(); - has_simple_parameters = function_scope->has_simple_parameters(); - asm_module = function_scope->asm_module(); - asm_function = function_scope->asm_function(); - function_kind = function_scope->function_kind(); - } - - // Encode the flags. - int flags = - ScopeTypeField::encode(scope->scope_type()) | - CallsEvalField::encode(scope->calls_eval()) | - LanguageModeField::encode(scope->language_mode()) | - DeclarationScopeField::encode(scope->is_declaration_scope()) | - ReceiverVariableField::encode(receiver_info) | - HasNewTargetField::encode(has_new_target) | - FunctionVariableField::encode(function_name_info) | - AsmModuleField::encode(asm_module) | - AsmFunctionField::encode(asm_function) | - HasSimpleParametersField::encode(has_simple_parameters) | - FunctionKindField::encode(function_kind) | - HasOuterScopeInfoField::encode(has_outer_scope_info) | - IsDebugEvaluateScopeField::encode(scope->is_debug_evaluate_scope()); - scope_info->SetFlags(flags); - - scope_info->SetParameterCount(parameter_count); - scope_info->SetStackLocalCount(stack_local_count); - scope_info->SetContextLocalCount(context_local_count); - - int index = kVariablePartIndex; - // Add parameters. - DCHECK_EQ(index, scope_info->ParameterNamesIndex()); - if (scope->is_declaration_scope()) { - for (int i = 0; i < parameter_count; ++i) { - scope_info->set(index++, - *scope->AsDeclarationScope()->parameter(i)->name()); - } - } - - // Add stack locals' names, context locals' names and info, module variables' - // names and info. We are assuming that the stack locals' slots are allocated - // in increasing order, so we can simply add them to the ScopeInfo object. - // Context locals are added using their index. - DCHECK_EQ(index, scope_info->StackLocalFirstSlotIndex()); - scope_info->set(index++, Smi::FromInt(first_slot_index)); - DCHECK_EQ(index, scope_info->StackLocalNamesIndex()); - - int stack_local_base = index; - int context_local_base = stack_local_base + stack_local_count; - int context_local_info_base = context_local_base + context_local_count; - int module_var_entry = scope_info->ModuleVariablesIndex(); - - for (Variable* var : *scope->locals()) { - switch (var->location()) { - case VariableLocation::LOCAL: { - int local_index = var->index() - first_slot_index; - DCHECK_LE(0, local_index); - DCHECK_LT(local_index, stack_local_count); - scope_info->set(stack_local_base + local_index, *var->name()); - break; - } - case VariableLocation::CONTEXT: { - // Due to duplicate parameters, context locals aren't guaranteed to come - // in order. - int local_index = var->index() - Context::MIN_CONTEXT_SLOTS; - DCHECK_LE(0, local_index); - DCHECK_LT(local_index, context_local_count); - uint32_t info = VariableModeField::encode(var->mode()) | - InitFlagField::encode(var->initialization_flag()) | - MaybeAssignedFlagField::encode(var->maybe_assigned()); - scope_info->set(context_local_base + local_index, *var->name()); - scope_info->set(context_local_info_base + local_index, - Smi::FromInt(info)); - break; - } - case VariableLocation::MODULE: { - scope_info->set(module_var_entry + kModuleVariableNameOffset, - *var->name()); - scope_info->set(module_var_entry + kModuleVariableIndexOffset, - Smi::FromInt(var->index())); - uint32_t properties = - VariableModeField::encode(var->mode()) | - InitFlagField::encode(var->initialization_flag()) | - MaybeAssignedFlagField::encode(var->maybe_assigned()); - scope_info->set(module_var_entry + kModuleVariablePropertiesOffset, - Smi::FromInt(properties)); - module_var_entry += kModuleVariableEntryLength; - break; - } - default: - break; - } - } - - index += stack_local_count + 2 * context_local_count; - - // If the receiver is allocated, add its index. - DCHECK_EQ(index, scope_info->ReceiverInfoIndex()); - if (has_receiver) { - int var_index = scope->AsDeclarationScope()->receiver()->index(); - scope_info->set(index++, Smi::FromInt(var_index)); - // ?? DCHECK(receiver_info != CONTEXT || var_index == - // scope_info->ContextLength() - 1); - } - - // If present, add the function variable name and its index. - DCHECK_EQ(index, scope_info->FunctionNameInfoIndex()); - if (has_function_name) { - int var_index = scope->AsDeclarationScope()->function_var()->index(); - scope_info->set(index++, - *scope->AsDeclarationScope()->function_var()->name()); - scope_info->set(index++, Smi::FromInt(var_index)); - DCHECK(function_name_info != CONTEXT || - var_index == scope_info->ContextLength() - 1); - } - - // If present, add the outer scope info. - DCHECK(index == scope_info->OuterScopeInfoIndex()); - if (has_outer_scope_info) { - scope_info->set(index++, *outer_scope.ToHandleChecked()); - } - - // Module-specific information (only for module scopes). - if (scope->is_module_scope()) { - Handle<ModuleInfo> module_info = - ModuleInfo::New(isolate, zone, scope->AsModuleScope()->module()); - DCHECK_EQ(index, scope_info->ModuleInfoIndex()); - scope_info->set(index++, *module_info); - DCHECK_EQ(index, scope_info->ModuleVariableCountIndex()); - scope_info->set(index++, Smi::FromInt(module_vars_count)); - DCHECK_EQ(index, scope_info->ModuleVariablesIndex()); - // The variable entries themselves have already been written above. - index += kModuleVariableEntryLength * module_vars_count; - } - - DCHECK_EQ(index, scope_info->length()); - DCHECK_EQ(scope->num_parameters(), scope_info->ParameterCount()); - DCHECK_EQ(scope->num_heap_slots(), scope_info->ContextLength()); - return scope_info; -} - -Handle<ScopeInfo> ScopeInfo::CreateForWithScope( - Isolate* isolate, MaybeHandle<ScopeInfo> outer_scope) { - const bool has_outer_scope_info = !outer_scope.is_null(); - const int length = kVariablePartIndex + 1 + (has_outer_scope_info ? 1 : 0); - - Factory* factory = isolate->factory(); - Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length); - - // Encode the flags. - int flags = - ScopeTypeField::encode(WITH_SCOPE) | CallsEvalField::encode(false) | - LanguageModeField::encode(SLOPPY) | DeclarationScopeField::encode(false) | - ReceiverVariableField::encode(NONE) | HasNewTargetField::encode(false) | - FunctionVariableField::encode(NONE) | AsmModuleField::encode(false) | - AsmFunctionField::encode(false) | HasSimpleParametersField::encode(true) | - FunctionKindField::encode(kNormalFunction) | - HasOuterScopeInfoField::encode(has_outer_scope_info) | - IsDebugEvaluateScopeField::encode(false); - scope_info->SetFlags(flags); - - scope_info->SetParameterCount(0); - scope_info->SetStackLocalCount(0); - scope_info->SetContextLocalCount(0); - - int index = kVariablePartIndex; - DCHECK_EQ(index, scope_info->ParameterNamesIndex()); - DCHECK_EQ(index, scope_info->StackLocalFirstSlotIndex()); - scope_info->set(index++, Smi::kZero); - DCHECK_EQ(index, scope_info->StackLocalNamesIndex()); - DCHECK_EQ(index, scope_info->ReceiverInfoIndex()); - DCHECK_EQ(index, scope_info->FunctionNameInfoIndex()); - DCHECK(index == scope_info->OuterScopeInfoIndex()); - if (has_outer_scope_info) { - scope_info->set(index++, *outer_scope.ToHandleChecked()); - } - DCHECK_EQ(index, scope_info->length()); - DCHECK_EQ(0, scope_info->ParameterCount()); - DCHECK_EQ(Context::MIN_CONTEXT_SLOTS, scope_info->ContextLength()); - return scope_info; -} - -Handle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) { - DCHECK(isolate->bootstrapper()->IsActive()); - - const int stack_local_count = 0; - const int context_local_count = 1; - const bool has_simple_parameters = true; - const VariableAllocationInfo receiver_info = CONTEXT; - const VariableAllocationInfo function_name_info = NONE; - const bool has_function_name = false; - const bool has_receiver = true; - const bool has_outer_scope_info = false; - const int parameter_count = 0; - const int length = kVariablePartIndex + parameter_count + - (1 + stack_local_count) + 2 * context_local_count + - (has_receiver ? 1 : 0) + (has_function_name ? 2 : 0) + - (has_outer_scope_info ? 1 : 0); - - Factory* factory = isolate->factory(); - Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length); - - // Encode the flags. - int flags = - ScopeTypeField::encode(SCRIPT_SCOPE) | CallsEvalField::encode(false) | - LanguageModeField::encode(SLOPPY) | DeclarationScopeField::encode(true) | - ReceiverVariableField::encode(receiver_info) | - FunctionVariableField::encode(function_name_info) | - AsmModuleField::encode(false) | AsmFunctionField::encode(false) | - HasSimpleParametersField::encode(has_simple_parameters) | - FunctionKindField::encode(FunctionKind::kNormalFunction) | - HasOuterScopeInfoField::encode(has_outer_scope_info) | - IsDebugEvaluateScopeField::encode(false); - scope_info->SetFlags(flags); - scope_info->SetParameterCount(parameter_count); - scope_info->SetStackLocalCount(stack_local_count); - scope_info->SetContextLocalCount(context_local_count); - - int index = kVariablePartIndex; - const int first_slot_index = 0; - DCHECK_EQ(index, scope_info->StackLocalFirstSlotIndex()); - scope_info->set(index++, Smi::FromInt(first_slot_index)); - DCHECK_EQ(index, scope_info->StackLocalNamesIndex()); - - // Here we add info for context-allocated "this". - DCHECK_EQ(index, scope_info->ContextLocalNamesIndex()); - scope_info->set(index++, isolate->heap()->this_string()); - DCHECK_EQ(index, scope_info->ContextLocalInfosIndex()); - const uint32_t value = VariableModeField::encode(CONST) | - InitFlagField::encode(kCreatedInitialized) | - MaybeAssignedFlagField::encode(kNotAssigned); - scope_info->set(index++, Smi::FromInt(value)); - - // And here we record that this scopeinfo binds a receiver. - DCHECK_EQ(index, scope_info->ReceiverInfoIndex()); - const int receiver_index = Context::MIN_CONTEXT_SLOTS + 0; - scope_info->set(index++, Smi::FromInt(receiver_index)); - - DCHECK_EQ(index, scope_info->FunctionNameInfoIndex()); - DCHECK_EQ(index, scope_info->OuterScopeInfoIndex()); - DCHECK_EQ(index, scope_info->length()); - DCHECK_EQ(scope_info->ParameterCount(), 0); - DCHECK_EQ(scope_info->ContextLength(), Context::MIN_CONTEXT_SLOTS + 1); - - return scope_info; -} - - -ScopeInfo* ScopeInfo::Empty(Isolate* isolate) { - return isolate->heap()->empty_scope_info(); -} - - -ScopeType ScopeInfo::scope_type() { - DCHECK_LT(0, length()); - return ScopeTypeField::decode(Flags()); -} - - -bool ScopeInfo::CallsEval() { - return length() > 0 && CallsEvalField::decode(Flags()); -} - - -LanguageMode ScopeInfo::language_mode() { - return length() > 0 ? LanguageModeField::decode(Flags()) : SLOPPY; -} - - -bool ScopeInfo::is_declaration_scope() { - return DeclarationScopeField::decode(Flags()); -} - - -int ScopeInfo::LocalCount() { - return StackLocalCount() + ContextLocalCount(); -} - - -int ScopeInfo::StackSlotCount() { - if (length() > 0) { - bool function_name_stack_slot = - FunctionVariableField::decode(Flags()) == STACK; - return StackLocalCount() + (function_name_stack_slot ? 1 : 0); - } - return 0; -} - - -int ScopeInfo::ContextLength() { - if (length() > 0) { - int context_locals = ContextLocalCount(); - bool function_name_context_slot = - FunctionVariableField::decode(Flags()) == CONTEXT; - bool has_context = context_locals > 0 || function_name_context_slot || - scope_type() == WITH_SCOPE || - (scope_type() == BLOCK_SCOPE && CallsSloppyEval() && - is_declaration_scope()) || - (scope_type() == FUNCTION_SCOPE && CallsSloppyEval()) || - scope_type() == MODULE_SCOPE; - - if (has_context) { - return Context::MIN_CONTEXT_SLOTS + context_locals + - (function_name_context_slot ? 1 : 0); - } - } - return 0; -} - - -bool ScopeInfo::HasReceiver() { - if (length() > 0) { - return NONE != ReceiverVariableField::decode(Flags()); - } else { - return false; - } -} - - -bool ScopeInfo::HasAllocatedReceiver() { - if (length() > 0) { - VariableAllocationInfo allocation = ReceiverVariableField::decode(Flags()); - return allocation == STACK || allocation == CONTEXT; - } else { - return false; - } -} - - -bool ScopeInfo::HasNewTarget() { return HasNewTargetField::decode(Flags()); } - - -bool ScopeInfo::HasFunctionName() { - if (length() > 0) { - return NONE != FunctionVariableField::decode(Flags()); - } else { - return false; - } -} - -bool ScopeInfo::HasOuterScopeInfo() { - if (length() > 0) { - return HasOuterScopeInfoField::decode(Flags()); - } else { - return false; - } -} - -bool ScopeInfo::IsDebugEvaluateScope() { - if (length() > 0) { - return IsDebugEvaluateScopeField::decode(Flags()); - } else { - return false; - } -} - -void ScopeInfo::SetIsDebugEvaluateScope() { - if (length() > 0) { - DCHECK_EQ(scope_type(), WITH_SCOPE); - SetFlags(Flags() | IsDebugEvaluateScopeField::encode(true)); - } else { - UNREACHABLE(); - } -} - -bool ScopeInfo::HasHeapAllocatedLocals() { - if (length() > 0) { - return ContextLocalCount() > 0; - } else { - return false; - } -} - - -bool ScopeInfo::HasContext() { - return ContextLength() > 0; -} - - -String* ScopeInfo::FunctionName() { - DCHECK(HasFunctionName()); - return String::cast(get(FunctionNameInfoIndex())); -} - -ScopeInfo* ScopeInfo::OuterScopeInfo() { - DCHECK(HasOuterScopeInfo()); - return ScopeInfo::cast(get(OuterScopeInfoIndex())); -} - -ModuleInfo* ScopeInfo::ModuleDescriptorInfo() { - DCHECK(scope_type() == MODULE_SCOPE); - return ModuleInfo::cast(get(ModuleInfoIndex())); -} - -String* ScopeInfo::ParameterName(int var) { - DCHECK_LE(0, var); - DCHECK_LT(var, ParameterCount()); - int info_index = ParameterNamesIndex() + var; - return String::cast(get(info_index)); -} - - -String* ScopeInfo::LocalName(int var) { - DCHECK_LE(0, var); - DCHECK_LT(var, LocalCount()); - DCHECK(StackLocalNamesIndex() + StackLocalCount() == - ContextLocalNamesIndex()); - int info_index = StackLocalNamesIndex() + var; - return String::cast(get(info_index)); -} - - -String* ScopeInfo::StackLocalName(int var) { - DCHECK_LE(0, var); - DCHECK_LT(var, StackLocalCount()); - int info_index = StackLocalNamesIndex() + var; - return String::cast(get(info_index)); -} - - -int ScopeInfo::StackLocalIndex(int var) { - DCHECK_LE(0, var); - DCHECK_LT(var, StackLocalCount()); - int first_slot_index = Smi::cast(get(StackLocalFirstSlotIndex()))->value(); - return first_slot_index + var; -} - - -String* ScopeInfo::ContextLocalName(int var) { - DCHECK_LE(0, var); - DCHECK_LT(var, ContextLocalCount()); - int info_index = ContextLocalNamesIndex() + var; - return String::cast(get(info_index)); -} - - -VariableMode ScopeInfo::ContextLocalMode(int var) { - DCHECK_LE(0, var); - DCHECK_LT(var, ContextLocalCount()); - int info_index = ContextLocalInfosIndex() + var; - int value = Smi::cast(get(info_index))->value(); - return VariableModeField::decode(value); -} - - -InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) { - DCHECK_LE(0, var); - DCHECK_LT(var, ContextLocalCount()); - int info_index = ContextLocalInfosIndex() + var; - int value = Smi::cast(get(info_index))->value(); - return InitFlagField::decode(value); -} - - -MaybeAssignedFlag ScopeInfo::ContextLocalMaybeAssignedFlag(int var) { - DCHECK_LE(0, var); - DCHECK_LT(var, ContextLocalCount()); - int info_index = ContextLocalInfosIndex() + var; - int value = Smi::cast(get(info_index))->value(); - return MaybeAssignedFlagField::decode(value); -} - -bool ScopeInfo::VariableIsSynthetic(String* name) { - // There's currently no flag stored on the ScopeInfo to indicate that a - // variable is a compiler-introduced temporary. However, to avoid conflict - // with user declarations, the current temporaries like .generator_object and - // .result start with a dot, so we can use that as a flag. It's a hack! - return name->length() == 0 || name->Get(0) == '.' || - name->Equals(name->GetHeap()->this_string()); -} - - -int ScopeInfo::StackSlotIndex(String* name) { - DCHECK(name->IsInternalizedString()); - if (length() > 0) { - int first_slot_index = Smi::cast(get(StackLocalFirstSlotIndex()))->value(); - int start = StackLocalNamesIndex(); - int end = start + StackLocalCount(); - for (int i = start; i < end; ++i) { - if (name == get(i)) { - return i - start + first_slot_index; - } - } - } - return -1; -} - -int ScopeInfo::ModuleIndex(Handle<String> name, VariableMode* mode, - InitializationFlag* init_flag, - MaybeAssignedFlag* maybe_assigned_flag) { - DCHECK_EQ(scope_type(), MODULE_SCOPE); - DCHECK(name->IsInternalizedString()); - DCHECK_NOT_NULL(mode); - DCHECK_NOT_NULL(init_flag); - DCHECK_NOT_NULL(maybe_assigned_flag); - - int module_vars_count = Smi::cast(get(ModuleVariableCountIndex()))->value(); - int entry = ModuleVariablesIndex(); - for (int i = 0; i < module_vars_count; ++i) { - if (*name == get(entry + kModuleVariableNameOffset)) { - int index; - ModuleVariable(i, nullptr, &index, mode, init_flag, maybe_assigned_flag); - return index; - } - entry += kModuleVariableEntryLength; - } - - return 0; -} - -int ScopeInfo::ContextSlotIndex(Handle<ScopeInfo> scope_info, - Handle<String> name, VariableMode* mode, - InitializationFlag* init_flag, - MaybeAssignedFlag* maybe_assigned_flag) { - DCHECK(name->IsInternalizedString()); - DCHECK_NOT_NULL(mode); - DCHECK_NOT_NULL(init_flag); - DCHECK_NOT_NULL(maybe_assigned_flag); - - if (scope_info->length() > 0) { - ContextSlotCache* context_slot_cache = - scope_info->GetIsolate()->context_slot_cache(); - int result = context_slot_cache->Lookup(*scope_info, *name, mode, init_flag, - maybe_assigned_flag); - if (result != ContextSlotCache::kNotFound) { - DCHECK_LT(result, scope_info->ContextLength()); - return result; - } - - int start = scope_info->ContextLocalNamesIndex(); - int end = start + scope_info->ContextLocalCount(); - for (int i = start; i < end; ++i) { - if (*name == scope_info->get(i)) { - int var = i - start; - *mode = scope_info->ContextLocalMode(var); - *init_flag = scope_info->ContextLocalInitFlag(var); - *maybe_assigned_flag = scope_info->ContextLocalMaybeAssignedFlag(var); - result = Context::MIN_CONTEXT_SLOTS + var; - - context_slot_cache->Update(scope_info, name, *mode, *init_flag, - *maybe_assigned_flag, result); - DCHECK_LT(result, scope_info->ContextLength()); - return result; - } - } - // Cache as not found. Mode, init flag and maybe assigned flag don't matter. - context_slot_cache->Update(scope_info, name, TEMPORARY, - kNeedsInitialization, kNotAssigned, -1); - } - - return -1; -} - -String* ScopeInfo::ContextSlotName(int slot_index) { - int const var = slot_index - Context::MIN_CONTEXT_SLOTS; - DCHECK_LE(0, var); - DCHECK_LT(var, ContextLocalCount()); - return ContextLocalName(var); -} - - -int ScopeInfo::ParameterIndex(String* name) { - DCHECK(name->IsInternalizedString()); - if (length() > 0) { - // We must read parameters from the end since for - // multiply declared parameters the value of the - // last declaration of that parameter is used - // inside a function (and thus we need to look - // at the last index). Was bug# 1110337. - int start = ParameterNamesIndex(); - int end = start + ParameterCount(); - for (int i = end - 1; i >= start; --i) { - if (name == get(i)) { - return i - start; - } - } - } - return -1; -} - - -int ScopeInfo::ReceiverContextSlotIndex() { - if (length() > 0 && ReceiverVariableField::decode(Flags()) == CONTEXT) - return Smi::cast(get(ReceiverInfoIndex()))->value(); - return -1; -} - -int ScopeInfo::FunctionContextSlotIndex(String* name) { - DCHECK(name->IsInternalizedString()); - if (length() > 0) { - if (FunctionVariableField::decode(Flags()) == CONTEXT && - FunctionName() == name) { - return Smi::cast(get(FunctionNameInfoIndex() + 1))->value(); - } - } - return -1; -} - - -FunctionKind ScopeInfo::function_kind() { - return FunctionKindField::decode(Flags()); -} - -int ScopeInfo::ParameterNamesIndex() { - DCHECK_LT(0, length()); - return kVariablePartIndex; -} - - -int ScopeInfo::StackLocalFirstSlotIndex() { - return ParameterNamesIndex() + ParameterCount(); -} - -int ScopeInfo::StackLocalNamesIndex() { return StackLocalFirstSlotIndex() + 1; } - -int ScopeInfo::ContextLocalNamesIndex() { - return StackLocalNamesIndex() + StackLocalCount(); -} - -int ScopeInfo::ContextLocalInfosIndex() { - return ContextLocalNamesIndex() + ContextLocalCount(); -} - -int ScopeInfo::ReceiverInfoIndex() { - return ContextLocalInfosIndex() + ContextLocalCount(); -} - -int ScopeInfo::FunctionNameInfoIndex() { - return ReceiverInfoIndex() + (HasAllocatedReceiver() ? 1 : 0); -} - -int ScopeInfo::OuterScopeInfoIndex() { - return FunctionNameInfoIndex() + (HasFunctionName() ? 2 : 0); -} - -int ScopeInfo::ModuleInfoIndex() { - return OuterScopeInfoIndex() + (HasOuterScopeInfo() ? 1 : 0); -} - -int ScopeInfo::ModuleVariableCountIndex() { return ModuleInfoIndex() + 1; } - -int ScopeInfo::ModuleVariablesIndex() { return ModuleVariableCountIndex() + 1; } - -void ScopeInfo::ModuleVariable(int i, String** name, int* index, - VariableMode* mode, - InitializationFlag* init_flag, - MaybeAssignedFlag* maybe_assigned_flag) { - DCHECK_LE(0, i); - DCHECK_LT(i, Smi::cast(get(ModuleVariableCountIndex()))->value()); - - int entry = ModuleVariablesIndex() + i * kModuleVariableEntryLength; - int properties = - Smi::cast(get(entry + kModuleVariablePropertiesOffset))->value(); - - if (name != nullptr) { - *name = String::cast(get(entry + kModuleVariableNameOffset)); - } - if (index != nullptr) { - *index = Smi::cast(get(entry + kModuleVariableIndexOffset))->value(); - DCHECK_NE(*index, 0); - } - if (mode != nullptr) { - *mode = VariableModeField::decode(properties); - } - if (init_flag != nullptr) { - *init_flag = InitFlagField::decode(properties); - } - if (maybe_assigned_flag != nullptr) { - *maybe_assigned_flag = MaybeAssignedFlagField::decode(properties); - } -} - -#ifdef DEBUG - -static void PrintList(const char* list_name, - int nof_internal_slots, - int start, - int end, - ScopeInfo* scope_info) { - if (start < end) { - PrintF("\n // %s\n", list_name); - if (nof_internal_slots > 0) { - PrintF(" %2d - %2d [internal slots]\n", 0 , nof_internal_slots - 1); - } - for (int i = nof_internal_slots; start < end; ++i, ++start) { - PrintF(" %2d ", i); - String::cast(scope_info->get(start))->ShortPrint(); - PrintF("\n"); - } - } -} - - -void ScopeInfo::Print() { - PrintF("ScopeInfo "); - if (HasFunctionName()) { - FunctionName()->ShortPrint(); - } else { - PrintF("/* no function name */"); - } - PrintF("{"); - - if (length() > 0) { - PrintList("parameters", 0, ParameterNamesIndex(), - ParameterNamesIndex() + ParameterCount(), this); - PrintList("stack slots", 0, StackLocalNamesIndex(), - StackLocalNamesIndex() + StackLocalCount(), this); - PrintList("context slots", Context::MIN_CONTEXT_SLOTS, - ContextLocalNamesIndex(), - ContextLocalNamesIndex() + ContextLocalCount(), this); - // TODO(neis): Print module stuff if present. - } - - PrintF("}\n"); -} -#endif // DEBUG - -Handle<ModuleInfoEntry> ModuleInfoEntry::New(Isolate* isolate, - Handle<Object> export_name, - Handle<Object> local_name, - Handle<Object> import_name, - int module_request, int cell_index, - int beg_pos, int end_pos) { - Handle<ModuleInfoEntry> result = Handle<ModuleInfoEntry>::cast( - isolate->factory()->NewStruct(MODULE_INFO_ENTRY_TYPE)); - result->set_export_name(*export_name); - result->set_local_name(*local_name); - result->set_import_name(*import_name); - result->set_module_request(module_request); - result->set_cell_index(cell_index); - result->set_beg_pos(beg_pos); - result->set_end_pos(end_pos); - return result; -} - -Handle<ModuleInfo> ModuleInfo::New(Isolate* isolate, Zone* zone, - ModuleDescriptor* descr) { - // Serialize module requests. - Handle<FixedArray> module_requests = isolate->factory()->NewFixedArray( - static_cast<int>(descr->module_requests().size())); - for (const auto& elem : descr->module_requests()) { - module_requests->set(elem.second, *elem.first->string()); - } - - // Serialize special exports. - Handle<FixedArray> special_exports = - isolate->factory()->NewFixedArray(descr->special_exports().length()); - { - int i = 0; - for (auto entry : descr->special_exports()) { - Handle<ModuleInfoEntry> serialized_entry = entry->Serialize(isolate); - special_exports->set(i++, *serialized_entry); - } - } - - // Serialize namespace imports. - Handle<FixedArray> namespace_imports = - isolate->factory()->NewFixedArray(descr->namespace_imports().length()); - { - int i = 0; - for (auto entry : descr->namespace_imports()) { - Handle<ModuleInfoEntry> serialized_entry = entry->Serialize(isolate); - namespace_imports->set(i++, *serialized_entry); - } - } - - // Serialize regular exports. - Handle<FixedArray> regular_exports = - descr->SerializeRegularExports(isolate, zone); - - // Serialize regular imports. - Handle<FixedArray> regular_imports = isolate->factory()->NewFixedArray( - static_cast<int>(descr->regular_imports().size())); - { - int i = 0; - for (const auto& elem : descr->regular_imports()) { - Handle<ModuleInfoEntry> serialized_entry = - elem.second->Serialize(isolate); - regular_imports->set(i++, *serialized_entry); - } - } - - Handle<ModuleInfo> result = isolate->factory()->NewModuleInfo(); - result->set(kModuleRequestsIndex, *module_requests); - result->set(kSpecialExportsIndex, *special_exports); - result->set(kRegularExportsIndex, *regular_exports); - result->set(kNamespaceImportsIndex, *namespace_imports); - result->set(kRegularImportsIndex, *regular_imports); - return result; -} - -int ModuleInfo::RegularExportCount() const { - DCHECK_EQ(regular_exports()->length() % kRegularExportLength, 0); - return regular_exports()->length() / kRegularExportLength; -} - -String* ModuleInfo::RegularExportLocalName(int i) const { - return String::cast(regular_exports()->get(i * kRegularExportLength + - kRegularExportLocalNameOffset)); -} - -int ModuleInfo::RegularExportCellIndex(int i) const { - return Smi::cast(regular_exports()->get(i * kRegularExportLength + - kRegularExportCellIndexOffset)) - ->value(); -} - -FixedArray* ModuleInfo::RegularExportExportNames(int i) const { - return FixedArray::cast(regular_exports()->get( - i * kRegularExportLength + kRegularExportExportNamesOffset)); -} - -Handle<ModuleInfoEntry> ModuleInfo::LookupRegularImport( - Handle<ModuleInfo> info, Handle<String> local_name) { - Isolate* isolate = info->GetIsolate(); - Handle<FixedArray> regular_imports(info->regular_imports(), isolate); - for (int i = 0, n = regular_imports->length(); i < n; ++i) { - Handle<ModuleInfoEntry> entry( - ModuleInfoEntry::cast(regular_imports->get(i)), isolate); - if (String::cast(entry->local_name())->Equals(*local_name)) { - return entry; - } - } - UNREACHABLE(); - return Handle<ModuleInfoEntry>(); -} - -} // namespace internal -} // namespace v8 diff --git a/deps/v8/src/ast/scopes.cc b/deps/v8/src/ast/scopes.cc index c1679a40b8..b61bcdab55 100644 --- a/deps/v8/src/ast/scopes.cc +++ b/deps/v8/src/ast/scopes.cc @@ -9,12 +9,27 @@ #include "src/accessors.h" #include "src/ast/ast.h" #include "src/bootstrapper.h" +#include "src/counters.h" #include "src/messages.h" +#include "src/objects-inl.h" +#include "src/objects/module-info.h" #include "src/parsing/parse-info.h" namespace v8 { namespace internal { +namespace { +void* kDummyPreParserVariable = reinterpret_cast<void*>(0x1); +void* kDummyPreParserLexicalVariable = reinterpret_cast<void*>(0x2); + +bool IsLexical(Variable* variable) { + if (variable == kDummyPreParserLexicalVariable) return true; + if (variable == kDummyPreParserVariable) return false; + return IsLexicalVariableMode(variable->mode()); +} + +} // namespace + // ---------------------------------------------------------------------------- // Implementation of LocalsMap // @@ -49,6 +64,19 @@ Variable* VariableMap::Declare(Zone* zone, Scope* scope, return reinterpret_cast<Variable*>(p->value); } +void VariableMap::DeclareName(Zone* zone, const AstRawString* name, + VariableMode mode) { + Entry* p = + ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->hash(), + ZoneAllocationPolicy(zone)); + if (p->value == nullptr) { + // The variable has not been declared yet -> insert it. + DCHECK_EQ(name, p->key); + p->value = + mode == VAR ? kDummyPreParserVariable : kDummyPreParserLexicalVariable; + } +} + void VariableMap::Remove(Variable* var) { const AstRawString* name = var->raw_name(); ZoneHashMap::Remove(const_cast<AstRawString*>(name), name->hash()); @@ -74,21 +102,27 @@ Variable* VariableMap::Lookup(const AstRawString* name) { return NULL; } +void SloppyBlockFunctionMap::Delegate::set_statement(Statement* statement) { + if (statement_ != nullptr) { + statement_->set_statement(statement); + } +} + SloppyBlockFunctionMap::SloppyBlockFunctionMap(Zone* zone) : ZoneHashMap(8, ZoneAllocationPolicy(zone)) {} -void SloppyBlockFunctionMap::Declare(Zone* zone, const AstRawString* name, - SloppyBlockFunctionStatement* stmt) { +void SloppyBlockFunctionMap::Declare( + Zone* zone, const AstRawString* name, + SloppyBlockFunctionMap::Delegate* delegate) { // AstRawStrings are unambiguous, i.e., the same string is always represented // by the same AstRawString*. Entry* p = ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->hash(), ZoneAllocationPolicy(zone)); - stmt->set_next(static_cast<SloppyBlockFunctionStatement*>(p->value)); - p->value = stmt; + delegate->set_next(static_cast<SloppyBlockFunctionMap::Delegate*>(p->value)); + p->value = delegate; } - // ---------------------------------------------------------------------------- // Implementation of Scope @@ -243,8 +277,7 @@ 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, this, catch_variable_name, VAR, - NORMAL_VARIABLE, kCreatedInitialized); + Variable* variable = Declare(zone, catch_variable_name, VAR); AllocateHeapSlot(variable); } @@ -263,7 +296,14 @@ void DeclarationScope::SetDefaults() { arguments_ = nullptr; this_function_ = nullptr; should_eager_compile_ = false; - is_lazily_parsed_ = false; + was_lazily_parsed_ = false; +#ifdef DEBUG + DeclarationScope* outer_declaration_scope = + outer_scope_ ? outer_scope_->GetDeclarationScope() : nullptr; + is_being_lazily_parsed_ = + outer_declaration_scope ? outer_declaration_scope->is_being_lazily_parsed_ + : false; +#endif } void Scope::SetDefaults() { @@ -305,7 +345,7 @@ bool DeclarationScope::ShouldEagerCompile() const { } void DeclarationScope::set_should_eager_compile() { - should_eager_compile_ = !is_lazily_parsed_; + should_eager_compile_ = !was_lazily_parsed_; } void DeclarationScope::set_asm_module() { @@ -354,17 +394,16 @@ Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone, } DCHECK(!scope_info->HasOuterScopeInfo()); break; - } else if (scope_info->scope_type() == FUNCTION_SCOPE || - scope_info->scope_type() == EVAL_SCOPE) { - // TODO(neis): For an eval scope, we currently create an ordinary function - // context. This is wrong and needs to be fixed. - // https://bugs.chromium.org/p/v8/issues/detail?id=5295 + } else if (scope_info->scope_type() == FUNCTION_SCOPE) { outer_scope = new (zone) DeclarationScope(zone, FUNCTION_SCOPE, handle(scope_info)); if (scope_info->IsAsmFunction()) outer_scope->AsDeclarationScope()->set_asm_function(); if (scope_info->IsAsmModule()) outer_scope->AsDeclarationScope()->set_asm_module(); + } else if (scope_info->scope_type() == EVAL_SCOPE) { + outer_scope = + new (zone) DeclarationScope(zone, EVAL_SCOPE, handle(scope_info)); } else if (scope_info->scope_type() == BLOCK_SCOPE) { if (scope_info->is_declaration_scope()) { outer_scope = @@ -424,11 +463,21 @@ int Scope::num_parameters() const { return is_declaration_scope() ? AsDeclarationScope()->num_parameters() : 0; } +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); +} + void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { DCHECK(is_sloppy(language_mode())); DCHECK(is_function_scope() || is_eval_scope() || is_script_scope() || (is_block_scope() && outer_scope()->is_function_scope())); - DCHECK(HasSimpleParameters() || is_block_scope()); + DCHECK(HasSimpleParameters() || is_block_scope() || is_being_lazily_parsed_); + DCHECK_EQ(factory == nullptr, is_being_lazily_parsed_); + bool has_simple_parameters = HasSimpleParameters(); // For each variable which is used as a function declaration in a sloppy // block, @@ -460,7 +509,7 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { bool var_created = false; // Write in assignments to var for each block-scoped function declaration - auto delegates = static_cast<SloppyBlockFunctionStatement*>(p->value); + auto delegates = static_cast<SloppyBlockFunctionMap::Delegate*>(p->value); DeclarationScope* decl_scope = this; while (decl_scope->is_eval_scope()) { @@ -468,7 +517,7 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { } Scope* outer_scope = decl_scope->outer_scope(); - for (SloppyBlockFunctionStatement* delegate = delegates; + for (SloppyBlockFunctionMap::Delegate* delegate = delegates; delegate != nullptr; delegate = delegate->next()) { // Check if there's a conflict with a lexical declaration Scope* query_scope = delegate->scope()->outer_scope(); @@ -482,7 +531,7 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { // `{ let e; try {} catch (e) { function e(){} } }` do { var = query_scope->LookupLocal(name); - if (var != nullptr && IsLexicalVariableMode(var->mode())) { + if (var != nullptr && IsLexical(var)) { should_hoist = false; break; } @@ -494,30 +543,39 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { // Declare a var-style binding for the function in the outer scope if (!var_created) { var_created = true; - VariableProxy* proxy = factory->NewVariableProxy(name, NORMAL_VARIABLE); - Declaration* 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; - DeclareVariable(declaration, VAR, - Variable::DefaultInitializationFlag(VAR), false, - nullptr, &ok); - CHECK(ok); // Based on the preceding check, this should not fail + if (factory) { + 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; + DeclareVariable(declaration, VAR, + Variable::DefaultInitializationFlag(VAR), false, + nullptr, &ok); + CHECK(ok); // Based on the preceding check, this should not fail + } else { + DeclareVariableName(name, VAR); + } } - 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); + if (factory) { + 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); + } } } } void DeclarationScope::Analyze(ParseInfo* info, AnalyzeMode mode) { + RuntimeCallTimerScope runtimeTimer(info->isolate(), + &RuntimeCallStats::CompileScopeAnalysis); DCHECK(info->literal() != NULL); DeclarationScope* scope = info->literal()->scope(); @@ -542,13 +600,15 @@ void DeclarationScope::Analyze(ParseInfo* info, AnalyzeMode mode) { scope->HoistSloppyBlockFunctions(&factory); } - // We are compiling one of three cases: + // We are compiling one of four cases: // 1) top-level code, // 2) a function/eval/module on the top-level // 3) a function/eval in a scope that was already resolved. + // 4) an asm.js function DCHECK(scope->scope_type() == SCRIPT_SCOPE || scope->outer_scope()->scope_type() == SCRIPT_SCOPE || - scope->outer_scope()->already_resolved_); + scope->outer_scope()->already_resolved_ || + (info->asm_function_scope() && scope->is_function_scope())); // The outer scope is never lazy. scope->set_should_eager_compile(); @@ -577,11 +637,11 @@ void DeclarationScope::DeclareThis(AstValueFactory* ast_value_factory) { DCHECK(is_declaration_scope()); DCHECK(has_this_declaration()); - bool subclass_constructor = IsSubclassConstructor(function_kind_); - Variable* var = Declare( - zone(), this, ast_value_factory->this_string(), - subclass_constructor ? CONST : VAR, THIS_VARIABLE, - subclass_constructor ? kNeedsInitialization : kCreatedInitialized); + bool derived_constructor = IsDerivedConstructor(function_kind_); + Variable* var = + Declare(zone(), ast_value_factory->this_string(), + derived_constructor ? CONST : VAR, THIS_VARIABLE, + derived_constructor ? kNeedsInitialization : kCreatedInitialized); receiver_ = var; } @@ -594,8 +654,7 @@ void DeclarationScope::DeclareArguments(AstValueFactory* ast_value_factory) { // Declare 'arguments' variable which exists in all non arrow functions. // Note that it might never be accessed, in which case it won't be // allocated during variable allocation. - arguments_ = Declare(zone(), this, ast_value_factory->arguments_string(), - VAR, NORMAL_VARIABLE, kCreatedInitialized); + arguments_ = Declare(zone(), ast_value_factory->arguments_string(), VAR); } else if (IsLexicalVariableMode(arguments_->mode())) { // Check if there's lexically declared variable named arguments to avoid // redeclaration. See ES#sec-functiondeclarationinstantiation, step 20. @@ -609,14 +668,12 @@ void DeclarationScope::DeclareDefaultFunctionVariables( DCHECK(!is_arrow_scope()); DeclareThis(ast_value_factory); - new_target_ = Declare(zone(), this, ast_value_factory->new_target_string(), - CONST, NORMAL_VARIABLE, kCreatedInitialized); + new_target_ = Declare(zone(), ast_value_factory->new_target_string(), CONST); if (IsConciseMethod(function_kind_) || IsClassConstructor(function_kind_) || IsAccessorFunction(function_kind_)) { this_function_ = - Declare(zone(), this, ast_value_factory->this_function_string(), CONST, - NORMAL_VARIABLE, kCreatedInitialized); + Declare(zone(), ast_value_factory->this_function_string(), CONST); } } @@ -637,23 +694,12 @@ Variable* DeclarationScope::DeclareFunctionVar(const AstRawString* name) { } bool Scope::HasBeenRemoved() const { - // TODO(neis): Store this information somewhere instead of calculating it. - - if (!is_block_scope()) return false; // Shortcut. - - Scope* parent = outer_scope(); - if (parent == nullptr) { - DCHECK(is_script_scope()); - return false; - } - - Scope* sibling = parent->inner_scope(); - for (; sibling != nullptr; sibling = sibling->sibling()) { - if (sibling == this) return false; + if (sibling() == this) { + DCHECK_NULL(inner_scope_); + DCHECK(is_block_scope()); + return true; } - - DCHECK_NULL(inner_scope_); - return true; + return false; } Scope* Scope::GetUnremovedScope() { @@ -667,6 +713,7 @@ Scope* Scope::GetUnremovedScope() { Scope* Scope::FinalizeBlockScope() { DCHECK(is_block_scope()); + DCHECK(!HasBeenRemoved()); if (variables_.occupancy() > 0 || (is_declaration_scope() && calls_sloppy_eval())) { @@ -705,7 +752,12 @@ Scope* Scope::FinalizeBlockScope() { PropagateUsageFlagsToScope(outer_scope_); // This block does not need a context. num_heap_slots_ = 0; - return NULL; + + // Mark scope as removed by making it its own sibling. + sibling_ = this; + DCHECK(HasBeenRemoved()); + + return nullptr; } void DeclarationScope::AddLocal(Variable* var) { @@ -715,13 +767,13 @@ void DeclarationScope::AddLocal(Variable* var) { locals_.Add(var); } -Variable* Scope::Declare(Zone* zone, Scope* scope, const AstRawString* name, +Variable* Scope::Declare(Zone* zone, const AstRawString* name, VariableMode mode, VariableKind kind, InitializationFlag initialization_flag, MaybeAssignedFlag maybe_assigned_flag) { bool added; Variable* var = - variables_.Declare(zone, scope, name, mode, kind, initialization_flag, + variables_.Declare(zone, this, name, mode, kind, initialization_flag, maybe_assigned_flag, &added); if (added) locals_.Add(var); return var; @@ -796,6 +848,7 @@ void Scope::PropagateUsageFlagsToScope(Scope* 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) { @@ -869,12 +922,13 @@ Variable* DeclarationScope::DeclareParameter( DCHECK(is_function_scope() || is_module_scope()); DCHECK(!has_rest_); DCHECK(!is_optional || !is_rest); + DCHECK(!is_being_lazily_parsed_); + DCHECK(!was_lazily_parsed_); Variable* var; if (mode == TEMPORARY) { var = NewTemporary(name); } else { - var = - Declare(zone(), this, name, mode, NORMAL_VARIABLE, kCreatedInitialized); + var = Declare(zone(), name, mode); // TODO(wingo): Avoid O(n^2) check. *is_duplicate = IsDeclaredParameter(name); } @@ -894,8 +948,9 @@ Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode, // introduced during variable allocation, and TEMPORARY variables are // allocated via NewTemporary(). DCHECK(IsDeclaredVariableMode(mode)); - return Declare(zone(), this, name, mode, kind, init_flag, - maybe_assigned_flag); + DCHECK(!GetDeclarationScope()->is_being_lazily_parsed()); + DCHECK(!GetDeclarationScope()->was_lazily_parsed()); + return Declare(zone(), name, mode, kind, init_flag, maybe_assigned_flag); } Variable* Scope::DeclareVariable( @@ -904,6 +959,8 @@ Variable* Scope::DeclareVariable( bool* sloppy_mode_block_scope_function_redefinition, bool* ok) { DCHECK(IsDeclaredVariableMode(mode)); DCHECK(!already_resolved_); + DCHECK(!GetDeclarationScope()->is_being_lazily_parsed()); + DCHECK(!GetDeclarationScope()->was_lazily_parsed()); if (mode == VAR && !is_declaration_scope()) { return GetDeclarationScope()->DeclareVariable( @@ -1002,6 +1059,28 @@ Variable* Scope::DeclareVariable( return var; } +void Scope::DeclareVariableName(const AstRawString* name, VariableMode mode) { + DCHECK(IsDeclaredVariableMode(mode)); + DCHECK(!already_resolved_); + DCHECK(GetDeclarationScope()->is_being_lazily_parsed()); + + if (mode == VAR && !is_declaration_scope()) { + return GetDeclarationScope()->DeclareVariableName(name, mode); + } + DCHECK(!is_with_scope()); + DCHECK(!is_eval_scope()); + // Unlike DeclareVariable, DeclareVariableName allows declaring variables in + // catch scopes: Parser::RewriteCatchPattern bypasses DeclareVariable by + // calling DeclareLocal directly, and it doesn't make sense to add a similar + // bypass mechanism for PreParser. + DCHECK(is_declaration_scope() || (IsLexicalVariableMode(mode) && + (is_block_scope() || is_catch_scope()))); + DCHECK(scope_info_.is_null()); + + // Declare the variable in the declaration scope. + variables_.DeclareName(zone(), name, mode); +} + VariableProxy* Scope::NewUnresolved(AstNodeFactory* factory, const AstRawString* name, int start_position, VariableKind kind) { @@ -1009,7 +1088,7 @@ VariableProxy* Scope::NewUnresolved(AstNodeFactory* factory, // the same name because they may be removed selectively via // RemoveUnresolved(). DCHECK(!already_resolved_); - DCHECK_EQ(!needs_migration_, factory->zone() == zone()); + DCHECK_EQ(factory->zone(), zone()); VariableProxy* proxy = factory->NewVariableProxy(name, kind, start_position); proxy->set_next_unresolved(unresolved_); unresolved_ = proxy; @@ -1026,8 +1105,7 @@ void Scope::AddUnresolved(VariableProxy* proxy) { Variable* DeclarationScope::DeclareDynamicGlobal(const AstRawString* name, VariableKind kind) { DCHECK(is_script_scope()); - return variables_.Declare(zone(), this, name, DYNAMIC_GLOBAL, kind, - kCreatedInitialized); + return variables_.Declare(zone(), this, name, DYNAMIC_GLOBAL, kind); } @@ -1050,26 +1128,6 @@ bool Scope::RemoveUnresolved(VariableProxy* var) { return false; } -bool Scope::RemoveUnresolved(const AstRawString* name) { - if (unresolved_ != nullptr && unresolved_->raw_name() == name) { - VariableProxy* removed = unresolved_; - unresolved_ = unresolved_->next_unresolved(); - removed->set_next_unresolved(nullptr); - return true; - } - VariableProxy* current = unresolved_; - while (current != nullptr) { - VariableProxy* next = current->next_unresolved(); - if (next != nullptr && next->raw_name() == name) { - current->set_next_unresolved(next->next_unresolved()); - next->set_next_unresolved(nullptr); - return true; - } - current = next; - } - return false; -} - Variable* Scope::NewTemporary(const AstRawString* name) { DeclarationScope* scope = GetClosureScope(); Variable* var = new (zone()) @@ -1157,9 +1215,9 @@ bool Scope::AllowsLazyParsingWithoutUnresolvedVariables( // guaranteed to be correct. for (const Scope* s = this; s != outer; s = s->outer_scope_) { // Eval forces context allocation on all outer scopes, so we don't need to - // look at those scopes. Sloppy eval makes all top-level variables dynamic, - // whereas strict-mode requires context allocation. - if (s->is_eval_scope()) return !is_strict(s->language_mode()); + // look at those scopes. Sloppy eval makes top-level non-lexical variables + // dynamic, whereas strict-mode requires context allocation. + if (s->is_eval_scope()) return is_sloppy(s->language_mode()); // Catch scopes force context allocation of all variables. if (s->is_catch_scope()) continue; // With scopes do not introduce variables that need allocation. @@ -1276,7 +1334,7 @@ Scope* Scope::GetOuterScopeWithContext() { Handle<StringSet> DeclarationScope::CollectNonLocals( ParseInfo* info, Handle<StringSet> non_locals) { - VariableProxy* free_variables = FetchFreeVariables(this, true, info); + VariableProxy* free_variables = FetchFreeVariables(this, info); for (VariableProxy* proxy = free_variables; proxy != nullptr; proxy = proxy->next_unresolved()) { non_locals = StringSet::Add(non_locals, proxy->name()); @@ -1292,21 +1350,30 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory, params_.Clear(); decls_.Clear(); locals_.Clear(); - sloppy_block_function_map_.Clear(); - variables_.Clear(); - // Make sure we won't walk the scope tree from here on. inner_scope_ = nullptr; unresolved_ = nullptr; - if (aborted && !IsArrowFunction(function_kind_)) { - DeclareDefaultFunctionVariables(ast_value_factory); + 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); + } + } else { + // Make sure this scope isn't used for allocation anymore. + zone_ = nullptr; + variables_.Invalidate(); + sloppy_block_function_map_.Invalidate(); } #ifdef DEBUG needs_migration_ = false; + is_being_lazily_parsed_ = false; #endif - is_lazily_parsed_ = !aborted; + was_lazily_parsed_ = !aborted; } void DeclarationScope::AnalyzePartially(AstNodeFactory* ast_node_factory) { @@ -1317,9 +1384,8 @@ void DeclarationScope::AnalyzePartially(AstNodeFactory* ast_node_factory) { // Try to resolve unresolved variables for this Scope and migrate those // which cannot be resolved inside. It doesn't make sense to try to resolve // them in the outer Scopes here, because they are incomplete. - for (VariableProxy* proxy = - FetchFreeVariables(this, !FLAG_lazy_inner_functions); - proxy != nullptr; proxy = proxy->next_unresolved()) { + for (VariableProxy* proxy = FetchFreeVariables(this); proxy != nullptr; + proxy = proxy->next_unresolved()) { DCHECK(!proxy->is_resolved()); VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy); copy->set_next_unresolved(unresolved); @@ -1339,8 +1405,10 @@ void DeclarationScope::AnalyzePartially(AstNodeFactory* ast_node_factory) { } #ifdef DEBUG -static const char* Header(ScopeType scope_type, FunctionKind function_kind, - bool is_declaration_scope) { +namespace { + +const char* Header(ScopeType scope_type, FunctionKind function_kind, + bool is_declaration_scope) { switch (scope_type) { case EVAL_SCOPE: return "eval"; // TODO(adamk): Should we print concise method scopes specially? @@ -1359,18 +1427,13 @@ static const char* Header(ScopeType scope_type, FunctionKind function_kind, return NULL; } +void Indent(int n, const char* str) { PrintF("%*s%s", n, "", str); } -static void Indent(int n, const char* str) { - PrintF("%*s%s", n, "", str); -} - - -static void PrintName(const AstRawString* name) { +void PrintName(const AstRawString* name) { PrintF("%.*s", name->length(), name->raw_data()); } - -static void PrintLocation(Variable* var) { +void PrintLocation(Variable* var) { switch (var->location()) { case VariableLocation::UNALLOCATED: break; @@ -1392,45 +1455,48 @@ static void PrintLocation(Variable* var) { } } - -static void PrintVar(int indent, Variable* var) { - if (var->is_used() || !var->IsUnallocated()) { - Indent(indent, VariableMode2String(var->mode())); - PrintF(" "); - if (var->raw_name()->IsEmpty()) - PrintF(".%p", reinterpret_cast<void*>(var)); - else - PrintName(var->raw_name()); - PrintF("; // "); - PrintLocation(var); - bool comma = !var->IsUnallocated(); - if (var->has_forced_context_allocation()) { - if (comma) PrintF(", "); - PrintF("forced context allocation"); - comma = true; - } - if (var->maybe_assigned() == kNotAssigned) { - if (comma) PrintF(", "); - PrintF("never assigned"); - } - PrintF("\n"); +void PrintVar(int indent, Variable* var) { + Indent(indent, VariableMode2String(var->mode())); + PrintF(" "); + if (var->raw_name()->IsEmpty()) + PrintF(".%p", reinterpret_cast<void*>(var)); + else + PrintName(var->raw_name()); + PrintF("; // "); + PrintLocation(var); + bool comma = !var->IsUnallocated(); + if (var->has_forced_context_allocation()) { + if (comma) PrintF(", "); + PrintF("forced context allocation"); + comma = true; + } + if (var->maybe_assigned() == kNotAssigned) { + if (comma) PrintF(", "); + PrintF("never assigned"); } + PrintF("\n"); } -static void PrintMap(int indent, VariableMap* map, bool locals) { +void PrintMap(int indent, const char* label, VariableMap* map, bool locals, + Variable* function_var) { + bool printed_label = false; for (VariableMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) { Variable* var = reinterpret_cast<Variable*>(p->value); + if (var == function_var) continue; bool local = !IsDynamicVariableMode(var->mode()); - if (locals ? local : !local) { - if (var == nullptr) { - Indent(indent, "<?>\n"); - } else { - PrintVar(indent, var); + if ((locals ? local : !local) && + (var->is_used() || !var->IsUnallocated())) { + if (!printed_label) { + Indent(indent, label); + printed_label = true; } + PrintVar(indent, var); } } } +} // anonymous namespace + void DeclarationScope::PrintParameters() { PrintF(" ("); for (int i = 0; i < params_.length(); i++) { @@ -1487,9 +1553,12 @@ void Scope::Print(int n) { if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n"); if (is_declaration_scope()) { DeclarationScope* scope = AsDeclarationScope(); - if (scope->is_lazily_parsed()) Indent(n1, "// lazily parsed\n"); + if (scope->was_lazily_parsed()) Indent(n1, "// lazily parsed\n"); if (scope->ShouldEagerCompile()) Indent(n1, "// will be compiled\n"); } + if (has_forced_context_allocation()) { + Indent(n1, "// forces context allocation\n"); + } if (num_stack_slots_ > 0) { Indent(n1, "// "); PrintF("%d stack slots\n", num_stack_slots_); @@ -1505,12 +1574,22 @@ void Scope::Print(int n) { PrintVar(n1, function); } - if (variables_.Start() != NULL) { - Indent(n1, "// local vars:\n"); - PrintMap(n1, &variables_, true); + // Print temporaries. + { + bool printed_header = false; + for (Variable* local : locals_) { + if (local->mode() != TEMPORARY) continue; + if (!printed_header) { + printed_header = true; + Indent(n1, "// temporary vars:\n"); + } + PrintVar(n1, local); + } + } - Indent(n1, "// dynamic vars:\n"); - PrintMap(n1, &variables_, false); + if (variables_.occupancy() > 0) { + PrintMap(n1, "// local vars:\n", &variables_, true, function); + PrintMap(n1, "// dynamic vars:\n", &variables_, false, function); } // Print inner scopes (disable by providing negative n). @@ -1539,6 +1618,12 @@ void Scope::CheckScopePositions() { void Scope::CheckZones() { DCHECK(!needs_migration_); for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { + if (scope->is_declaration_scope() && + scope->AsDeclarationScope()->was_lazily_parsed()) { + DCHECK_NULL(scope->zone()); + DCHECK_NULL(scope->inner_scope_); + continue; + } CHECK_EQ(scope->zone(), zone()); scope->CheckZones(); } @@ -1548,8 +1633,7 @@ void Scope::CheckZones() { Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) { // Declare a new non-local. DCHECK(IsDynamicVariableMode(mode)); - Variable* var = variables_.Declare(zone(), NULL, name, mode, NORMAL_VARIABLE, - kCreatedInitialized); + Variable* var = variables_.Declare(zone(), nullptr, name, mode); // Allocate it by giving it a dynamic lookup. var->AllocateTo(VariableLocation::LOOKUP, -1); return var; @@ -1590,6 +1674,13 @@ Variable* Scope::LookupRecursive(VariableProxy* proxy, Scope* outer_scope_end) { // The variable could not be resolved statically. if (var == nullptr) return var; + // TODO(marja): Separate LookupRecursive for preparsed scopes better. + if (var == kDummyPreParserVariable || var == kDummyPreParserLexicalVariable) { + DCHECK(GetDeclarationScope()->is_being_lazily_parsed()); + DCHECK(FLAG_lazy_inner_functions); + return var; + } + if (is_function_scope() && !var->is_dynamic()) { var->ForceContextAllocation(); } @@ -1641,34 +1732,20 @@ void Scope::ResolveVariable(ParseInfo* info, VariableProxy* proxy) { DCHECK(!proxy->is_resolved()); Variable* var = LookupRecursive(proxy, nullptr); ResolveTo(info, proxy, var); - - if (FLAG_lazy_inner_functions) { - if (info != nullptr && info->is_native()) return; - // Pessimistically force context allocation for all variables to which inner - // scope variables could potentially resolve to. - Scope* scope = GetClosureScope()->outer_scope_; - while (scope != nullptr && scope->scope_info_.is_null()) { - var = scope->LookupLocal(proxy->raw_name()); - if (var != nullptr) { - // Since we don't lazy parse inner arrow functions, inner functions - // cannot refer to the outer "this". - if (!var->is_dynamic() && !var->is_this() && - !var->has_forced_context_allocation()) { - var->ForceContextAllocation(); - var->set_is_used(); - // We don't know what the (potentially lazy parsed) inner function - // does with the variable; pessimistically assume that it's assigned. - var->set_maybe_assigned(); - } - } - scope = scope->outer_scope_; - } - } } namespace { bool AccessNeedsHoleCheck(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); + } + if (!var->binding_needs_init()) { return false; } @@ -1703,8 +1780,7 @@ bool AccessNeedsHoleCheck(Variable* var, VariableProxy* proxy, Scope* scope) { } if (var->is_this()) { - DCHECK( - IsSubclassConstructor(scope->GetDeclarationScope()->function_kind())); + DCHECK(IsDerivedConstructor(scope->GetDeclarationScope()->function_kind())); // TODO(littledan): implement 'this' hole check elimination. return true; } @@ -1749,37 +1825,65 @@ void Scope::ResolveTo(ParseInfo* info, VariableProxy* proxy, Variable* var) { void Scope::ResolveVariablesRecursively(ParseInfo* info) { DCHECK(info->script_scope()->is_script_scope()); + // Lazy parsed declaration scopes are already partially analyzed. If there are + // unresolved references remaining, they just need to be resolved in outer + // scopes. + if (is_declaration_scope() && AsDeclarationScope()->was_lazily_parsed()) { + DCHECK(variables_.occupancy() == 0); + for (VariableProxy* proxy = unresolved_; proxy != nullptr; + proxy = proxy->next_unresolved()) { + Variable* var = outer_scope()->LookupRecursive(proxy, nullptr); + if (!var->is_dynamic()) { + var->set_is_used(); + var->ForceContextAllocation(); + if (proxy->is_assigned()) var->set_maybe_assigned(); + } + } + } else { + // Resolve unresolved variables for this scope. + for (VariableProxy* proxy = unresolved_; proxy != nullptr; + proxy = proxy->next_unresolved()) { + ResolveVariable(info, proxy); + } - // Resolve unresolved variables for this scope. - for (VariableProxy* proxy = unresolved_; proxy != nullptr; - proxy = proxy->next_unresolved()) { - ResolveVariable(info, proxy); - } - - // Resolve unresolved variables for inner scopes. - for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { - scope->ResolveVariablesRecursively(info); + // Resolve unresolved variables for inner scopes. + for (Scope* scope = inner_scope_; scope != nullptr; + scope = scope->sibling_) { + scope->ResolveVariablesRecursively(info); + } } } VariableProxy* Scope::FetchFreeVariables(DeclarationScope* max_outer_scope, - bool try_to_resolve, ParseInfo* info, + ParseInfo* info, VariableProxy* stack) { + // Lazy parsed declaration scopes are already partially analyzed. If there are + // unresolved references remaining, they just need to be resolved in outer + // scopes. + Scope* lookup = + is_declaration_scope() && AsDeclarationScope()->was_lazily_parsed() + ? outer_scope() + : this; for (VariableProxy *proxy = unresolved_, *next = nullptr; proxy != nullptr; proxy = next) { next = proxy->next_unresolved(); DCHECK(!proxy->is_resolved()); - Variable* var = nullptr; - if (try_to_resolve) { - var = LookupRecursive(proxy, max_outer_scope->outer_scope()); - } + Variable* var = + lookup->LookupRecursive(proxy, max_outer_scope->outer_scope()); if (var == nullptr) { proxy->set_next_unresolved(stack); stack = proxy; - } else if (info != nullptr) { - ResolveTo(info, proxy, var); - } else { - var->set_is_used(); + } else if (var != kDummyPreParserVariable && + var != kDummyPreParserLexicalVariable) { + if (info != nullptr) { + // In this case we need to leave scopes in a way that they can be + // allocated. If we resolved variables from lazy parsed scopes, we need + // to context allocate the var. + ResolveTo(info, proxy, var); + if (!var->is_dynamic() && lookup != this) var->ForceContextAllocation(); + } else { + var->set_is_used(); + } } } @@ -1787,8 +1891,7 @@ VariableProxy* Scope::FetchFreeVariables(DeclarationScope* max_outer_scope, unresolved_ = nullptr; for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { - stack = - scope->FetchFreeVariables(max_outer_scope, try_to_resolve, info, stack); + stack = scope->FetchFreeVariables(max_outer_scope, info, stack); } return stack; @@ -1823,7 +1926,10 @@ bool Scope::MustAllocateInContext(Variable* var) { if (has_forced_context_allocation()) return true; if (var->mode() == TEMPORARY) return false; if (is_catch_scope()) return true; - if (is_script_scope() && IsLexicalVariableMode(var->mode())) return true; + if ((is_script_scope() || is_eval_scope()) && + IsLexicalVariableMode(var->mode())) { + return true; + } return var->has_forced_context_allocation() || inner_scope_calls_eval_; } @@ -1880,6 +1986,7 @@ void DeclarationScope::AllocateParameterLocals() { DCHECK_EQ(this, var->scope()); if (uses_sloppy_arguments) { var->set_is_used(); + var->set_maybe_assigned(); var->ForceContextAllocation(); } AllocateParameter(var, i); @@ -1969,7 +2076,7 @@ void Scope::AllocateVariablesRecursively() { DCHECK(!already_resolved_); DCHECK_EQ(0, num_stack_slots_); // Don't allocate variables of preparsed scopes. - if (is_declaration_scope() && AsDeclarationScope()->is_lazily_parsed()) { + if (is_declaration_scope() && AsDeclarationScope()->was_lazily_parsed()) { return; } @@ -1994,9 +2101,9 @@ void Scope::AllocateVariablesRecursively() { // Force allocation of a context for this scope if necessary. For a 'with' // scope and for a function scope that makes an 'eval' call we need a context, // even if no local variables were statically allocated in the scope. - // Likewise for modules. + // Likewise for modules and function scopes representing asm.js modules. bool must_have_context = - is_with_scope() || is_module_scope() || + is_with_scope() || is_module_scope() || IsAsmModule() || (is_function_scope() && calls_sloppy_eval()) || (is_block_scope() && is_declaration_scope() && calls_sloppy_eval()); diff --git a/deps/v8/src/ast/scopes.h b/deps/v8/src/ast/scopes.h index c7d88aca11..49cfdffba7 100644 --- a/deps/v8/src/ast/scopes.h +++ b/deps/v8/src/ast/scopes.h @@ -9,6 +9,7 @@ #include "src/base/hashmap.h" #include "src/globals.h" #include "src/objects.h" +#include "src/objects/scope-info.h" #include "src/zone/zone.h" namespace v8 { @@ -20,6 +21,7 @@ class AstRawString; class Declaration; class ParseInfo; class SloppyBlockFunctionStatement; +class Statement; class StringSet; class VariableProxy; @@ -28,11 +30,16 @@ class VariableMap: public ZoneHashMap { public: explicit VariableMap(Zone* zone); - Variable* Declare(Zone* zone, Scope* scope, const AstRawString* name, - VariableMode mode, VariableKind kind, - InitializationFlag initialization_flag, - MaybeAssignedFlag maybe_assigned_flag = kNotAssigned, - bool* added = nullptr); + Variable* Declare( + Zone* zone, Scope* scope, const AstRawString* name, VariableMode mode, + VariableKind kind = NORMAL_VARIABLE, + InitializationFlag initialization_flag = kCreatedInitialized, + MaybeAssignedFlag maybe_assigned_flag = kNotAssigned, + bool* added = nullptr); + + // Records that "name" exists (if not recorded yet) but doesn't create a + // Variable. Useful for preparsing. + void DeclareName(Zone* zone, const AstRawString* name, VariableMode mode); Variable* Lookup(const AstRawString* name); void Remove(Variable* var); @@ -43,9 +50,24 @@ class VariableMap: public ZoneHashMap { // Sloppy block-scoped function declarations to var-bind class SloppyBlockFunctionMap : public ZoneHashMap { public: + class Delegate : public ZoneObject { + public: + explicit Delegate(Scope* scope, + SloppyBlockFunctionStatement* statement = nullptr) + : scope_(scope), statement_(statement), next_(nullptr) {} + void set_statement(Statement* statement); + void set_next(Delegate* next) { next_ = next; } + Delegate* next() const { return next_; } + Scope* scope() const { return scope_; } + + private: + Scope* scope_; + SloppyBlockFunctionStatement* statement_; + Delegate* next_; + }; + explicit SloppyBlockFunctionMap(Zone* zone); - void Declare(Zone* zone, const AstRawString* name, - SloppyBlockFunctionStatement* statement); + void Declare(Zone* zone, const AstRawString* name, Delegate* delegate); }; enum class AnalyzeMode { kRegular, kDebugger }; @@ -148,7 +170,8 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { // Declare a local variable in this scope. If the variable has been // declared before, the previously declared variable is returned. Variable* DeclareLocal(const AstRawString* name, VariableMode mode, - InitializationFlag init_flag, VariableKind kind, + InitializationFlag init_flag = kCreatedInitialized, + VariableKind kind = NORMAL_VARIABLE, MaybeAssignedFlag maybe_assigned_flag = kNotAssigned); Variable* DeclareVariable(Declaration* declaration, VariableMode mode, @@ -157,6 +180,8 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { bool* sloppy_mode_block_scope_function_redefinition, bool* ok); + void DeclareVariableName(const AstRawString* name, VariableMode mode); + // Declarations list. ThreadedList<Declaration>* declarations() { return &decls_; } @@ -177,7 +202,6 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { // allocated globally as a "ghost" variable. RemoveUnresolved removes // such a variable again if it was added; otherwise this is a no-op. bool RemoveUnresolved(VariableProxy* var); - bool RemoveUnresolved(const AstRawString* name); // Creates a new temporary variable in this scope's TemporaryScope. The // name is only used for printing and cannot be used to find the variable. @@ -207,14 +231,11 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { // Scope-specific info. // Inform the scope and outer scopes that the corresponding code contains an - // eval call. We don't record eval calls from innner scopes in the outer most - // script scope, as we only see those when parsing eagerly. If we recorded the - // calls then, the outer most script scope would look different depending on - // whether we parsed eagerly or not which is undesirable. + // eval call. void RecordEvalCall() { scope_calls_eval_ = true; inner_scope_calls_eval_ = true; - for (Scope* scope = outer_scope(); scope && !scope->is_script_scope(); + for (Scope* scope = outer_scope(); scope != nullptr; scope = scope->outer_scope()) { scope->inner_scope_calls_eval_ = true; } @@ -303,6 +324,7 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { bool calls_sloppy_eval() const { return scope_calls_eval_ && is_sloppy(language_mode()); } + bool inner_scope_calls_eval() const { return inner_scope_calls_eval_; } bool IsAsmModule() const; bool IsAsmFunction() const; // Does this scope have the potential to execute declarations non-linearly? @@ -423,6 +445,22 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { void set_is_debug_evaluate_scope() { is_debug_evaluate_scope_ = true; } bool is_debug_evaluate_scope() const { return is_debug_evaluate_scope_; } + bool RemoveInnerScope(Scope* inner_scope) { + DCHECK_NOT_NULL(inner_scope); + if (inner_scope == inner_scope_) { + inner_scope_ = inner_scope_->sibling_; + return true; + } + for (Scope* scope = inner_scope_; scope != nullptr; + scope = scope->sibling_) { + if (scope->sibling_ == inner_scope) { + scope->sibling_ = scope->sibling_->sibling_; + return true; + } + } + return false; + } + protected: explicit Scope(Zone* zone); @@ -431,10 +469,11 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { } private: - Variable* Declare(Zone* zone, Scope* scope, const AstRawString* name, - VariableMode mode, VariableKind kind, - InitializationFlag initialization_flag, - MaybeAssignedFlag maybe_assigned_flag = kNotAssigned); + Variable* Declare( + Zone* zone, const AstRawString* name, VariableMode mode, + VariableKind kind = NORMAL_VARIABLE, + InitializationFlag initialization_flag = kCreatedInitialized, + MaybeAssignedFlag maybe_assigned_flag = kNotAssigned); // This method should only be invoked on scopes created during parsing (i.e., // not deserialized from a context). Also, since NeedsContext() is only @@ -527,7 +566,6 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { // list along the way, so full resolution cannot be done afterwards. // If a ParseInfo* is passed, non-free variables will be resolved. VariableProxy* FetchFreeVariables(DeclarationScope* max_outer_scope, - bool try_to_resolve = true, ParseInfo* info = nullptr, VariableProxy* stack = nullptr); @@ -556,30 +594,15 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { Handle<ScopeInfo> scope_info); void AddInnerScope(Scope* inner_scope) { - DCHECK_EQ(!needs_migration_, inner_scope->zone() == zone()); inner_scope->sibling_ = inner_scope_; inner_scope_ = inner_scope; inner_scope->outer_scope_ = this; } - void RemoveInnerScope(Scope* inner_scope) { - DCHECK_NOT_NULL(inner_scope); - if (inner_scope == inner_scope_) { - inner_scope_ = inner_scope_->sibling_; - return; - } - for (Scope* scope = inner_scope_; scope != nullptr; - scope = scope->sibling_) { - if (scope->sibling_ == inner_scope) { - scope->sibling_ = scope->sibling_->sibling_; - return; - } - } - } - void SetDefaults(); friend class DeclarationScope; + friend class ScopeTestHelper; }; class DeclarationScope : public Scope { @@ -616,7 +639,15 @@ class DeclarationScope : public Scope { IsClassConstructor(function_kind()))); } - bool is_lazily_parsed() const { return is_lazily_parsed_; } + bool was_lazily_parsed() const { return was_lazily_parsed_; } + +#ifdef DEBUG + void set_is_being_lazily_parsed(bool is_being_lazily_parsed) { + is_being_lazily_parsed_ = is_being_lazily_parsed; + } + bool is_being_lazily_parsed() const { return is_being_lazily_parsed_; } +#endif + bool ShouldEagerCompile() const; void set_should_eager_compile(); @@ -629,7 +660,7 @@ class DeclarationScope : public Scope { bool asm_module() const { return asm_module_; } void set_asm_module(); bool asm_function() const { return asm_function_; } - void set_asm_function() { asm_module_ = true; } + void set_asm_function() { asm_function_ = true; } void DeclareThis(AstValueFactory* ast_value_factory); void DeclareArguments(AstValueFactory* ast_value_factory); @@ -736,10 +767,9 @@ class DeclarationScope : public Scope { // initializers. void AddLocal(Variable* var); - void DeclareSloppyBlockFunction(const AstRawString* name, - SloppyBlockFunctionStatement* statement) { - sloppy_block_function_map_.Declare(zone(), name, statement); - } + void DeclareSloppyBlockFunction( + const AstRawString* name, Scope* scope, + SloppyBlockFunctionStatement* statement = nullptr); // Go through sloppy_block_function_map_ and hoist those (into this scope) // which should be hoisted. @@ -819,7 +849,11 @@ class DeclarationScope : public Scope { // This scope uses "super" property ('super.foo'). bool scope_uses_super_property_ : 1; bool should_eager_compile_ : 1; - bool is_lazily_parsed_ : 1; + // Set to true after we have finished lazy parsing the scope. + bool was_lazily_parsed_ : 1; +#if DEBUG + bool is_being_lazily_parsed_ : 1; +#endif // Parameter list in source order. ZoneList<Variable*> params_; diff --git a/deps/v8/src/ast/variables.cc b/deps/v8/src/ast/variables.cc index 3771bfee12..f138727177 100644 --- a/deps/v8/src/ast/variables.cc +++ b/deps/v8/src/ast/variables.cc @@ -6,6 +6,7 @@ #include "src/ast/scopes.h" #include "src/globals.h" +#include "src/objects-inl.h" namespace v8 { namespace internal { |