summaryrefslogtreecommitdiff
path: root/deps/v8/src/ast
diff options
context:
space:
mode:
authorMichaël Zasso <targos@protonmail.com>2017-03-21 10:16:54 +0100
committerMichaël Zasso <targos@protonmail.com>2017-03-25 09:44:10 +0100
commitc459d8ea5d402c702948c860d9497b2230ff7e8a (patch)
tree56c282fc4d40e5cb613b47cf7be3ea0526ed5b6f /deps/v8/src/ast
parente0bc5a7361b1d29c3ed034155fd779ce6f44fb13 (diff)
downloadandroid-node-v8-c459d8ea5d402c702948c860d9497b2230ff7e8a.tar.gz
android-node-v8-c459d8ea5d402c702948c860d9497b2230ff7e8a.tar.bz2
android-node-v8-c459d8ea5d402c702948c860d9497b2230ff7e8a.zip
deps: update V8 to 5.7.492.69
PR-URL: https://github.com/nodejs/node/pull/11752 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com>
Diffstat (limited to 'deps/v8/src/ast')
-rw-r--r--deps/v8/src/ast/ast-expression-rewriter.cc6
-rw-r--r--deps/v8/src/ast/ast-function-literal-id-reindexer.cc29
-rw-r--r--deps/v8/src/ast/ast-function-literal-id-reindexer.h36
-rw-r--r--deps/v8/src/ast/ast-literal-reindexer.cc4
-rw-r--r--deps/v8/src/ast/ast-numbering.cc119
-rw-r--r--deps/v8/src/ast/ast-numbering.h15
-rw-r--r--deps/v8/src/ast/ast-traversal-visitor.h8
-rw-r--r--deps/v8/src/ast/ast-types.cc7
-rw-r--r--deps/v8/src/ast/ast-value-factory.cc45
-rw-r--r--deps/v8/src/ast/ast-value-factory.h129
-rw-r--r--deps/v8/src/ast/ast.cc226
-rw-r--r--deps/v8/src/ast/ast.h353
-rw-r--r--deps/v8/src/ast/compile-time-value.cc4
-rw-r--r--deps/v8/src/ast/compile-time-value.h4
-rw-r--r--deps/v8/src/ast/modules.cc2
-rw-r--r--deps/v8/src/ast/prettyprinter.cc53
-rw-r--r--deps/v8/src/ast/prettyprinter.h4
-rw-r--r--deps/v8/src/ast/scopeinfo.cc975
-rw-r--r--deps/v8/src/ast/scopes.cc511
-rw-r--r--deps/v8/src/ast/scopes.h118
-rw-r--r--deps/v8/src/ast/variables.cc1
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 {