Merge V8 5.8.283.32
Test: Build V8 for arm, arm64, x86, x86_64, mips, mips64 and
set a PAC script from the UI on bullhead
Change-Id: I7cc773b5daca34d869e768a1deebae3876f2dfac
diff --git a/src/ast/OWNERS b/src/ast/OWNERS
index b4e1473..16e048a 100644
--- a/src/ast/OWNERS
+++ b/src/ast/OWNERS
@@ -5,5 +5,6 @@
littledan@chromium.org
marja@chromium.org
mstarzinger@chromium.org
+neis@chromium.org
rossberg@chromium.org
verwaest@chromium.org
diff --git a/src/ast/ast-expression-rewriter.cc b/src/ast/ast-expression-rewriter.cc
index d0db9ea..f46e21b 100644
--- a/src/ast/ast-expression-rewriter.cc
+++ b/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 @@
NOTHING();
}
+void AstExpressionRewriter::VisitGetIterator(GetIterator* node) {
+ AST_REWRITE_PROPERTY(Expression, node, iterable);
+}
void AstExpressionRewriter::VisitDoExpression(DoExpression* node) {
REWRITE_THIS(node);
diff --git a/src/ast/ast-function-literal-id-reindexer.cc b/src/ast/ast-function-literal-id-reindexer.cc
new file mode 100644
index 0000000..5cb1e87
--- /dev/null
+++ b/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/src/ast/ast-function-literal-id-reindexer.h b/src/ast/ast-function-literal-id-reindexer.h
new file mode 100644
index 0000000..837595f
--- /dev/null
+++ b/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/src/ast/ast-literal-reindexer.cc b/src/ast/ast-literal-reindexer.cc
deleted file mode 100644
index 81a5225..0000000
--- a/src/ast/ast-literal-reindexer.cc
+++ /dev/null
@@ -1,318 +0,0 @@
-// Copyright 2015 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-literal-reindexer.h"
-
-#include "src/ast/ast.h"
-#include "src/ast/scopes.h"
-
-namespace v8 {
-namespace internal {
-
-
-void AstLiteralReindexer::VisitVariableDeclaration(VariableDeclaration* node) {
- VisitVariableProxy(node->proxy());
-}
-
-
-void AstLiteralReindexer::VisitEmptyStatement(EmptyStatement* node) {}
-
-
-void AstLiteralReindexer::VisitSloppyBlockFunctionStatement(
- SloppyBlockFunctionStatement* node) {
- Visit(node->statement());
-}
-
-
-void AstLiteralReindexer::VisitContinueStatement(ContinueStatement* node) {}
-
-
-void AstLiteralReindexer::VisitBreakStatement(BreakStatement* node) {}
-
-
-void AstLiteralReindexer::VisitDebuggerStatement(DebuggerStatement* node) {}
-
-
-void AstLiteralReindexer::VisitNativeFunctionLiteral(
- NativeFunctionLiteral* node) {}
-
-
-void AstLiteralReindexer::VisitDoExpression(DoExpression* node) {
- Visit(node->block());
- Visit(node->result());
-}
-
-
-void AstLiteralReindexer::VisitLiteral(Literal* node) {}
-
-
-void AstLiteralReindexer::VisitRegExpLiteral(RegExpLiteral* node) {
- UpdateIndex(node);
-}
-
-
-void AstLiteralReindexer::VisitVariableProxy(VariableProxy* node) {}
-
-
-void AstLiteralReindexer::VisitThisFunction(ThisFunction* node) {}
-
-
-void AstLiteralReindexer::VisitSuperPropertyReference(
- SuperPropertyReference* node) {
- Visit(node->this_var());
- Visit(node->home_object());
-}
-
-
-void AstLiteralReindexer::VisitSuperCallReference(SuperCallReference* node) {
- Visit(node->this_var());
- Visit(node->new_target_var());
- Visit(node->this_function_var());
-}
-
-
-void AstLiteralReindexer::VisitRewritableExpression(
- RewritableExpression* node) {
- Visit(node->expression());
-}
-
-
-void AstLiteralReindexer::VisitExpressionStatement(ExpressionStatement* node) {
- Visit(node->expression());
-}
-
-
-void AstLiteralReindexer::VisitReturnStatement(ReturnStatement* node) {
- Visit(node->expression());
-}
-
-
-void AstLiteralReindexer::VisitYield(Yield* node) {
- Visit(node->generator_object());
- Visit(node->expression());
-}
-
-
-void AstLiteralReindexer::VisitThrow(Throw* node) { Visit(node->exception()); }
-
-
-void AstLiteralReindexer::VisitUnaryOperation(UnaryOperation* node) {
- Visit(node->expression());
-}
-
-
-void AstLiteralReindexer::VisitCountOperation(CountOperation* node) {
- Visit(node->expression());
-}
-
-
-void AstLiteralReindexer::VisitBlock(Block* node) {
- VisitStatements(node->statements());
-}
-
-
-void AstLiteralReindexer::VisitFunctionDeclaration(FunctionDeclaration* node) {
- VisitVariableProxy(node->proxy());
- VisitFunctionLiteral(node->fun());
-}
-
-
-void AstLiteralReindexer::VisitCallRuntime(CallRuntime* node) {
- VisitArguments(node->arguments());
-}
-
-
-void AstLiteralReindexer::VisitWithStatement(WithStatement* node) {
- Visit(node->expression());
- Visit(node->statement());
-}
-
-
-void AstLiteralReindexer::VisitDoWhileStatement(DoWhileStatement* node) {
- Visit(node->body());
- Visit(node->cond());
-}
-
-
-void AstLiteralReindexer::VisitWhileStatement(WhileStatement* node) {
- Visit(node->cond());
- Visit(node->body());
-}
-
-
-void AstLiteralReindexer::VisitTryCatchStatement(TryCatchStatement* node) {
- Visit(node->try_block());
- Visit(node->catch_block());
-}
-
-
-void AstLiteralReindexer::VisitTryFinallyStatement(TryFinallyStatement* node) {
- Visit(node->try_block());
- Visit(node->finally_block());
-}
-
-
-void AstLiteralReindexer::VisitProperty(Property* node) {
- Visit(node->key());
- Visit(node->obj());
-}
-
-
-void AstLiteralReindexer::VisitAssignment(Assignment* node) {
- Visit(node->target());
- Visit(node->value());
-}
-
-
-void AstLiteralReindexer::VisitBinaryOperation(BinaryOperation* node) {
- Visit(node->left());
- Visit(node->right());
-}
-
-
-void AstLiteralReindexer::VisitCompareOperation(CompareOperation* node) {
- Visit(node->left());
- Visit(node->right());
-}
-
-
-void AstLiteralReindexer::VisitSpread(Spread* node) {
- // This is reachable because ParserBase::ParseArrowFunctionLiteral calls
- // ReindexLiterals before calling RewriteDestructuringAssignments.
- Visit(node->expression());
-}
-
-
-void AstLiteralReindexer::VisitEmptyParentheses(EmptyParentheses* node) {}
-
-
-void AstLiteralReindexer::VisitForInStatement(ForInStatement* node) {
- Visit(node->each());
- Visit(node->enumerable());
- Visit(node->body());
-}
-
-
-void AstLiteralReindexer::VisitForOfStatement(ForOfStatement* node) {
- Visit(node->assign_iterator());
- Visit(node->next_result());
- Visit(node->result_done());
- Visit(node->assign_each());
- Visit(node->body());
-}
-
-
-void AstLiteralReindexer::VisitConditional(Conditional* node) {
- Visit(node->condition());
- Visit(node->then_expression());
- Visit(node->else_expression());
-}
-
-
-void AstLiteralReindexer::VisitIfStatement(IfStatement* node) {
- Visit(node->condition());
- Visit(node->then_statement());
- if (node->HasElseStatement()) {
- Visit(node->else_statement());
- }
-}
-
-
-void AstLiteralReindexer::VisitSwitchStatement(SwitchStatement* node) {
- Visit(node->tag());
- ZoneList<CaseClause*>* cases = node->cases();
- for (int i = 0; i < cases->length(); i++) {
- VisitCaseClause(cases->at(i));
- }
-}
-
-
-void AstLiteralReindexer::VisitCaseClause(CaseClause* node) {
- if (!node->is_default()) Visit(node->label());
- VisitStatements(node->statements());
-}
-
-
-void AstLiteralReindexer::VisitForStatement(ForStatement* node) {
- if (node->init() != NULL) Visit(node->init());
- if (node->cond() != NULL) Visit(node->cond());
- if (node->next() != NULL) Visit(node->next());
- Visit(node->body());
-}
-
-
-void AstLiteralReindexer::VisitClassLiteral(ClassLiteral* node) {
- if (node->extends()) Visit(node->extends());
- if (node->constructor()) Visit(node->constructor());
- if (node->class_variable_proxy()) {
- VisitVariableProxy(node->class_variable_proxy());
- }
- for (int i = 0; i < node->properties()->length(); i++) {
- VisitLiteralProperty(node->properties()->at(i));
- }
-}
-
-void AstLiteralReindexer::VisitObjectLiteral(ObjectLiteral* node) {
- UpdateIndex(node);
- for (int i = 0; i < node->properties()->length(); i++) {
- VisitLiteralProperty(node->properties()->at(i));
- }
-}
-
-void AstLiteralReindexer::VisitLiteralProperty(LiteralProperty* node) {
- Visit(node->key());
- Visit(node->value());
-}
-
-
-void AstLiteralReindexer::VisitArrayLiteral(ArrayLiteral* node) {
- UpdateIndex(node);
- for (int i = 0; i < node->values()->length(); i++) {
- Visit(node->values()->at(i));
- }
-}
-
-
-void AstLiteralReindexer::VisitCall(Call* node) {
- Visit(node->expression());
- VisitArguments(node->arguments());
-}
-
-
-void AstLiteralReindexer::VisitCallNew(CallNew* node) {
- Visit(node->expression());
- VisitArguments(node->arguments());
-}
-
-
-void AstLiteralReindexer::VisitStatements(ZoneList<Statement*>* statements) {
- if (statements == NULL) return;
- for (int i = 0; i < statements->length(); i++) {
- Visit(statements->at(i));
- }
-}
-
-
-void AstLiteralReindexer::VisitDeclarations(
- ZoneList<Declaration*>* declarations) {
- for (int i = 0; i < declarations->length(); i++) {
- Visit(declarations->at(i));
- }
-}
-
-
-void AstLiteralReindexer::VisitArguments(ZoneList<Expression*>* arguments) {
- for (int i = 0; i < arguments->length(); i++) {
- Visit(arguments->at(i));
- }
-}
-
-
-void AstLiteralReindexer::VisitFunctionLiteral(FunctionLiteral* node) {
- // We don't recurse into the declarations or body of the function literal:
-}
-
-void AstLiteralReindexer::Reindex(Expression* pattern) { Visit(pattern); }
-} // namespace internal
-} // namespace v8
diff --git a/src/ast/ast-literal-reindexer.h b/src/ast/ast-literal-reindexer.h
deleted file mode 100644
index 4e0ca6b..0000000
--- a/src/ast/ast-literal-reindexer.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2015 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_LITERAL_REINDEXER
-#define V8_AST_AST_LITERAL_REINDEXER
-
-#include "src/ast/ast.h"
-#include "src/ast/scopes.h"
-
-namespace v8 {
-namespace internal {
-
-class AstLiteralReindexer final : public AstVisitor<AstLiteralReindexer> {
- public:
- AstLiteralReindexer() : next_index_(0) {}
-
- int count() const { return next_index_; }
- void Reindex(Expression* pattern);
-
- private:
-#define DEFINE_VISIT(type) void Visit##type(type* node);
- AST_NODE_LIST(DEFINE_VISIT)
-#undef DEFINE_VISIT
-
- void VisitStatements(ZoneList<Statement*>* statements);
- void VisitDeclarations(ZoneList<Declaration*>* declarations);
- void VisitArguments(ZoneList<Expression*>* arguments);
- void VisitLiteralProperty(LiteralProperty* property);
-
- void UpdateIndex(MaterializedLiteral* literal) {
- literal->literal_index_ = next_index_++;
- }
-
- int next_index_;
-
- DEFINE_AST_VISITOR_MEMBERS_WITHOUT_STACKOVERFLOW()
- DISALLOW_COPY_AND_ASSIGN(AstLiteralReindexer);
-};
-} // namespace internal
-} // namespace v8
-
-#endif // V8_AST_AST_LITERAL_REINDEXER
diff --git a/src/ast/ast-numbering.cc b/src/ast/ast-numbering.cc
index 82f9767..499760d 100644
--- a/src/ast/ast-numbering.cc
+++ b/src/ast/ast-numbering.cc
@@ -6,22 +6,27 @@
#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),
+ language_mode_(SLOPPY),
slot_cache_(zone),
+ disable_crankshaft_reason_(kNoReason),
dont_optimize_reason_(kNoReason),
catch_prediction_(HandlerTable::UNCAUGHT) {
- InitializeAstVisitor(isolate);
+ InitializeAstVisitor(stack_limit);
}
bool Renumber(FunctionLiteral* node);
@@ -32,10 +37,12 @@
AST_NODE_LIST(DEFINE_VISIT)
#undef DEFINE_VISIT
+ void VisitVariableProxy(VariableProxy* node, TypeofMode typeof_mode);
void VisitVariableProxyReference(VariableProxy* node);
void VisitPropertyReference(Property* node);
void VisitReference(Expression* expr);
+ void VisitStatementsAndDeclarations(Block* node);
void VisitStatements(ZoneList<Statement*>* statements);
void VisitDeclarations(Declaration::List* declarations);
void VisitArguments(ZoneList<Expression*>* arguments);
@@ -55,25 +62,43 @@
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->AssignFeedbackSlots(properties_.get_spec(), language_mode_,
+ &slot_cache_);
}
+ class LanguageModeScope {
+ public:
+ LanguageModeScope(AstNumberingVisitor* visitor, LanguageMode language_mode)
+ : visitor_(visitor), outer_language_mode_(visitor->language_mode_) {
+ visitor_->language_mode_ = language_mode;
+ }
+ ~LanguageModeScope() { visitor_->language_mode_ = outer_language_mode_; }
+
+ private:
+ AstNumberingVisitor* visitor_;
+ LanguageMode outer_language_mode_;
+ };
+
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_;
+ LanguageMode language_mode_;
+ // The slot cache allows us to reuse certain feedback slots.
+ FeedbackSlotCache slot_cache_;
+ BailoutReason disable_crankshaft_reason_;
BailoutReason dont_optimize_reason_;
HandlerTable::CatchPrediction catch_prediction_;
@@ -112,8 +137,7 @@
void AstNumberingVisitor::VisitDebuggerStatement(DebuggerStatement* node) {
IncrementNodeCount();
- DisableOptimization(kDebuggerStatement);
- node->set_base_id(ReserveIdRange(DebuggerStatement::num_ids()));
+ DisableFullCodegenAndCrankshaft(kDebuggerStatement);
}
@@ -122,6 +146,7 @@
IncrementNodeCount();
DisableOptimization(kNativeFunctionLiteral);
node->set_base_id(ReserveIdRange(NativeFunctionLiteral::num_ids()));
+ ReserveFeedbackSlots(node);
}
@@ -142,6 +167,7 @@
void AstNumberingVisitor::VisitRegExpLiteral(RegExpLiteral* node) {
IncrementNodeCount();
node->set_base_id(ReserveIdRange(RegExpLiteral::num_ids()));
+ ReserveFeedbackSlots(node);
}
@@ -149,10 +175,11 @@
IncrementNodeCount();
switch (node->var()->location()) {
case VariableLocation::LOOKUP:
- DisableCrankshaft(kReferenceToAVariableWhichRequiresDynamicLookup);
+ DisableFullCodegenAndCrankshaft(
+ kReferenceToAVariableWhichRequiresDynamicLookup);
break;
case VariableLocation::MODULE:
- DisableCrankshaft(kReferenceToModuleVariable);
+ DisableFullCodegenAndCrankshaft(kReferenceToModuleVariable);
break;
default:
break;
@@ -160,10 +187,14 @@
node->set_base_id(ReserveIdRange(VariableProxy::num_ids()));
}
+void AstNumberingVisitor::VisitVariableProxy(VariableProxy* node,
+ TypeofMode typeof_mode) {
+ VisitVariableProxyReference(node);
+ node->AssignFeedbackSlots(properties_.get_spec(), typeof_mode, &slot_cache_);
+}
void AstNumberingVisitor::VisitVariableProxy(VariableProxy* node) {
- VisitVariableProxyReference(node);
- ReserveFeedbackSlots(node);
+ VisitVariableProxy(node, NOT_INSIDE_TYPEOF);
}
@@ -176,7 +207,7 @@
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 +216,7 @@
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());
@@ -202,6 +233,9 @@
void AstNumberingVisitor::VisitReturnStatement(ReturnStatement* node) {
IncrementNodeCount();
Visit(node->expression());
+
+ DCHECK(!node->is_async_return() ||
+ properties_.flags() & AstProperties::kMustUseIgnitionTurbo);
}
@@ -225,7 +259,12 @@
void AstNumberingVisitor::VisitUnaryOperation(UnaryOperation* node) {
IncrementNodeCount();
node->set_base_id(ReserveIdRange(UnaryOperation::num_ids()));
- Visit(node->expression());
+ if ((node->op() == Token::TYPEOF) && node->expression()->IsVariableProxy()) {
+ VariableProxy* proxy = node->expression()->AsVariableProxy();
+ VisitVariableProxy(proxy, INSIDE_TYPEOF);
+ } else {
+ Visit(node->expression());
+ }
}
@@ -240,10 +279,21 @@
void AstNumberingVisitor::VisitBlock(Block* node) {
IncrementNodeCount();
node->set_base_id(ReserveIdRange(Block::num_ids()));
- if (node->scope() != NULL) VisitDeclarations(node->scope()->declarations());
- VisitStatements(node->statements());
+ Scope* scope = node->scope();
+ if (scope != nullptr) {
+ LanguageModeScope language_mode_scope(this, scope->language_mode());
+ VisitStatementsAndDeclarations(node);
+ } else {
+ VisitStatementsAndDeclarations(node);
+ }
}
+void AstNumberingVisitor::VisitStatementsAndDeclarations(Block* node) {
+ Scope* scope = node->scope();
+ DCHECK(scope == nullptr || !scope->HasBeenRemoved());
+ if (scope) VisitDeclarations(scope->declarations());
+ VisitStatements(node->statements());
+}
void AstNumberingVisitor::VisitFunctionDeclaration(FunctionDeclaration* node) {
IncrementNodeCount();
@@ -282,8 +332,7 @@
void AstNumberingVisitor::VisitWithStatement(WithStatement* node) {
IncrementNodeCount();
- DisableCrankshaft(kWithStatement);
- node->set_base_id(ReserveIdRange(WithStatement::num_ids()));
+ DisableFullCodegenAndCrankshaft(kWithStatement);
Visit(node->expression());
Visit(node->statement());
}
@@ -312,8 +361,9 @@
void AstNumberingVisitor::VisitTryCatchStatement(TryCatchStatement* node) {
+ DCHECK(node->scope() == nullptr || !node->scope()->HasBeenRemoved());
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 +382,7 @@
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 +443,25 @@
ReserveFeedbackSlots(node);
}
-
-void AstNumberingVisitor::VisitSpread(Spread* node) { UNREACHABLE(); }
-
+void AstNumberingVisitor::VisitSpread(Spread* node) {
+ IncrementNodeCount();
+ // We can only get here from spread calls currently.
+ DisableFullCodegenAndCrankshaft(kSpreadCall);
+ 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 +478,7 @@
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 +545,8 @@
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 +565,7 @@
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 +574,8 @@
}
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 +586,15 @@
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 +634,20 @@
void AstNumberingVisitor::VisitFunctionLiteral(FunctionLiteral* node) {
IncrementNodeCount();
node->set_base_id(ReserveIdRange(FunctionLiteral::num_ids()));
- // We don't recurse into the declarations or body of the function literal:
- // you have to separately Renumber() each FunctionLiteral that you compile.
+ if (node->ShouldEagerCompile()) {
+ if (eager_literals_) {
+ eager_literals_->Add(new (zone())
+ ThreadedListZoneEntry<FunctionLiteral*>(node));
+ }
+
+ // If the function literal is being eagerly compiled, recurse into the
+ // declarations and body of the function literal.
+ if (!AstNumbering::Renumber(stack_limit_, zone_, node, eager_literals_)) {
+ SetStackOverflow();
+ return;
+ }
+ }
+ ReserveFeedbackSlots(node);
}
@@ -584,37 +661,65 @@
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);
+ DCHECK(!scope->HasBeenRemoved());
+
+ 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);
}
+ LanguageModeScope language_mode_scope(this, node->language_mode());
+
VisitDeclarations(scope->declarations());
VisitStatements(node->body());
node->set_ast_properties(&properties_);
node->set_dont_optimize_reason(dont_optimize_reason());
node->set_yield_count(yield_count_);
+
+ if (FLAG_trace_opt) {
+ if (disable_crankshaft_reason_ != kNoReason) {
+ // TODO(leszeks): This is a quick'n'dirty fix to allow the debug name of
+ // the function to be accessed in the below print. This DCHECK will fail
+ // if we move ast numbering off the main thread, but that won't be before
+ // we remove FCG, in which case this entire check isn't necessary anyway.
+ AllowHandleDereference allow_deref;
+ DCHECK(!node->debug_name().is_null());
+
+ 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/src/ast/ast-numbering.h b/src/ast/ast-numbering.h
index 7327895..bea441d 100644
--- a/src/ast/ast-numbering.h
+++ b/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 @@
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/src/ast/ast-traversal-visitor.h b/src/ast/ast-traversal-visitor.h
index d93e02f..6d0c386 100644
--- a/src/ast/ast-traversal-visitor.h
+++ b/src/ast/ast-traversal-visitor.h
@@ -288,7 +288,7 @@
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 @@
}
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/src/ast/ast-types.cc b/src/ast/ast-types.cc
index 49551dd..3dde864 100644
--- a/src/ast/ast-types.cc
+++ b/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 {
@@ -156,6 +157,8 @@
case ONE_BYTE_STRING_TYPE:
case CONS_STRING_TYPE:
case CONS_ONE_BYTE_STRING_TYPE:
+ case THIN_STRING_TYPE:
+ case THIN_ONE_BYTE_STRING_TYPE:
case SLICED_STRING_TYPE:
case SLICED_ONE_BYTE_STRING_TYPE:
case EXTERNAL_STRING_TYPE:
@@ -192,8 +195,6 @@
}
case HEAP_NUMBER_TYPE:
return kNumber & kTaggedPointer;
- case SIMD128_VALUE_TYPE:
- return kSimd;
case JS_OBJECT_TYPE:
case JS_ARGUMENTS_TYPE:
case JS_ERROR_TYPE:
@@ -209,7 +210,6 @@
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.
@@ -220,6 +220,7 @@
case JS_SET_ITERATOR_TYPE:
case JS_MAP_ITERATOR_TYPE:
case JS_STRING_ITERATOR_TYPE:
+ case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
case JS_TYPED_ARRAY_KEY_ITERATOR_TYPE:
case JS_FAST_ARRAY_KEY_ITERATOR_TYPE:
@@ -259,6 +260,7 @@
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,19 +306,18 @@
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:
- case BOX_TYPE:
case DEBUG_INFO_TYPE:
case BREAK_POINT_INFO_TYPE:
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;
}
@@ -1295,13 +1296,6 @@
return i::SmiValuesAre31Bits() ? kUnsigned30 : kUnsigned31;
}
-#define CONSTRUCT_SIMD_TYPE(NAME, Name, name, lane_count, lane_type) \
- AstType* AstType::Name(Isolate* isolate, Zone* zone) { \
- return Class(i::handle(isolate->heap()->name##_map()), zone); \
- }
-SIMD128_TYPES(CONSTRUCT_SIMD_TYPE)
-#undef CONSTRUCT_SIMD_TYPE
-
// -----------------------------------------------------------------------------
// Instantiations.
diff --git a/src/ast/ast-types.h b/src/ast/ast-types.h
index 0b6e23f..ea0be65 100644
--- a/src/ast/ast-types.h
+++ b/src/ast/ast-types.h
@@ -156,15 +156,15 @@
#define AST_REPRESENTATION(k) ((k) & AstBitsetType::kRepresentation)
#define AST_SEMANTIC(k) ((k) & AstBitsetType::kSemantic)
+// Bits 21-22 are available.
#define AST_REPRESENTATION_BITSET_TYPE_LIST(V) \
V(None, 0) \
- V(UntaggedBit, 1u << 22 | kSemantic) \
- V(UntaggedIntegral8, 1u << 23 | kSemantic) \
- V(UntaggedIntegral16, 1u << 24 | kSemantic) \
- V(UntaggedIntegral32, 1u << 25 | kSemantic) \
- V(UntaggedFloat32, 1u << 26 | kSemantic) \
- V(UntaggedFloat64, 1u << 27 | kSemantic) \
- V(UntaggedSimd128, 1u << 28 | kSemantic) \
+ V(UntaggedBit, 1u << 23 | kSemantic) \
+ V(UntaggedIntegral8, 1u << 24 | kSemantic) \
+ V(UntaggedIntegral16, 1u << 25 | kSemantic) \
+ V(UntaggedIntegral32, 1u << 26 | kSemantic) \
+ V(UntaggedFloat32, 1u << 27 | kSemantic) \
+ V(UntaggedFloat64, 1u << 28 | kSemantic) \
V(UntaggedPointer, 1u << 29 | kSemantic) \
V(TaggedSigned, 1u << 30 | kSemantic) \
V(TaggedPointer, 1u << 31 | kSemantic) \
@@ -197,13 +197,12 @@
V(Symbol, 1u << 12 | AST_REPRESENTATION(kTaggedPointer)) \
V(InternalizedString, 1u << 13 | AST_REPRESENTATION(kTaggedPointer)) \
V(OtherString, 1u << 14 | AST_REPRESENTATION(kTaggedPointer)) \
- V(Simd, 1u << 15 | AST_REPRESENTATION(kTaggedPointer)) \
- V(OtherObject, 1u << 17 | AST_REPRESENTATION(kTaggedPointer)) \
+ V(OtherObject, 1u << 15 | AST_REPRESENTATION(kTaggedPointer)) \
V(OtherUndetectable, 1u << 16 | AST_REPRESENTATION(kTaggedPointer)) \
- V(Proxy, 1u << 18 | AST_REPRESENTATION(kTaggedPointer)) \
- V(Function, 1u << 19 | AST_REPRESENTATION(kTaggedPointer)) \
- V(Hole, 1u << 20 | AST_REPRESENTATION(kTaggedPointer)) \
- V(OtherInternal, 1u << 21 | \
+ V(Proxy, 1u << 17 | AST_REPRESENTATION(kTaggedPointer)) \
+ V(Function, 1u << 18 | AST_REPRESENTATION(kTaggedPointer)) \
+ V(Hole, 1u << 19 | AST_REPRESENTATION(kTaggedPointer)) \
+ V(OtherInternal, 1u << 20 | \
AST_REPRESENTATION(kTagged | kUntagged)) \
\
V(Signed31, kUnsigned30 | kNegative31) \
@@ -232,11 +231,10 @@
V(NullOrUndefined, kNull | kUndefined) \
V(Undetectable, kNullOrUndefined | kOtherUndetectable) \
V(NumberOrOddball, kNumber | kNullOrUndefined | kBoolean | kHole) \
- V(NumberOrSimdOrString, kNumber | kSimd | kString) \
V(NumberOrString, kNumber | kString) \
V(NumberOrUndefined, kNumber | kUndefined) \
V(PlainPrimitive, kNumberOrString | kBoolean | kNullOrUndefined) \
- V(Primitive, kSymbol | kSimd | kPlainPrimitive) \
+ V(Primitive, kSymbol | kPlainPrimitive) \
V(DetectableReceiver, kFunction | kOtherObject | kProxy) \
V(Object, kFunction | kOtherObject | kOtherUndetectable) \
V(Receiver, kObject | kProxy) \
@@ -770,11 +768,6 @@
return tuple;
}
-#define CONSTRUCT_SIMD_TYPE(NAME, Name, name, lane_count, lane_type) \
- static AstType* Name(Isolate* isolate, Zone* zone);
- SIMD128_TYPES(CONSTRUCT_SIMD_TYPE)
-#undef CONSTRUCT_SIMD_TYPE
-
static AstType* Union(AstType* type1, AstType* type2, Zone* zone);
static AstType* Intersect(AstType* type1, AstType* type2, Zone* zone);
diff --git a/src/ast/ast-value-factory.cc b/src/ast/ast-value-factory.cc
index ed2976f..b160c48 100644
--- a/src/ast/ast-value-factory.cc
+++ b/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"
@@ -127,6 +129,36 @@
return false;
}
+bool AstRawString::Compare(void* a, void* b) {
+ const AstRawString* lhs = static_cast<AstRawString*>(a);
+ const AstRawString* rhs = static_cast<AstRawString*>(b);
+ DCHECK_EQ(lhs->hash(), rhs->hash());
+ if (lhs->length() != rhs->length()) return false;
+ const unsigned char* l = lhs->raw_data();
+ const unsigned char* r = rhs->raw_data();
+ size_t length = rhs->length();
+ if (lhs->is_one_byte()) {
+ if (rhs->is_one_byte()) {
+ return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(l),
+ reinterpret_cast<const uint8_t*>(r),
+ length) == 0;
+ } else {
+ return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(l),
+ reinterpret_cast<const uint16_t*>(r),
+ length) == 0;
+ }
+ } else {
+ if (rhs->is_one_byte()) {
+ return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(l),
+ reinterpret_cast<const uint8_t*>(r),
+ length) == 0;
+ } else {
+ return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(l),
+ reinterpret_cast<const uint16_t*>(r),
+ length) == 0;
+ }
+ }
+}
void AstConsString::Internalize(Isolate* isolate) {
// AstRawStrings are internalized before AstConsStrings so left and right are
@@ -182,14 +214,10 @@
DCHECK(!string_->string().is_null());
break;
case SYMBOL:
- if (symbol_name_[0] == 'i') {
- DCHECK_EQ(0, strcmp(symbol_name_, "iterator_symbol"));
- set_value(isolate->factory()->iterator_symbol());
- } else if (strcmp(symbol_name_, "hasInstance_symbol") == 0) {
- set_value(isolate->factory()->has_instance_symbol());
- } else {
- DCHECK_EQ(0, strcmp(symbol_name_, "home_object_symbol"));
- set_value(isolate->factory()->home_object_symbol());
+ switch (symbol_) {
+ case AstSymbol::kHomeObjectSymbol:
+ set_value(isolate->factory()->home_object_symbol());
+ break;
}
break;
case NUMBER_WITH_DOT:
@@ -219,9 +247,17 @@
}
}
-
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 +296,6 @@
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.
@@ -318,9 +321,8 @@
return AddValue(value);
}
-
-const AstValue* AstValueFactory::NewSymbol(const char* name) {
- AstValue* value = new (zone_) AstValue(name);
+const AstValue* AstValueFactory::NewSymbol(AstSymbol symbol) {
+ AstValue* value = new (zone_) AstValue(symbol);
return AddValue(value);
}
@@ -379,7 +381,7 @@
// return this AstRawString.
AstRawString key(is_one_byte, literal_bytes, hash);
base::HashMap::Entry* entry = string_table_.LookupOrInsert(&key, hash);
- if (entry->value == NULL) {
+ if (entry->value == nullptr) {
// Copy literal contents for later comparison.
int length = literal_bytes.length();
byte* new_literal_bytes = zone_->NewArray<byte>(length);
@@ -394,36 +396,5 @@
return reinterpret_cast<AstRawString*>(entry->key);
}
-
-bool AstValueFactory::AstRawStringCompare(void* a, void* b) {
- const AstRawString* lhs = static_cast<AstRawString*>(a);
- const AstRawString* rhs = static_cast<AstRawString*>(b);
- DCHECK_EQ(lhs->hash(), rhs->hash());
- if (lhs->length() != rhs->length()) return false;
- const unsigned char* l = lhs->raw_data();
- const unsigned char* r = rhs->raw_data();
- size_t length = rhs->length();
- if (lhs->is_one_byte()) {
- if (rhs->is_one_byte()) {
- return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(l),
- reinterpret_cast<const uint8_t*>(r),
- length) == 0;
- } else {
- return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(l),
- reinterpret_cast<const uint16_t*>(r),
- length) == 0;
- }
- } else {
- if (rhs->is_one_byte()) {
- return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(l),
- reinterpret_cast<const uint8_t*>(r),
- length) == 0;
- } else {
- return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(l),
- reinterpret_cast<const uint16_t*>(r),
- length) == 0;
- }
- }
-}
} // namespace internal
} // namespace v8
diff --git a/src/ast/ast-value-factory.h b/src/ast/ast-value-factory.h
index 4ce480f..c1ed7ac 100644
--- a/src/ast/ast-value-factory.h
+++ b/src/ast/ast-value-factory.h
@@ -28,9 +28,11 @@
#ifndef V8_AST_AST_VALUE_FACTORY_H_
#define V8_AST_AST_VALUE_FACTORY_H_
-#include "src/api.h"
#include "src/base/hashmap.h"
+#include "src/conversions.h"
+#include "src/factory.h"
#include "src/globals.h"
+#include "src/isolate.h"
#include "src/utils.h"
// AstString, AstValue and AstValueFactory are for storing strings and values
@@ -104,14 +106,17 @@
return *c;
}
+ static bool Compare(void* a, void* b);
+
// For storing AstRawStrings in a hash map.
uint32_t hash() const {
return hash_;
}
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)
@@ -149,19 +154,19 @@
const AstString* right_;
};
+enum class AstSymbol : uint8_t { kHomeObjectSymbol };
-// AstValue is either a string, a number, a string array, a boolean, or a
-// special value (null, undefined, the hole).
+// AstValue is either a string, a symbol, a number, a string array, a boolean,
+// or a special value (null, undefined, the hole).
class AstValue : public ZoneObject {
public:
bool IsString() const {
return type_ == STRING;
}
- bool IsNumber() const {
- return type_ == NUMBER || type_ == NUMBER_WITH_DOT || type_ == SMI ||
- type_ == SMI_WITH_DOT;
- }
+ bool IsSymbol() const { return type_ == SYMBOL; }
+
+ bool IsNumber() const { return IsSmi() || IsHeapNumber(); }
bool ContainsDot() const {
return type_ == NUMBER_WITH_DOT || type_ == SMI_WITH_DOT;
@@ -172,20 +177,36 @@
return string_;
}
+ AstSymbol AsSymbol() const {
+ CHECK_EQ(SYMBOL, type_);
+ return symbol_;
+ }
+
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 +216,9 @@
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; }
@@ -235,8 +259,8 @@
string_ = s;
}
- explicit AstValue(const char* name) : type_(SYMBOL), next_(nullptr) {
- symbol_name_ = name;
+ explicit AstValue(AstSymbol symbol) : type_(SYMBOL), next_(nullptr) {
+ symbol_ = symbol;
}
explicit AstValue(double n, bool with_dot) : next_(nullptr) {
@@ -276,11 +300,10 @@
double number_;
int smi_;
bool bool_;
- const char* symbol_name_;
+ AstSymbol symbol_;
};
};
-
// For generating constants.
#define STRING_CONSTANTS(F) \
F(anonymous_function, "(anonymous function)") \
@@ -291,7 +314,6 @@
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 +326,7 @@
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 +343,55 @@
F(use_strict, "use strict") \
F(value, "value")
+class AstStringConstants final {
+ public:
+ AstStringConstants(Isolate* isolate, uint32_t hash_seed)
+ : zone_(isolate->allocator(), ZONE_NAME),
+ string_table_(AstRawString::Compare),
+ 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()); \
+ base::HashMap::Entry* entry = \
+ string_table_.InsertNew(name##_string_, name##_string_->hash()); \
+ DCHECK(entry->value == nullptr); \
+ entry->value = reinterpret_cast<void*>(1); \
+ }
+ STRING_CONSTANTS(F)
+#undef F
+ }
+
+#define F(name, str) \
+ const AstRawString* name##_string() const { return name##_string_; }
+ STRING_CONSTANTS(F)
+#undef F
+
+ uint32_t hash_seed() const { return hash_seed_; }
+ const base::CustomMatcherHashMap* string_table() const {
+ return &string_table_;
+ }
+
+ private:
+ Zone zone_;
+ base::CustomMatcherHashMap string_table_;
+ 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 +401,23 @@
class AstValueFactory {
public:
- AstValueFactory(Zone* zone, uint32_t hash_seed)
- : string_table_(AstRawStringCompare),
+ AstValueFactory(Zone* zone, const AstStringConstants* string_constants,
+ uint32_t hash_seed)
+ : string_table_(string_constants->string_table()),
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);
}
Zone* zone() const { return zone_; }
@@ -361,28 +435,21 @@
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);
+ V8_EXPORT_PRIVATE 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
- const AstValue* NewString(const AstRawString* string);
+ V8_EXPORT_PRIVATE const AstValue* NewString(const AstRawString* string);
// A JavaScript symbol (ECMA-262 edition 6).
- const AstValue* NewSymbol(const char* name);
- const AstValue* NewNumber(double number, bool with_dot = false);
+ const AstValue* NewSymbol(AstSymbol symbol);
+ V8_EXPORT_PRIVATE const AstValue* NewNumber(double number,
+ bool with_dot = false);
const AstValue* NewSmi(uint32_t number);
const AstValue* NewBoolean(bool b);
const AstValue* NewStringList(ZoneList<const AstRawString*>* strings);
@@ -415,27 +482,29 @@
AstRawString* GetString(uint32_t hash, bool is_one_byte,
Vector<const byte> literal_bytes);
- static bool AstRawStringCompare(void* a, void* b);
-
// All strings are copied here, one after another (no NULLs inbetween).
base::CustomMatcherHashMap string_table_;
// For keeping track of all AstValues and AstRawStrings we've created (so that
// 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.
+ const 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/src/ast/ast.cc b/src/ast/ast.cc
index fc8bd8a..5705c70 100644
--- a/src/ast/ast.cc
+++ b/src/ast/ast.cc
@@ -10,11 +10,15 @@
#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"
#include "src/conversions.h"
+#include "src/double.h"
#include "src/elements.h"
+#include "src/objects-inl.h"
+#include "src/objects/literal-objects.h"
#include "src/property-details.h"
#include "src/property.h"
#include "src/string-stream.h"
@@ -28,6 +32,24 @@
#ifdef DEBUG
+static const char* NameForNativeContextIntrinsicIndex(uint32_t idx) {
+ switch (idx) {
+#define NATIVE_CONTEXT_FIELDS_IDX(NAME, Type, name) \
+ case Context::NAME: \
+ return #name;
+
+ NATIVE_CONTEXT_FIELDS(NATIVE_CONTEXT_FIELDS_IDX)
+#undef NATIVE_CONTEXT_FIELDS_IDX
+
+ default:
+ break;
+ }
+
+ return "UnknownIntrinsicIndex";
+}
+
+void AstNode::Print() { Print(Isolate::Current()); }
+
void AstNode::Print(Isolate* isolate) {
AstPrinter::PrintOut(isolate, this);
}
@@ -70,6 +92,10 @@
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();
}
@@ -195,50 +221,51 @@
set_var(var);
set_is_resolved();
var->set_is_used();
+ if (is_assigned()) var->set_maybe_assigned();
}
-
-void VariableProxy::AssignFeedbackVectorSlots(Isolate* isolate,
- FeedbackVectorSpec* spec,
- FeedbackVectorSlotCache* cache) {
+void VariableProxy::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+ TypeofMode typeof_mode,
+ FeedbackSlotCache* cache) {
if (UsesVariableFeedbackSlot()) {
// VariableProxies that point to the same Variable within a function can
// make their loads from the same IC slot.
if (var()->IsUnallocated() || var()->mode() == DYNAMIC_GLOBAL) {
- ZoneHashMap::Entry* entry = cache->Get(var());
- if (entry != NULL) {
- variable_feedback_slot_ = FeedbackVectorSlot(
- static_cast<int>(reinterpret_cast<intptr_t>(entry->value)));
+ FeedbackSlot slot = cache->Get(typeof_mode, var());
+ if (!slot.IsInvalid()) {
+ variable_feedback_slot_ = slot;
return;
}
- variable_feedback_slot_ = spec->AddLoadGlobalICSlot(var()->name());
- cache->Put(var(), variable_feedback_slot_);
+ variable_feedback_slot_ = spec->AddLoadGlobalICSlot(typeof_mode);
+ cache->Put(typeof_mode, var(), variable_feedback_slot_);
} else {
variable_feedback_slot_ = spec->AddLoadICSlot();
}
}
}
-
static void AssignVectorSlots(Expression* expr, FeedbackVectorSpec* spec,
- FeedbackVectorSlot* out_slot) {
+ LanguageMode language_mode,
+ FeedbackSlot* out_slot) {
Property* property = expr->AsProperty();
LhsKind assign_type = Property::GetAssignType(property);
if ((assign_type == VARIABLE &&
expr->AsVariableProxy()->var()->IsUnallocated()) ||
assign_type == NAMED_PROPERTY || assign_type == KEYED_PROPERTY) {
// TODO(ishell): consider using ICSlotCache for variables here.
- FeedbackVectorSlotKind kind = assign_type == KEYED_PROPERTY
- ? FeedbackVectorSlotKind::KEYED_STORE_IC
- : FeedbackVectorSlotKind::STORE_IC;
- *out_slot = spec->AddSlot(kind);
+ if (assign_type == KEYED_PROPERTY) {
+ *out_slot = spec->AddKeyedStoreICSlot(language_mode);
+
+ } else {
+ *out_slot = spec->AddStoreICSlot(language_mode);
+ }
}
}
-void ForInStatement::AssignFeedbackVectorSlots(Isolate* isolate,
- FeedbackVectorSpec* spec,
- FeedbackVectorSlotCache* cache) {
- AssignVectorSlots(each(), spec, &each_slot_);
+void ForInStatement::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+ LanguageMode language_mode,
+ FeedbackSlotCache* cache) {
+ AssignVectorSlots(each(), spec, language_mode, &each_slot_);
for_in_feedback_slot_ = spec->AddGeneralSlot();
}
@@ -253,17 +280,16 @@
StoreModeField::encode(STANDARD_STORE) | TokenField::encode(op);
}
-void Assignment::AssignFeedbackVectorSlots(Isolate* isolate,
- FeedbackVectorSpec* spec,
- FeedbackVectorSlotCache* cache) {
- AssignVectorSlots(target(), spec, &slot_);
+void Assignment::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+ LanguageMode language_mode,
+ FeedbackSlotCache* cache) {
+ AssignVectorSlots(target(), spec, language_mode, &slot_);
}
-
-void CountOperation::AssignFeedbackVectorSlots(Isolate* isolate,
- FeedbackVectorSpec* spec,
- FeedbackVectorSlotCache* cache) {
- AssignVectorSlots(expression(), spec, &slot_);
+void CountOperation::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+ LanguageMode language_mode,
+ FeedbackSlotCache* cache) {
+ AssignVectorSlots(expression(), spec, language_mode, &slot_);
// Assign a slot to collect feedback about binary operations. Used only in
// ignition. Fullcodegen uses AstId to record type feedback.
binary_operation_slot_ = spec->AddInterpreterBinaryOpICSlot();
@@ -346,6 +372,16 @@
}
}
+FeedbackSlot LiteralProperty::GetStoreDataPropertySlot() const {
+ int offset = FunctionLiteral::NeedsHomeObject(value_) ? 1 : 0;
+ return GetSlot(offset);
+}
+
+void LiteralProperty::SetStoreDataPropertySlot(FeedbackSlot slot) {
+ int offset = FunctionLiteral::NeedsHomeObject(value_) ? 1 : 0;
+ return SetSlot(slot, offset);
+}
+
bool LiteralProperty::NeedsSetFunctionName() const {
return is_computed_name_ &&
(value_->IsAnonymousFunctionDefinition() ||
@@ -360,22 +396,27 @@
kind_(kind),
is_static_(is_static) {}
-void ClassLiteral::AssignFeedbackVectorSlots(Isolate* isolate,
- FeedbackVectorSpec* spec,
- FeedbackVectorSlotCache* cache) {
+void ClassLiteral::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+ LanguageMode language_mode,
+ FeedbackSlotCache* 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(language_mode);
+ }
+
if (NeedsProxySlot()) {
- proxy_slot_ = spec->AddStoreICSlot();
+ proxy_slot_ = spec->AddStoreICSlot(language_mode);
}
for (int i = 0; i < properties()->length(); i++) {
ClassLiteral::Property* property = properties()->at(i);
Expression* value = property->value();
if (FunctionLiteral::NeedsHomeObject(value)) {
- property->SetSlot(spec->AddStoreICSlot());
+ property->SetSlot(spec->AddStoreICSlot(language_mode));
}
+ property->SetStoreDataPropertySlot(
+ spec->AddStoreDataPropertyInLiteralICSlot());
}
}
@@ -392,9 +433,11 @@
bool ObjectLiteral::Property::emit_store() const { return emit_store_; }
-void ObjectLiteral::AssignFeedbackVectorSlots(Isolate* isolate,
- FeedbackVectorSpec* spec,
- FeedbackVectorSlotCache* cache) {
+void ObjectLiteral::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+ LanguageMode language_mode,
+ FeedbackSlotCache* cache) {
+ MaterializedLiteral::AssignFeedbackSlots(spec, language_mode, cache);
+
// This logic that computes the number of slots needed for vector store
// ics must mirror FullCodeGenerator::VisitObjectLiteral.
int property_index = 0;
@@ -406,6 +449,7 @@
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,29 +457,29 @@
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());
+ property->SetSlot(spec->AddStoreOwnICSlot());
if (FunctionLiteral::NeedsHomeObject(value)) {
- property->SetSlot(spec->AddStoreICSlot(), 1);
+ property->SetSlot(spec->AddStoreICSlot(language_mode), 1);
}
}
break;
}
if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) {
- property->SetSlot(spec->AddStoreICSlot());
+ property->SetSlot(spec->AddStoreICSlot(language_mode));
}
break;
case ObjectLiteral::Property::PROTOTYPE:
break;
case ObjectLiteral::Property::GETTER:
if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) {
- property->SetSlot(spec->AddStoreICSlot());
+ property->SetSlot(spec->AddStoreICSlot(language_mode));
}
break;
case ObjectLiteral::Property::SETTER:
if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) {
- property->SetSlot(spec->AddStoreICSlot());
+ property->SetSlot(spec->AddStoreICSlot(language_mode));
}
break;
}
@@ -447,9 +491,11 @@
Expression* value = property->value();
if (property->kind() != ObjectLiteral::Property::PROTOTYPE) {
if (FunctionLiteral::NeedsHomeObject(value)) {
- property->SetSlot(spec->AddStoreICSlot());
+ property->SetSlot(spec->AddStoreICSlot(language_mode));
}
}
+ property->SetStoreDataPropertySlot(
+ spec->AddStoreDataPropertyInLiteralICSlot());
}
}
@@ -491,13 +537,8 @@
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 +562,43 @@
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 +608,117 @@
set_depth(depth_acc);
}
+void ObjectLiteral::BuildConstantProperties(Isolate* isolate) {
+ if (!constant_properties_.is_null()) return;
+
+ int index_keys = 0;
+ bool has_seen_proto = false;
+ for (int i = 0; i < properties()->length(); i++) {
+ ObjectLiteral::Property* property = properties()->at(i);
+ if (!IsBoilerplateProperty(property)) {
+ has_seen_proto = true;
+ continue;
+ }
+ if (property->is_computed_name()) {
+ continue;
+ }
+
+ Handle<Object> key = property->key()->AsLiteral()->value();
+
+ uint32_t element_index = 0;
+ if (key->ToArrayIndex(&element_index) ||
+ (key->IsString() && String::cast(*key)->AsArrayIndex(&element_index))) {
+ index_keys++;
+ }
+ }
+
+ Handle<BoilerplateDescription> constant_properties =
+ isolate->factory()->NewBoilerplateDescription(boilerplate_properties_,
+ properties()->length(),
+ index_keys, has_seen_proto);
+
+ 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;
+}
+
+ElementsKind ArrayLiteral::constant_elements_kind() const {
+ return static_cast<ElementsKind>(constant_elements()->elements_kind());
+}
+
+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 +731,6 @@
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 +739,6 @@
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 +751,6 @@
if (boilerplate_value->IsUninitialized(isolate)) {
boilerplate_value = handle(Smi::kZero, isolate);
- is_simple = false;
}
kind = GetMoreGeneralElementsKind(kind,
@@ -623,7 +762,7 @@
// 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,21 +776,29 @@
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,
- FeedbackVectorSlotCache* cache) {
+void ArrayLiteral::RewindSpreads() {
+ values_->Rewind(first_spread_index_);
+ first_spread_index_ = -1;
+}
+
+void ArrayLiteral::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+ LanguageMode language_mode,
+ FeedbackSlotCache* cache) {
+ MaterializedLiteral::AssignFeedbackSlots(spec, language_mode, cache);
+
// This logic that computes the number of slots needed for vector store
// ics must mirror FullCodeGenerator::VisitArrayLiteral.
for (int array_index = 0; array_index < values()->length(); array_index++) {
@@ -661,7 +808,7 @@
// We'll reuse the same literal slot for all of the non-constant
// subexpressions that use a keyed store IC.
- literal_slot_ = spec->AddKeyedStoreICSlot();
+ literal_slot_ = spec->AddKeyedStoreICSlot(language_mode);
return;
}
}
@@ -678,6 +825,16 @@
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 +844,6 @@
return AsObjectLiteral()->BuildConstantProperties(isolate);
}
DCHECK(IsRegExpLiteral());
- DCHECK(depth() >= 1); // Depth should be initialized.
}
@@ -710,9 +866,9 @@
set_to_boolean_types(oracle->ToBooleanTypes(right()->test_id()));
}
-void BinaryOperation::AssignFeedbackVectorSlots(
- Isolate* isolate, FeedbackVectorSpec* spec,
- FeedbackVectorSlotCache* cache) {
+void BinaryOperation::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+ LanguageMode language_mode,
+ FeedbackSlotCache* cache) {
// Feedback vector slot is only used by interpreter for binary operations.
// Full-codegen uses AstId to record type feedback.
switch (op()) {
@@ -722,7 +878,7 @@
case Token::OR:
return;
default:
- type_feedback_slot_ = spec->AddInterpreterBinaryOpICSlot();
+ feedback_slot_ = spec->AddInterpreterBinaryOpICSlot();
return;
}
}
@@ -732,9 +888,9 @@
return maybe_unary != NULL && maybe_unary->op() == Token::TYPEOF;
}
-void CompareOperation::AssignFeedbackVectorSlots(
- Isolate* isolate, FeedbackVectorSpec* spec,
- FeedbackVectorSlotCache* cache_) {
+void CompareOperation::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+ LanguageMode language_mode,
+ FeedbackSlotCache* cache_) {
// Feedback vector slot is only used by interpreter for binary operations.
// Full-codegen uses AstId to record type feedback.
switch (op()) {
@@ -743,7 +899,7 @@
case Token::IN:
return;
default:
- type_feedback_slot_ = spec->AddInterpreterCompareICSlot();
+ feedback_slot_ = spec->AddInterpreterCompareICSlot();
}
}
@@ -892,8 +1048,9 @@
}
}
-void Call::AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
- FeedbackVectorSlotCache* cache) {
+void Call::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+ LanguageMode language_mode,
+ FeedbackSlotCache* cache) {
ic_slot_ = spec->AddCallICSlot();
}
@@ -931,10 +1088,10 @@
statements_(statements),
compare_type_(AstType::None()) {}
-void CaseClause::AssignFeedbackVectorSlots(Isolate* isolate,
- FeedbackVectorSpec* spec,
- FeedbackVectorSlotCache* cache) {
- type_feedback_slot_ = spec->AddInterpreterCompareICSlot();
+void CaseClause::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+ LanguageMode language_mode,
+ FeedbackSlotCache* cache) {
+ feedback_slot_ = spec->AddInterpreterCompareICSlot();
}
uint32_t Literal::Hash() {
@@ -952,5 +1109,14 @@
(x->IsNumber() && y->IsNumber() && x->AsNumber() == y->AsNumber());
}
+const char* CallRuntime::debug_name() {
+#ifdef DEBUG
+ return is_jsruntime() ? NameForNativeContextIntrinsicIndex(context_index_)
+ : function_->name;
+#else
+ return is_jsruntime() ? "(context function)" : function_->name;
+#endif // DEBUG
+}
+
} // namespace internal
} // namespace v8
diff --git a/src/ast/ast.h b/src/ast/ast.h
index 99e0672..90e94bb 100644
--- a/src/ast/ast.h
+++ b/src/ast/ast.h
@@ -14,11 +14,12 @@
#include "src/factory.h"
#include "src/globals.h"
#include "src/isolate.h"
+#include "src/label.h"
#include "src/list.h"
+#include "src/objects/literal-objects.h"
#include "src/parsing/token.h"
#include "src/runtime/runtime.h"
#include "src/small-pointer-list.h"
-#include "src/utils.h"
namespace v8 {
namespace internal {
@@ -102,6 +103,7 @@
V(SuperCallReference) \
V(CaseClause) \
V(EmptyParentheses) \
+ V(GetIterator) \
V(DoExpression) \
V(RewritableExpression)
@@ -125,27 +127,29 @@
AST_NODE_LIST(DEF_FORWARD_DECLARATION)
#undef DEF_FORWARD_DECLARATION
-
-class FeedbackVectorSlotCache {
+class FeedbackSlotCache {
public:
- explicit FeedbackVectorSlotCache(Zone* zone)
- : zone_(zone),
- hash_map_(ZoneHashMap::kDefaultHashMapCapacity,
- ZoneAllocationPolicy(zone)) {}
+ typedef std::pair<TypeofMode, Variable*> Key;
- void Put(Variable* variable, FeedbackVectorSlot slot) {
- ZoneHashMap::Entry* entry = hash_map_.LookupOrInsert(
- variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone_));
- entry->value = reinterpret_cast<void*>(slot.ToInt());
+ explicit FeedbackSlotCache(Zone* zone) : map_(zone) {}
+
+ void Put(TypeofMode typeof_mode, Variable* variable, FeedbackSlot slot) {
+ Key key = std::make_pair(typeof_mode, variable);
+ auto entry = std::make_pair(key, slot);
+ map_.insert(entry);
}
- ZoneHashMap::Entry* Get(Variable* variable) const {
- return hash_map_.Lookup(variable, ComputePointerHash(variable));
+ FeedbackSlot Get(TypeofMode typeof_mode, Variable* variable) const {
+ Key key = std::make_pair(typeof_mode, variable);
+ auto iter = map_.find(key);
+ if (iter != map_.end()) {
+ return iter->second;
+ }
+ return FeedbackSlot();
}
private:
- Zone* zone_;
- ZoneHashMap hash_map_;
+ ZoneMap<Key, FeedbackSlot> map_;
};
@@ -154,7 +158,7 @@
enum Flag {
kNoFlags = 0,
kDontSelfOptimize = 1 << 0,
- kDontCrankshaft = 1 << 1
+ kMustUseIgnitionTurbo = 1 << 1
};
typedef base::Flags<Flag> Flags;
@@ -190,6 +194,7 @@
int position() const { return position_; }
#ifdef DEBUG
+ void Print();
void Print(Isolate* isolate);
#endif // DEBUG
@@ -317,6 +322,9 @@
// 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 +474,6 @@
class IgnoreCompletionField
: public BitField<bool, BreakableStatement::kNextBitFieldIndex, 1> {};
-
- protected:
- static const uint8_t kNextBitFieldIndex = IgnoreCompletionField::kNext;
};
@@ -484,9 +489,6 @@
}
bool IsAnonymousFunctionDefinition() const;
- protected:
- static const uint8_t kNextBitFieldIndex = Expression::kNextBitFieldIndex;
-
private:
friend class AstNodeFactory;
@@ -518,8 +520,6 @@
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,10 +734,10 @@
void set_subject(Expression* e) { subject_ = e; }
// Type feedback information.
- void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
- FeedbackVectorSlotCache* cache);
- FeedbackVectorSlot EachFeedbackSlot() const { return each_slot_; }
- FeedbackVectorSlot ForInFeedbackSlot() {
+ void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+ FeedbackSlotCache* cache);
+ FeedbackSlot EachFeedbackSlot() const { return each_slot_; }
+ FeedbackSlot ForInFeedbackSlot() {
DCHECK(!for_in_feedback_slot_.IsInvalid());
return for_in_feedback_slot_;
}
@@ -773,14 +773,11 @@
Expression* each_;
Expression* subject_;
- FeedbackVectorSlot each_slot_;
- FeedbackVectorSlot for_in_feedback_slot_;
+ FeedbackSlot each_slot_;
+ FeedbackSlot for_in_feedback_slot_;
class ForInTypeField
: public BitField<ForInType, ForEachStatement::kNextBitFieldIndex, 1> {};
-
- protected:
- static const uint8_t kNextBitFieldIndex = ForInTypeField::kNext;
};
@@ -826,12 +823,6 @@
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 +833,6 @@
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_;
@@ -908,17 +897,25 @@
class ReturnStatement final : public JumpStatement {
public:
+ enum Type { kNormal, kAsyncReturn };
Expression* expression() const { return expression_; }
void set_expression(Expression* e) { expression_ = e; }
+ Type type() const { return TypeField::decode(bit_field_); }
+ bool is_async_return() const { return type() == kAsyncReturn; }
private:
friend class AstNodeFactory;
- ReturnStatement(Expression* expression, int pos)
- : JumpStatement(pos, kReturnStatement), expression_(expression) {}
+ ReturnStatement(Expression* expression, Type type, int pos)
+ : JumpStatement(pos, kReturnStatement), expression_(expression) {
+ bit_field_ |= TypeField::encode(type);
+ }
Expression* expression_;
+
+ class TypeField
+ : public BitField<Type, JumpStatement::kNextBitFieldIndex, 1> {};
};
@@ -930,30 +927,16 @@
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,12 +964,10 @@
// 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,
- FeedbackVectorSlotCache* cache);
+ void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+ FeedbackSlotCache* cache);
- FeedbackVectorSlot CompareOperationFeedbackSlot() {
- return type_feedback_slot_;
- }
+ FeedbackSlot CompareOperationFeedbackSlot() { return feedback_slot_; }
private:
friend class AstNodeFactory;
@@ -999,7 +980,7 @@
Label body_target_;
ZoneList<Statement*>* statements_;
AstType* compare_type_;
- FeedbackVectorSlot type_feedback_slot_;
+ FeedbackSlot feedback_slot_;
};
@@ -1174,26 +1155,10 @@
class DebuggerStatement final : public Statement {
- public:
- void set_base_id(int id) { base_id_ = id; }
- static int num_ids() { return parent_num_ids() + 1; }
- BailoutId DebugBreakId() const { return BailoutId(local_id(0)); }
-
private:
friend class AstNodeFactory;
- explicit DebuggerStatement(int pos)
- : Statement(pos, kDebuggerStatement),
- base_id_(BailoutId::None().ToInt()) {}
-
- 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_;
+ explicit DebuggerStatement(int pos) : Statement(pos, kDebuggerStatement) {}
};
@@ -1212,22 +1177,15 @@
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_;
};
@@ -1275,32 +1233,32 @@
const AstValue* value_;
};
-
-class AstLiteralReindexer;
-
-// Base class for literals that needs space in the corresponding JSFunction.
+// Base class for literals that need space in the type feedback vector.
class MaterializedLiteral : public Expression {
public:
- int literal_index() { return literal_index_; }
-
int depth() const {
// only callable after initialization.
DCHECK(depth_ >= 1);
return depth_;
}
+ void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+ FeedbackSlotCache* cache) {
+ literal_slot_ = spec->AddLiteralSlot();
+ }
+
+ FeedbackSlot literal_slot() const { return literal_slot_; }
+
private:
int depth_ : 31;
- int literal_index_;
-
- friend class AstLiteralReindexer;
+ FeedbackSlot literal_slot_;
class IsSimpleField
: public BitField<bool, Expression::kNextBitFieldIndex, 1> {};
protected:
- MaterializedLiteral(int literal_index, int pos, NodeType type)
- : Expression(pos, type), depth_(0), literal_index_(literal_index) {
+ MaterializedLiteral(int pos, NodeType type)
+ : Expression(pos, type), depth_(0) {
bit_field_ |= IsSimpleField::encode(false);
}
@@ -1317,6 +1275,9 @@
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;
@@ -1342,16 +1303,20 @@
bool is_computed_name() const { return is_computed_name_; }
- FeedbackVectorSlot GetSlot(int offset = 0) const {
+ FeedbackSlot GetSlot(int offset = 0) const {
DCHECK_LT(offset, static_cast<int>(arraysize(slots_)));
return slots_[offset];
}
- void SetSlot(FeedbackVectorSlot slot, int offset = 0) {
+ FeedbackSlot GetStoreDataPropertySlot() const;
+
+ void SetSlot(FeedbackSlot slot, int offset = 0) {
DCHECK_LT(offset, static_cast<int>(arraysize(slots_)));
slots_[offset] = slot;
}
+ void SetStoreDataPropertySlot(FeedbackSlot slot);
+
bool NeedsSetFunctionName() const;
protected:
@@ -1360,7 +1325,7 @@
Expression* key_;
Expression* value_;
- FeedbackVectorSlot slots_[2];
+ FeedbackSlot slots_[2];
bool is_computed_name_;
};
@@ -1374,8 +1339,9 @@
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_; }
@@ -1411,7 +1377,8 @@
public:
typedef ObjectLiteralProperty Property;
- Handle<FixedArray> constant_properties() const {
+ Handle<BoilerplateDescription> constant_properties() const {
+ DCHECK(!constant_properties_.is_null());
return constant_properties_;
}
int properties_count() const { return boilerplate_properties_; }
@@ -1424,10 +1391,25 @@
bool has_shallow_properties() const {
return depth() == 1 && !has_elements() && !may_store_doubles();
}
+ bool has_rest_property() const {
+ return HasRestPropertyField::decode(bit_field_);
+ }
// Decide if a property should be in the object boilerplate.
static bool IsBoilerplateProperty(Property* property);
+ // Populate the depth field and flags.
+ void InitDepthAndFlags();
+
+ // Get the constant properties fixed array, populating it if necessary.
+ Handle<BoilerplateDescription> 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 +1418,9 @@
// 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;
@@ -1452,7 +1437,8 @@
kNoFlags = 0,
kFastElements = 1,
kShallowProperties = 1 << 1,
- kDisableMementos = 1 << 2
+ kDisableMementos = 1 << 2,
+ kHasRestProperty = 1 << 3,
};
struct Accessors: public ZoneObject {
@@ -1465,43 +1451,37 @@
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,
- FeedbackVectorSlotCache* cache);
+ void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+ FeedbackSlotCache* cache);
private:
friend class AstNodeFactory;
- ObjectLiteral(ZoneList<Property*>* properties, int literal_index,
- uint32_t boilerplate_properties, int pos)
- : MaterializedLiteral(literal_index, pos, kObjectLiteral),
+ ObjectLiteral(ZoneList<Property*>* properties,
+ uint32_t boilerplate_properties, int pos,
+ bool has_rest_property)
+ : MaterializedLiteral(pos, kObjectLiteral),
boilerplate_properties_(boilerplate_properties),
properties_(properties) {
bit_field_ |= FastElementsField::encode(false) |
HasElementsField::encode(false) |
- MayStoreDoublesField::encode(false);
+ MayStoreDoublesField::encode(false) |
+ HasRestPropertyField::encode(has_rest_property);
}
static int parent_num_ids() { return MaterializedLiteral::num_ids(); }
int local_id(int n) const { return base_id() + parent_num_ids() + n; }
uint32_t boilerplate_properties_;
- FeedbackVectorSlot slot_;
- Handle<FixedArray> constant_properties_;
+ Handle<BoilerplateDescription> constant_properties_;
ZoneList<Property*>* properties_;
class FastElementsField
@@ -1510,9 +1490,8 @@
};
class MayStoreDoublesField
: public BitField<bool, HasElementsField::kNext, 1> {};
-
- protected:
- static const uint8_t kNextBitFieldIndex = MayStoreDoublesField::kNext;
+ class HasRestPropertyField
+ : public BitField<bool, MayStoreDoublesField::kNext, 1> {};
};
@@ -1543,14 +1522,14 @@
class RegExpLiteral final : public MaterializedLiteral {
public:
Handle<String> pattern() const { return pattern_->string(); }
+ const AstRawString* raw_pattern() const { return pattern_; }
int flags() const { return flags_; }
private:
friend class AstNodeFactory;
- RegExpLiteral(const AstRawString* pattern, int flags, int literal_index,
- int pos)
- : MaterializedLiteral(literal_index, pos, kRegExpLiteral),
+ RegExpLiteral(const AstRawString* pattern, int flags, int pos)
+ : MaterializedLiteral(pos, kRegExpLiteral),
flags_(flags),
pattern_(pattern) {
set_depth(1);
@@ -1565,12 +1544,10 @@
// for minimizing the work when constructing it at runtime.
class ArrayLiteral final : public MaterializedLiteral {
public:
- Handle<FixedArray> 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());
+ Handle<ConstantElementsPair> constant_elements() const {
+ return constant_elements_;
}
+ ElementsKind constant_elements_kind() const;
ZoneList<Expression*>* values() const { return values_; }
@@ -1583,9 +1560,23 @@
// 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;
@@ -1603,10 +1594,7 @@
ZoneList<Expression*>::iterator EndValue() const { return values_->end(); }
// Rewind an array literal omitting everything from the first spread on.
- void RewindSpreads() {
- values_->Rewind(first_spread_index_);
- first_spread_index_ = -1;
- }
+ void RewindSpreads();
enum Flags {
kNoFlags = 0,
@@ -1614,16 +1602,15 @@
kDisableMementos = 1 << 1
};
- void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
- FeedbackVectorSlotCache* cache);
- FeedbackVectorSlot LiteralFeedbackSlot() const { return literal_slot_; }
+ void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+ FeedbackSlotCache* cache);
+ FeedbackSlot LiteralFeedbackSlot() const { return literal_slot_; }
private:
friend class AstNodeFactory;
- ArrayLiteral(ZoneList<Expression*>* values, int first_spread_index,
- int literal_index, int pos)
- : MaterializedLiteral(literal_index, pos, kArrayLiteral),
+ ArrayLiteral(ZoneList<Expression*>* values, int first_spread_index, int pos)
+ : MaterializedLiteral(pos, kArrayLiteral),
first_spread_index_(first_spread_index),
values_(values) {}
@@ -1631,8 +1618,8 @@
int local_id(int n) const { return base_id() + parent_num_ids() + n; }
int first_spread_index_;
- FeedbackVectorSlot literal_slot_;
- Handle<FixedArray> constant_elements_;
+ FeedbackSlot literal_slot_;
+ Handle<ConstantElementsPair> constant_elements_;
ZoneList<Expression*>* values_;
};
@@ -1663,6 +1650,9 @@
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,10 +1680,10 @@
return var()->IsUnallocated() || var()->IsLookupSlot();
}
- void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
- FeedbackVectorSlotCache* cache);
+ void AssignFeedbackSlots(FeedbackVectorSpec* spec, TypeofMode typeof_mode,
+ FeedbackSlotCache* cache);
- FeedbackVectorSlot VariableFeedbackSlot() { return variable_feedback_slot_; }
+ FeedbackSlot VariableFeedbackSlot() { return variable_feedback_slot_; }
static int num_ids() { return parent_num_ids() + 1; }
BailoutId BeforeId() const { return BailoutId(local_id(0)); }
@@ -1719,7 +1709,7 @@
class HoleCheckModeField
: public BitField<HoleCheckMode, IsNewTargetField::kNext, 1> {};
- FeedbackVectorSlot variable_feedback_slot_;
+ FeedbackSlot variable_feedback_slot_;
union {
const AstRawString* raw_name_; // if !is_resolved_
Variable* var_; // if is_resolved_
@@ -1786,17 +1776,16 @@
bool IsSuperAccess() { return obj()->IsSuperPropertyReference(); }
- void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
- FeedbackVectorSlotCache* cache) {
- FeedbackVectorSlotKind kind = key()->IsPropertyName()
- ? FeedbackVectorSlotKind::LOAD_IC
- : FeedbackVectorSlotKind::KEYED_LOAD_IC;
- property_feedback_slot_ = spec->AddSlot(kind);
+ void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+ FeedbackSlotCache* cache) {
+ if (key()->IsPropertyName()) {
+ property_feedback_slot_ = spec->AddLoadICSlot();
+ } else {
+ property_feedback_slot_ = spec->AddKeyedLoadICSlot();
+ }
}
- FeedbackVectorSlot PropertyFeedbackSlot() const {
- return property_feedback_slot_;
- }
+ FeedbackSlot PropertyFeedbackSlot() const { return property_feedback_slot_; }
// Returns the properties assign type.
static LhsKind GetAssignType(Property* property) {
@@ -1829,7 +1818,7 @@
class InlineCacheStateField
: public BitField<InlineCacheState, KeyTypeField::kNext, 4> {};
- FeedbackVectorSlot property_feedback_slot_;
+ FeedbackSlot property_feedback_slot_;
Expression* obj_;
Expression* key_;
SmallMapList receiver_types_;
@@ -1844,10 +1833,10 @@
void set_expression(Expression* e) { expression_ = e; }
// Type feedback information.
- void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
- FeedbackVectorSlotCache* cache);
+ void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+ FeedbackSlotCache* cache);
- FeedbackVectorSlot CallFeedbackICSlot() const { return ic_slot_; }
+ FeedbackSlot CallFeedbackICSlot() const { return ic_slot_; }
SmallMapList* GetReceiverTypes() {
if (expression()->IsProperty()) {
@@ -1876,11 +1865,9 @@
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_);
@@ -1899,6 +1886,10 @@
}
void MarkTail() { bit_field_ = IsTailField::update(bit_field_, true); }
+ bool only_last_arg_is_spread() {
+ return !arguments_->is_empty() && arguments_->last()->IsSpread();
+ }
+
enum CallType {
GLOBAL_CALL,
WITH_CALL,
@@ -1948,7 +1939,7 @@
class IsTailField : public BitField<bool, IsUninitializedField::kNext, 1> {};
class IsPossiblyEvalField : public BitField<bool, IsTailField::kNext, 1> {};
- FeedbackVectorSlot ic_slot_;
+ FeedbackSlot ic_slot_;
Expression* expression_;
ZoneList<Expression*>* arguments_;
Handle<JSFunction> target_;
@@ -1964,14 +1955,14 @@
void set_expression(Expression* e) { expression_ = e; }
// Type feedback information.
- void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
- FeedbackVectorSlotCache* cache) {
+ void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+ FeedbackSlotCache* cache) {
// CallNew stores feedback in the exact same way as Call. We can
// piggyback on the type feedback infrastructure for calls.
callnew_feedback_slot_ = spec->AddCallICSlot();
}
- FeedbackVectorSlot CallNewFeedbackSlot() {
+ FeedbackSlot CallNewFeedbackSlot() {
DCHECK(!callnew_feedback_slot_.IsInvalid());
return callnew_feedback_slot_;
}
@@ -1998,6 +1989,10 @@
set_is_monomorphic(true);
}
+ bool only_last_arg_is_spread() {
+ return !arguments_->is_empty() && arguments_->last()->IsSpread();
+ }
+
private:
friend class AstNodeFactory;
@@ -2011,7 +2006,7 @@
static int parent_num_ids() { return Expression::num_ids(); }
int local_id(int n) const { return base_id() + parent_num_ids() + n; }
- FeedbackVectorSlot callnew_feedback_slot_;
+ FeedbackSlot callnew_feedback_slot_;
Expression* expression_;
ZoneList<Expression*>* arguments_;
Handle<JSFunction> target_;
@@ -2046,10 +2041,7 @@
static int num_ids() { return parent_num_ids() + 1; }
BailoutId CallId() { return BailoutId(local_id(0)); }
-
- const char* debug_name() {
- return is_jsruntime() ? "(context function)" : function_->name;
- }
+ const char* debug_name();
private:
friend class AstNodeFactory;
@@ -2138,12 +2130,10 @@
// 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,
- FeedbackVectorSlotCache* cache);
+ void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+ FeedbackSlotCache* cache);
- FeedbackVectorSlot BinaryOperationFeedbackSlot() const {
- return type_feedback_slot_;
- }
+ FeedbackSlot BinaryOperationFeedbackSlot() const { return feedback_slot_; }
TypeFeedbackId BinaryOperationFeedbackId() const {
return TypeFeedbackId(local_id(1));
@@ -2181,7 +2171,7 @@
Expression* left_;
Expression* right_;
Handle<AllocationSite> allocation_site_;
- FeedbackVectorSlot type_feedback_slot_;
+ FeedbackSlot feedback_slot_;
class OperatorField
: public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {};
@@ -2227,13 +2217,13 @@
}
// Feedback slot for binary operation is only used by ignition.
- FeedbackVectorSlot CountBinaryOpFeedbackSlot() const {
+ FeedbackSlot CountBinaryOpFeedbackSlot() const {
return binary_operation_slot_;
}
- void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
- FeedbackVectorSlotCache* cache);
- FeedbackVectorSlot CountSlot() const { return slot_; }
+ void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+ FeedbackSlotCache* cache);
+ FeedbackSlot CountSlot() const { return slot_; }
private:
friend class AstNodeFactory;
@@ -2255,8 +2245,8 @@
: public BitField<KeyedAccessStoreMode, KeyTypeField::kNext, 3> {};
class TokenField : public BitField<Token::Value, StoreModeField::kNext, 7> {};
- FeedbackVectorSlot slot_;
- FeedbackVectorSlot binary_operation_slot_;
+ FeedbackSlot slot_;
+ FeedbackSlot binary_operation_slot_;
AstType* type_;
Expression* expression_;
SmallMapList receiver_types_;
@@ -2283,12 +2273,10 @@
// 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,
- FeedbackVectorSlotCache* cache);
+ void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+ FeedbackSlotCache* cache);
- FeedbackVectorSlot CompareOperationFeedbackSlot() const {
- return type_feedback_slot_;
- }
+ FeedbackSlot CompareOperationFeedbackSlot() const { return feedback_slot_; }
// Match special cases.
bool IsLiteralCompareTypeof(Expression** expr, Handle<String>* check);
@@ -2315,7 +2303,7 @@
Expression* right_;
AstType* combined_type_;
- FeedbackVectorSlot type_feedback_slot_;
+ FeedbackSlot feedback_slot_;
class OperatorField
: public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {};
};
@@ -2429,9 +2417,9 @@
bit_field_ = StoreModeField::update(bit_field_, mode);
}
- void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
- FeedbackVectorSlotCache* cache);
- FeedbackVectorSlot AssignmentSlot() const { return slot_; }
+ void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+ FeedbackSlotCache* cache);
+ FeedbackSlot AssignmentSlot() const { return slot_; }
private:
friend class AstNodeFactory;
@@ -2449,7 +2437,7 @@
: public BitField<KeyedAccessStoreMode, KeyTypeField::kNext, 3> {};
class TokenField : public BitField<Token::Value, StoreModeField::kNext, 7> {};
- FeedbackVectorSlot slot_;
+ FeedbackSlot slot_;
Expression* target_;
Expression* value_;
BinaryOperation* binary_operation_;
@@ -2571,6 +2559,8 @@
kAccessorOrMethod
};
+ enum IdType { kIdTypeInvalid = -1, kIdTypeTopLevel = 0 };
+
enum ParameterFlag { kNoDuplicateParameters, kHasDuplicateParameters };
enum EagerCompileHint { kShouldEagerCompile, kShouldLazyCompile };
@@ -2594,9 +2584,15 @@
}
LanguageMode language_mode() const;
+ void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+ FeedbackSlotCache* cache) {
+ literal_feedback_slot_ = spec->AddCreateClosureSlot();
+ }
+
+ FeedbackSlot LiteralFeedbackSlot() const { return literal_feedback_slot_; }
+
static bool NeedsHomeObject(Expression* expr);
- int materialized_literal_count() { return materialized_literal_count_; }
int expected_property_count() { return expected_property_count_; }
int parameter_count() { return parameter_count_; }
int function_length() { return function_length_; }
@@ -2644,8 +2640,6 @@
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,38 +2685,27 @@
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;
FunctionLiteral(Zone* zone, const AstString* name,
AstValueFactory* ast_value_factory, DeclarationScope* scope,
- ZoneList<Statement*>* body, int materialized_literal_count,
- int expected_property_count, int parameter_count,
- int function_length, FunctionType function_type,
+ ZoneList<Statement*>* body, int expected_property_count,
+ int parameter_count, 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),
parameter_count_(parameter_count),
function_length_(function_length),
@@ -2733,16 +2716,14 @@
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,17 +2731,12 @@
: 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_;
int parameter_count_;
int function_length_;
@@ -2774,6 +2750,8 @@
const AstString* raw_inferred_name_;
Handle<String> inferred_name_;
AstProperties ast_properties_;
+ int function_literal_id_;
+ FeedbackSlot literal_feedback_slot_;
};
// Property is used for passing information
@@ -2808,62 +2786,55 @@
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,
- FeedbackVectorSlotCache* cache);
+ void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+ FeedbackSlotCache* cache);
bool NeedsProxySlot() const {
return class_variable_proxy() != nullptr &&
class_variable_proxy()->var()->IsUnallocated();
}
- FeedbackVectorSlot PrototypeSlot() const { return prototype_slot_; }
- FeedbackVectorSlot ProxySlot() const { return proxy_slot_; }
+ FeedbackSlot HomeObjectSlot() const { return home_object_slot_; }
+ FeedbackSlot ProxySlot() const { return proxy_slot_; }
private:
friend class AstNodeFactory;
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 proxy_slot_;
+ FeedbackSlot home_object_slot_;
+ FeedbackSlot 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 +2842,14 @@
public:
Handle<String> name() const { return name_->string(); }
v8::Extension* extension() const { return extension_; }
+ FeedbackSlot LiteralFeedbackSlot() const { return literal_feedback_slot_; }
+
+ void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+ FeedbackSlotCache* cache) {
+ // TODO(mvstanton): The FeedbackSlotCache can be adapted
+ // to always return the same slot for this case.
+ literal_feedback_slot_ = spec->AddCreateClosureSlot();
+ }
private:
friend class AstNodeFactory;
@@ -2883,6 +2862,7 @@
const AstRawString* name_;
v8::Extension* extension_;
+ FeedbackSlot literal_feedback_slot_;
};
@@ -2955,7 +2935,59 @@
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.
+enum class IteratorType { kNormal, kAsync };
+class GetIterator final : public Expression {
+ public:
+ IteratorType hint() const { return hint_; }
+ Expression* iterable() const { return iterable_; }
+ void set_iterable(Expression* iterable) { iterable_ = iterable; }
+
+ static int num_ids() { return parent_num_ids(); }
+
+ void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+ FeedbackSlotCache* cache) {
+ iterator_property_feedback_slot_ = spec->AddLoadICSlot();
+ iterator_call_feedback_slot_ = spec->AddCallICSlot();
+ if (hint() == IteratorType::kAsync) {
+ async_iterator_property_feedback_slot_ = spec->AddLoadICSlot();
+ async_iterator_call_feedback_slot_ = spec->AddCallICSlot();
+ }
+ }
+
+ FeedbackSlot IteratorPropertyFeedbackSlot() const {
+ return iterator_property_feedback_slot_;
+ }
+
+ FeedbackSlot IteratorCallFeedbackSlot() const {
+ return iterator_call_feedback_slot_;
+ }
+
+ FeedbackSlot AsyncIteratorPropertyFeedbackSlot() const {
+ return async_iterator_property_feedback_slot_;
+ }
+
+ FeedbackSlot AsyncIteratorCallFeedbackSlot() const {
+ return async_iterator_call_feedback_slot_;
+ }
+
+ private:
+ friend class AstNodeFactory;
+
+ explicit GetIterator(Expression* iterable, IteratorType hint, int pos)
+ : Expression(pos, kGetIterator), hint_(hint), iterable_(iterable) {}
+
+ IteratorType hint_;
+ Expression* iterable_;
+ FeedbackSlot iterator_property_feedback_slot_;
+ FeedbackSlot iterator_call_feedback_slot_;
+ FeedbackSlot async_iterator_property_feedback_slot_;
+ FeedbackSlot async_iterator_call_feedback_slot_;
+};
// ----------------------------------------------------------------------------
// Basic visitor
@@ -3170,6 +3202,11 @@
return NULL;
}
+ ForOfStatement* NewForOfStatement(ZoneList<const AstRawString*>* labels,
+ int pos) {
+ return new (zone_) ForOfStatement(labels, pos);
+ }
+
ExpressionStatement* NewExpressionStatement(Expression* expression, int pos) {
return new (zone_) ExpressionStatement(expression, pos);
}
@@ -3183,7 +3220,13 @@
}
ReturnStatement* NewReturnStatement(Expression* expression, int pos) {
- return new (zone_) ReturnStatement(expression, pos);
+ return new (zone_)
+ ReturnStatement(expression, ReturnStatement::kNormal, pos);
+ }
+
+ ReturnStatement* NewAsyncReturnStatement(Expression* expression, int pos) {
+ return new (zone_)
+ ReturnStatement(expression, ReturnStatement::kAsyncReturn, pos);
}
WithStatement* NewWithStatement(Scope* scope,
@@ -3217,15 +3260,6 @@
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 +3292,9 @@
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(
@@ -3273,8 +3307,8 @@
}
// A JavaScript symbol (ECMA-262 edition 6).
- Literal* NewSymbolLiteral(const char* name, int pos) {
- return new (zone_) Literal(ast_value_factory_->NewSymbol(name), pos);
+ Literal* NewSymbolLiteral(AstSymbol symbol, int pos) {
+ return new (zone_) Literal(ast_value_factory_->NewSymbol(symbol), pos);
}
Literal* NewNumberLiteral(double number, int pos, bool with_dot = false) {
@@ -3303,10 +3337,10 @@
}
ObjectLiteral* NewObjectLiteral(
- ZoneList<ObjectLiteral::Property*>* properties, int literal_index,
- uint32_t boilerplate_properties, int pos) {
- return new (zone_)
- ObjectLiteral(properties, literal_index, boilerplate_properties, pos);
+ ZoneList<ObjectLiteral::Property*>* properties,
+ uint32_t boilerplate_properties, int pos, bool has_rest_property) {
+ return new (zone_) ObjectLiteral(properties, boilerplate_properties, pos,
+ has_rest_property);
}
ObjectLiteral::Property* NewObjectLiteralProperty(
@@ -3324,21 +3358,18 @@
}
RegExpLiteral* NewRegExpLiteral(const AstRawString* pattern, int flags,
- int literal_index, int pos) {
- return new (zone_) RegExpLiteral(pattern, flags, literal_index, pos);
+ int pos) {
+ return new (zone_) RegExpLiteral(pattern, flags, pos);
}
ArrayLiteral* NewArrayLiteral(ZoneList<Expression*>* values,
- int literal_index,
int pos) {
- return new (zone_) ArrayLiteral(values, -1, literal_index, pos);
+ return new (zone_) ArrayLiteral(values, -1, pos);
}
ArrayLiteral* NewArrayLiteral(ZoneList<Expression*>* values,
- int first_spread_index, int literal_index,
- int pos) {
- return new (zone_)
- ArrayLiteral(values, first_spread_index, literal_index, pos);
+ int first_spread_index, int pos) {
+ return new (zone_) ArrayLiteral(values, first_spread_index, pos);
}
VariableProxy* NewVariableProxy(Variable* var,
@@ -3437,9 +3468,13 @@
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);
}
@@ -3458,32 +3493,33 @@
FunctionLiteral* NewFunctionLiteral(
const AstRawString* name, DeclarationScope* scope,
- ZoneList<Statement*>* body, int materialized_literal_count,
- int expected_property_count, int parameter_count, int function_length,
+ ZoneList<Statement*>* body, int expected_property_count,
+ int parameter_count, int function_length,
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);
+ zone_, name, ast_value_factory_, scope, body, expected_property_count,
+ parameter_count, function_length, function_type,
+ has_duplicate_parameters, eager_compile_hint, position, has_braces,
+ function_literal_id);
}
// Creates a FunctionLiteral representing a top-level script, the
// result of an eval (top-level or otherwise), or the result of calling
// the Function constructor.
- FunctionLiteral* NewScriptOrEvalFunctionLiteral(
- DeclarationScope* scope, ZoneList<Statement*>* body,
- int materialized_literal_count, int expected_property_count,
- int parameter_count) {
+ FunctionLiteral* NewScriptOrEvalFunctionLiteral(DeclarationScope* scope,
+ ZoneList<Statement*>* body,
+ int expected_property_count,
+ int parameter_count) {
return new (zone_) FunctionLiteral(
zone_, ast_value_factory_->empty_string(), ast_value_factory_, scope,
- body, materialized_literal_count, expected_property_count,
- parameter_count, parameter_count, FunctionLiteral::kAnonymousExpression,
+ body, 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 +3532,12 @@
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 +3573,11 @@
return new (zone_) EmptyParentheses(pos);
}
+ GetIterator* NewGetIterator(Expression* iterable, IteratorType hint,
+ int pos) {
+ return new (zone_) GetIterator(iterable, hint, pos);
+ }
+
Zone* zone() const { return zone_; }
void set_zone(Zone* zone) { zone_ = zone; }
diff --git a/src/ast/compile-time-value.cc b/src/ast/compile-time-value.cc
index eda536b..27dd29f 100644
--- a/src/ast/compile-time-value.cc
+++ b/src/ast/compile-time-value.cc
@@ -48,8 +48,8 @@
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/src/ast/compile-time-value.h b/src/ast/compile-time-value.h
index 27351b7..d61443e 100644
--- a/src/ast/compile-time-value.h
+++ b/src/ast/compile-time-value.h
@@ -31,8 +31,8 @@
// 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/src/ast/context-slot-cache.cc b/src/ast/context-slot-cache.cc
index b1387e1..4548218 100644
--- a/src/ast/context-slot-cache.cc
+++ b/src/ast/context-slot-cache.cc
@@ -12,9 +12,9 @@
// (disallowed) include: src/factory.h -> src/objects-inl.h
#include "src/objects-inl.h"
// FIXME(mstarzinger, marja): This is weird, but required because of the missing
-// (disallowed) include: src/type-feedback-vector.h ->
-// src/type-feedback-vector-inl.h
-#include "src/type-feedback-vector-inl.h"
+// (disallowed) include: src/feedback-vector.h ->
+// src/feedback-vector-inl.h
+#include "src/feedback-vector-inl.h"
namespace v8 {
namespace internal {
diff --git a/src/ast/modules.cc b/src/ast/modules.cc
index 339d64c..9d3a235 100644
--- a/src/ast/modules.cc
+++ b/src/ast/modules.cc
@@ -5,6 +5,9 @@
#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"
+#include "src/pending-compilation-error-handler.h"
namespace v8 {
namespace internal {
diff --git a/src/ast/modules.h b/src/ast/modules.h
index 94550fb..ce8aba8 100644
--- a/src/ast/modules.h
+++ b/src/ast/modules.h
@@ -6,7 +6,6 @@
#define V8_AST_MODULES_H_
#include "src/parsing/scanner.h" // Only for Scanner::Location.
-#include "src/pending-compilation-error-handler.h"
#include "src/zone/zone-containers.h"
namespace v8 {
@@ -16,6 +15,7 @@
class AstRawString;
class ModuleInfo;
class ModuleInfoEntry;
+class PendingCompilationErrorHandler;
class ModuleDescriptor : public ZoneObject {
public:
diff --git a/src/ast/prettyprinter.cc b/src/ast/prettyprinter.cc
index a3fc50a..725a8a7 100644
--- a/src/ast/prettyprinter.cc
+++ b/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::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::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::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 @@
UNREACHABLE();
}
+void CallPrinter::VisitGetIterator(GetIterator* node) {
+ Print("GetIterator(");
+ Find(node->iterable(), true);
+ Print(")");
+}
void CallPrinter::VisitThisFunction(ThisFunction* node) {}
@@ -434,9 +440,9 @@
#ifdef DEBUG
-// A helper for ast nodes that use FeedbackVectorSlots.
+// A helper for ast nodes that use FeedbackSlots.
static int FormatSlotNode(Vector<char>* buf, Expression* node,
- const char* node_name, FeedbackVectorSlot slot) {
+ const char* node_name, FeedbackSlot slot) {
int pos = SNPrintF(*buf, "%s", node_name);
if (!slot.IsInvalid()) {
pos += SNPrintF(*buf + pos, " Slot(%d)", slot.ToInt());
@@ -874,15 +880,16 @@
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);
}
@@ -971,7 +978,7 @@
void AstPrinter::VisitRegExpLiteral(RegExpLiteral* node) {
IndentedScope indent(this, "REGEXP LITERAL", node->position());
EmbeddedVector<char, 128> buf;
- SNPrintF(buf, "literal_index = %d\n", node->literal_index());
+ SNPrintF(buf, "literal_slot = %d\n", node->literal_slot().ToInt());
PrintIndented(buf.start());
PrintLiteralIndented("PATTERN", node->pattern(), false);
int i = 0;
@@ -990,7 +997,7 @@
void AstPrinter::VisitObjectLiteral(ObjectLiteral* node) {
IndentedScope indent(this, "OBJ LITERAL", node->position());
EmbeddedVector<char, 128> buf;
- SNPrintF(buf, "literal_index = %d\n", node->literal_index());
+ SNPrintF(buf, "literal_slot = %d\n", node->literal_slot().ToInt());
PrintIndented(buf.start());
PrintObjectProperties(node->properties());
}
@@ -1019,6 +1026,9 @@
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);
@@ -1033,7 +1043,7 @@
IndentedScope indent(this, "ARRAY LITERAL", node->position());
EmbeddedVector<char, 128> buf;
- SNPrintF(buf, "literal_index = %d\n", node->literal_index());
+ SNPrintF(buf, "literal_slot = %d\n", node->literal_slot().ToInt());
PrintIndented(buf.start());
if (node->values()->length() > 0) {
IndentedScope indent(this, "VALUES", node->position());
@@ -1136,7 +1146,14 @@
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 @@
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/src/ast/prettyprinter.h b/src/ast/prettyprinter.h
index b56c834..fdc079c 100644
--- a/src/ast/prettyprinter.h
+++ b/src/ast/prettyprinter.h
@@ -15,7 +15,7 @@
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 @@
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/src/ast/scopeinfo.cc b/src/ast/scopeinfo.cc
deleted file mode 100644
index 3a3ea03..0000000
--- a/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/src/ast/scopes.cc b/src/ast/scopes.cc
index c1679a4..225793c 100644
--- a/src/ast/scopes.cc
+++ b/src/ast/scopes.cc
@@ -9,12 +9,29 @@
#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/objects/scope-info.h"
#include "src/parsing/parse-info.h"
+#include "src/parsing/preparsed-scope-data.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 +66,20 @@
return reinterpret_cast<Variable*>(p->value);
}
+Variable* 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;
+ }
+ return reinterpret_cast<Variable*>(p->value);
+}
+
void VariableMap::Remove(Variable* var) {
const AstRawString* name = var->raw_name();
ZoneHashMap::Remove(const_cast<AstRawString*>(name), name->hash());
@@ -74,21 +105,27 @@
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 +280,7 @@
// 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);
}
@@ -261,9 +297,16 @@
new_target_ = nullptr;
function_ = nullptr;
arguments_ = nullptr;
- this_function_ = nullptr;
+ rare_data_ = 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 +348,7 @@
}
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 +397,16 @@
}
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 +466,21 @@
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,
@@ -457,10 +509,10 @@
}
}
- bool var_created = false;
+ Variable* created_variable = nullptr;
// 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 +520,7 @@
}
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 +534,7 @@
// `{ 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;
}
@@ -492,32 +544,47 @@
if (!should_hoist) continue;
// 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) {
+ DCHECK(!is_being_lazily_parsed_);
+ if (created_variable == nullptr) {
+ VariableProxy* proxy =
+ factory->NewVariableProxy(name, NORMAL_VARIABLE);
+ auto declaration =
+ factory->NewVariableDeclaration(proxy, this, kNoSourcePosition);
+ // Based on the preceding check, it doesn't matter what we pass as
+ // allow_harmony_restrictive_generators and
+ // sloppy_mode_block_scope_function_redefinition.
+ bool ok = true;
+ created_variable = DeclareVariable(
+ declaration, VAR, Variable::DefaultInitializationFlag(VAR), false,
+ nullptr, &ok);
+ CHECK(ok); // Based on the preceding check, this should not fail
+ }
- Expression* assignment = factory->NewAssignment(
- Token::ASSIGN, NewUnresolved(factory, name),
- delegate->scope()->NewUnresolved(factory, name), kNoSourcePosition);
- Statement* statement =
- factory->NewExpressionStatement(assignment, kNoSourcePosition);
- delegate->set_statement(statement);
+ Expression* assignment = factory->NewAssignment(
+ Token::ASSIGN, NewUnresolved(factory, name),
+ delegate->scope()->NewUnresolved(factory, name), kNoSourcePosition);
+ Statement* statement =
+ factory->NewExpressionStatement(assignment, kNoSourcePosition);
+ delegate->set_statement(statement);
+ } else {
+ DCHECK(is_being_lazily_parsed_);
+ if (created_variable == nullptr) {
+ created_variable = DeclareVariableName(name, VAR);
+ if (created_variable != kDummyPreParserVariable &&
+ created_variable != kDummyPreParserLexicalVariable) {
+ DCHECK(FLAG_preparser_scope_analysis);
+ created_variable->set_maybe_assigned();
+ }
+ }
+ }
}
}
}
void DeclarationScope::Analyze(ParseInfo* info, AnalyzeMode mode) {
+ RuntimeCallTimerScope runtimeTimer(info->isolate(),
+ &RuntimeCallStats::CompileScopeAnalysis);
DCHECK(info->literal() != NULL);
DeclarationScope* scope = info->literal()->scope();
@@ -542,13 +609,15 @@
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();
@@ -565,6 +634,7 @@
#ifdef DEBUG
if (info->script_is_native() ? FLAG_print_builtin_scopes
: FLAG_print_scopes) {
+ PrintF("Global scope:\n");
scope->Print();
}
scope->CheckScopePositions();
@@ -577,11 +647,11 @@
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,9 +664,8 @@
// 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);
- } else if (IsLexicalVariableMode(arguments_->mode())) {
+ arguments_ = Declare(zone(), ast_value_factory->arguments_string(), VAR);
+ } else if (IsLexical(arguments_)) {
// Check if there's lexically declared variable named arguments to avoid
// redeclaration. See ES#sec-functiondeclarationinstantiation, step 20.
arguments_ = nullptr;
@@ -609,14 +678,12 @@
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);
+ EnsureRareData()->this_function =
+ Declare(zone(), ast_value_factory->this_function_string(), CONST);
}
}
@@ -636,24 +703,32 @@
return function_;
}
+Variable* DeclarationScope::DeclareGeneratorObjectVar(
+ const AstRawString* name) {
+ DCHECK(is_function_scope() || is_module_scope());
+ DCHECK_NULL(generator_object_var());
+
+ Variable* result = EnsureRareData()->generator_object =
+ NewTemporary(name, kNotAssigned);
+ result->set_is_used();
+ return result;
+}
+
+Variable* DeclarationScope::DeclarePromiseVar(const AstRawString* name) {
+ DCHECK(is_function_scope());
+ DCHECK_NULL(promise_var());
+ Variable* result = EnsureRareData()->promise = NewTemporary(name);
+ result->set_is_used();
+ return result;
+}
+
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;
+ if (sibling() == this) {
+ DCHECK_NULL(inner_scope_);
+ DCHECK(is_block_scope());
+ return true;
}
-
- Scope* sibling = parent->inner_scope();
- for (; sibling != nullptr; sibling = sibling->sibling()) {
- if (sibling == this) return false;
- }
-
- DCHECK_NULL(inner_scope_);
- return true;
+ return false;
}
Scope* Scope::GetUnremovedScope() {
@@ -667,6 +742,7 @@
Scope* Scope::FinalizeBlockScope() {
DCHECK(is_block_scope());
+ DCHECK(!HasBeenRemoved());
if (variables_.occupancy() > 0 ||
(is_declaration_scope() && calls_sloppy_eval())) {
@@ -705,7 +781,12 @@
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 +796,13 @@
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 +877,7 @@
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 +951,14 @@
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);
+ DCHECK_EQ(mode, VAR);
+ var = Declare(zone(), name, mode);
// TODO(wingo): Avoid O(n^2) check.
*is_duplicate = IsDeclaredParameter(name);
}
@@ -886,6 +970,26 @@
return var;
}
+Variable* DeclarationScope::DeclareParameterName(
+ const AstRawString* name, bool is_rest,
+ AstValueFactory* ast_value_factory) {
+ DCHECK(!already_resolved_);
+ DCHECK(is_function_scope() || is_module_scope());
+ DCHECK(!has_rest_ || is_rest);
+ DCHECK(is_being_lazily_parsed_);
+ has_rest_ = is_rest;
+ if (name == ast_value_factory->arguments_string()) {
+ has_arguments_parameter_ = true;
+ }
+ if (FLAG_preparser_scope_analysis) {
+ Variable* var = Declare(zone(), name, VAR);
+ params_.Add(var, zone());
+ return var;
+ }
+ DeclareVariableName(name, VAR);
+ return nullptr;
+}
+
Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode,
InitializationFlag init_flag, VariableKind kind,
MaybeAssignedFlag maybe_assigned_flag) {
@@ -894,8 +998,10 @@
// 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_IMPLIES(GetDeclarationScope()->is_being_lazily_parsed(),
+ mode == VAR || mode == LET || mode == CONST);
+ DCHECK(!GetDeclarationScope()->was_lazily_parsed());
+ return Declare(zone(), name, mode, kind, init_flag, maybe_assigned_flag);
}
Variable* Scope::DeclareVariable(
@@ -904,6 +1010,8 @@
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(
@@ -920,15 +1028,25 @@
const AstRawString* name = proxy->raw_name();
bool is_function_declaration = declaration->IsFunctionDeclaration();
+ // Pessimistically assume that top-level variables will be assigned.
+ //
+ // Top-level variables in a script can be accessed by other scripts or even
+ // become global properties. While this does not apply to top-level variables
+ // in a module (assuming they are not exported), we must still mark these as
+ // assigned because they might be accessed by a lazily parsed top-level
+ // function, which, for efficiency, we preparse without variable tracking.
+ if (is_script_scope() || is_module_scope()) {
+ if (mode != CONST) proxy->set_is_assigned();
+ }
+
Variable* var = nullptr;
if (is_eval_scope() && is_sloppy(language_mode()) && mode == VAR) {
// In a var binding in a sloppy direct eval, pollute the enclosing scope
// with this new binding by doing the following:
// The proxy is bound to a lookup variable to force a dynamic declaration
// using the DeclareEvalVar or DeclareEvalFunction runtime functions.
- VariableKind kind = NORMAL_VARIABLE;
- // TODO(sigurds) figure out if kNotAssigned is OK here
- var = new (zone()) Variable(this, name, mode, kind, init, kNotAssigned);
+ var = new (zone())
+ Variable(this, name, mode, NORMAL_VARIABLE, init, kMaybeAssigned);
var->AllocateTo(VariableLocation::LOOKUP, -1);
} else {
// Declare the variable in the declaration scope.
@@ -1002,6 +1120,43 @@
return var;
}
+Variable* 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.
+ if (FLAG_preparser_scope_analysis) {
+ Variable* var = LookupLocal(name);
+ DCHECK_NE(var, kDummyPreParserLexicalVariable);
+ DCHECK_NE(var, kDummyPreParserVariable);
+ if (var == nullptr) {
+ var = DeclareLocal(name, mode);
+ } else if (mode == VAR) {
+ DCHECK_EQ(var->mode(), VAR);
+ var->set_maybe_assigned();
+ }
+ var->set_is_used();
+ return var;
+ } else {
+ return variables_.DeclareName(zone(), name, mode);
+ }
+}
+
VariableProxy* Scope::NewUnresolved(AstNodeFactory* factory,
const AstRawString* name,
int start_position, VariableKind kind) {
@@ -1009,7 +1164,7 @@
// 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 +1181,8 @@
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);
+ // TODO(neis): Mark variable as maybe-assigned?
}
@@ -1050,31 +1205,17 @@
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) {
+ return NewTemporary(name, kMaybeAssigned);
}
-Variable* Scope::NewTemporary(const AstRawString* name) {
+Variable* Scope::NewTemporary(const AstRawString* name,
+ MaybeAssignedFlag maybe_assigned) {
DeclarationScope* scope = GetClosureScope();
Variable* var = new (zone())
Variable(scope, name, TEMPORARY, NORMAL_VARIABLE, kCreatedInitialized);
scope->AddLocal(var);
+ if (maybe_assigned == kMaybeAssigned) var->set_maybe_assigned();
return var;
}
@@ -1157,9 +1298,9 @@
// 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 +1417,7 @@
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());
@@ -1289,27 +1430,42 @@
DCHECK(is_function_scope());
// Reset all non-trivial members.
- params_.Clear();
+ if (!aborted || !IsArrowFunction(function_kind_)) {
+ // Do not remove parameters when lazy parsing an Arrow Function has failed,
+ // as the formal parameters are not re-parsed.
+ 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) {
+void DeclarationScope::AnalyzePartially(
+ AstNodeFactory* ast_node_factory,
+ PreParsedScopeData* preparsed_scope_data) {
DCHECK(!force_eager_compilation_);
VariableProxy* unresolved = nullptr;
@@ -1317,9 +1473,8 @@
// 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);
@@ -1331,7 +1486,20 @@
!(MustAllocate(arguments_) && !has_arguments_parameter_)) {
arguments_ = nullptr;
}
+
+ if (FLAG_preparser_scope_analysis) {
+ // Decide context allocation for the locals and parameters and store the
+ // info away.
+ AllocateVariablesRecursively();
+ CollectVariableData(preparsed_scope_data);
+ }
}
+#ifdef DEBUG
+ if (FLAG_print_scopes) {
+ PrintF("Inner function scope:\n");
+ Print();
+ }
+#endif
ResetAfterPreparsing(ast_node_factory->ast_value_factory(), false);
@@ -1339,8 +1507,10 @@
}
#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 +1529,13 @@
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 +1557,52 @@
}
}
-
-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;
+ if (var == kDummyPreParserVariable ||
+ var == kDummyPreParserLexicalVariable) {
+ 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++) {
@@ -1466,6 +1638,9 @@
}
PrintF(" { // (%d, %d)\n", start_position(), end_position());
+ if (is_hidden()) {
+ Indent(n1, "// is hidden\n");
+ }
// Function name, if any (named function literals, only).
if (function != nullptr) {
@@ -1487,9 +1662,12 @@
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 +1683,22 @@
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 +1727,12 @@
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 +1742,7 @@
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 +1783,13 @@
// 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 +1841,20 @@
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 +1889,7 @@
}
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;
}
@@ -1742,44 +1927,79 @@
#endif
DCHECK_NOT_NULL(var);
- if (proxy->is_assigned()) var->set_maybe_assigned();
if (AccessNeedsHoleCheck(var, proxy, this)) proxy->set_needs_hole_check();
proxy->BindTo(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) {
+ // Module variables must be allocated before variable resolution
+ // to ensure that AccessNeedsHoleCheck() can detect import variables.
+ if (info != nullptr && is_module_scope()) {
+ AsModuleScope()->AllocateModuleVariables();
+ }
+ // 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();
+ if (proxy->is_assigned()) {
+ var->set_maybe_assigned();
+ }
+ }
}
}
@@ -1787,14 +2007,16 @@
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;
}
bool Scope::MustAllocate(Variable* var) {
+ if (var == kDummyPreParserLexicalVariable || var == kDummyPreParserVariable) {
+ return true;
+ }
DCHECK(var->location() != VariableLocation::MODULE);
// Give var a read/write use if there is a chance it might be accessed
// via an eval() call. This is only possible if the variable has a
@@ -1823,7 +2045,10 @@
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 +2105,7 @@
DCHECK_EQ(this, var->scope());
if (uses_sloppy_arguments) {
var->set_is_used();
+ var->set_maybe_assigned();
var->ForceContextAllocation();
}
AllocateParameter(var, i);
@@ -1946,9 +2172,8 @@
new_target_ = nullptr;
}
- if (this_function_ != nullptr && !MustAllocate(this_function_)) {
- this_function_ = nullptr;
- }
+ NullifyRareVariableIf(RareVariable::kThisFunction,
+ [=](Variable* var) { return !MustAllocate(var); });
}
void ModuleScope::AllocateModuleVariables() {
@@ -1967,9 +2192,10 @@
void Scope::AllocateVariablesRecursively() {
DCHECK(!already_resolved_);
- DCHECK_EQ(0, num_stack_slots_);
+ DCHECK_IMPLIES(!FLAG_preparser_scope_analysis, num_stack_slots_ == 0);
+
// 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 +2220,9 @@
// 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());
@@ -2043,6 +2269,17 @@
}
}
+void Scope::CollectVariableData(PreParsedScopeData* data) {
+ PreParsedScopeData::ScopeScope scope_scope(data, scope_type(),
+ start_position(), end_position());
+ for (Variable* local : locals_) {
+ scope_scope.MaybeAddVariable(local);
+ }
+ for (Scope* inner = inner_scope_; inner != nullptr; inner = inner->sibling_) {
+ inner->CollectVariableData(data);
+ }
+}
+
int Scope::StackLocalCount() const {
Variable* function =
is_function_scope() ? AsDeclarationScope()->function_var() : nullptr;
diff --git a/src/ast/scopes.h b/src/ast/scopes.h
index c7d88ac..119d77c 100644
--- a/src/ast/scopes.h
+++ b/src/ast/scopes.h
@@ -19,7 +19,9 @@
class AstRawString;
class Declaration;
class ParseInfo;
+class PreParsedScopeData;
class SloppyBlockFunctionStatement;
+class Statement;
class StringSet;
class VariableProxy;
@@ -28,11 +30,17 @@
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.
+ Variable* DeclareName(Zone* zone, const AstRawString* name,
+ VariableMode mode);
Variable* Lookup(const AstRawString* name);
void Remove(Variable* var);
@@ -43,9 +51,24 @@
// 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 +171,8 @@
// 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 +181,9 @@
bool* sloppy_mode_block_scope_function_redefinition,
bool* ok);
+ // The return value is meaningful only if FLAG_preparser_scope_analysis is on.
+ Variable* DeclareVariableName(const AstRawString* name, VariableMode mode);
+
// Declarations list.
ThreadedList<Declaration>* declarations() { return &decls_; }
@@ -177,7 +204,6 @@
// 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 +233,11 @@
// 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 +326,7 @@
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?
@@ -387,7 +411,7 @@
Scope* GetOuterScopeWithContext();
// Analyze() must have been called once to create the ScopeInfo.
- Handle<ScopeInfo> scope_info() {
+ Handle<ScopeInfo> scope_info() const {
DCHECK(!scope_info_.is_null());
return scope_info_;
}
@@ -423,6 +447,22 @@
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 +471,11 @@
}
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
@@ -442,6 +483,8 @@
// should also be invoked after resolution.
bool NeedsScopeInfo() const;
+ Variable* NewTemporary(const AstRawString* name,
+ MaybeAssignedFlag maybe_assigned);
Zone* zone_;
// Scope tree.
@@ -527,7 +570,6 @@
// 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);
@@ -548,6 +590,8 @@
void AllocateDebuggerScopeInfos(Isolate* isolate,
MaybeHandle<ScopeInfo> outer_scope);
+ void CollectVariableData(PreParsedScopeData* data);
+
// Construct a scope based on the scope info.
Scope(Zone* zone, ScopeType type, Handle<ScopeInfo> scope_info);
@@ -556,33 +600,18 @@
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 {
+class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
public:
DeclarationScope(Zone* zone, Scope* outer_scope, ScopeType scope_type,
FunctionKind function_kind = kNormalFunction);
@@ -616,7 +645,15 @@
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 +666,7 @@
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);
@@ -645,6 +682,11 @@
// calls sloppy eval.
Variable* DeclareFunctionVar(const AstRawString* name);
+ // Declare some special internal variables which must be accessible to
+ // Ignition without ScopeInfo.
+ Variable* DeclareGeneratorObjectVar(const AstRawString* name);
+ Variable* DeclarePromiseVar(const AstRawString* name);
+
// Declare a parameter in this scope. When there are duplicated
// parameters the rightmost one 'wins'. However, the implementation
// expects all parameters to be declared and from left to right.
@@ -652,6 +694,11 @@
bool is_optional, bool is_rest, bool* is_duplicate,
AstValueFactory* ast_value_factory);
+ // Declares that a parameter with the name exists. Creates a Variable and
+ // returns it if FLAG_preparser_scope_analysis is on.
+ Variable* DeclareParameterName(const AstRawString* name, bool is_rest,
+ AstValueFactory* ast_value_factory);
+
// Declare an implicit global variable in this scope which must be a
// script scope. The variable was introduced (possibly from an inner
// scope) by a reference to an unresolved variable with no intervening
@@ -683,6 +730,17 @@
return function_;
}
+ Variable* generator_object_var() const {
+ DCHECK(is_function_scope() || is_module_scope());
+ return GetRareVariable(RareVariable::kGeneratorObject);
+ }
+
+ Variable* promise_var() const {
+ DCHECK(is_function_scope());
+ DCHECK(IsAsyncFunction(function_kind_));
+ return GetRareVariable(RareVariable::kPromise);
+ }
+
// Parameters. The left-most parameter has index 0.
// Only valid for function and module scopes.
Variable* parameter(int index) const {
@@ -723,12 +781,14 @@
}
Variable* this_function_var() const {
+ Variable* this_function = GetRareVariable(RareVariable::kThisFunction);
+
// This is only used in derived constructors atm.
- DCHECK(this_function_ == nullptr ||
+ DCHECK(this_function == nullptr ||
(is_function_scope() && (IsClassConstructor(function_kind()) ||
IsConciseMethod(function_kind()) ||
IsAccessorFunction(function_kind()))));
- return this_function_;
+ return this_function;
}
// Adds a local variable in this scope's locals list. This is for adjusting
@@ -736,10 +796,9 @@
// 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.
@@ -759,7 +818,8 @@
// records variables which cannot be resolved inside the Scope (we don't yet
// know what they will resolve to since the outer Scopes are incomplete) and
// migrates them into migrate_to.
- void AnalyzePartially(AstNodeFactory* ast_node_factory);
+ void AnalyzePartially(AstNodeFactory* ast_node_factory,
+ PreParsedScopeData* preparsed_scope_data);
Handle<StringSet> CollectNonLocals(ParseInfo* info,
Handle<StringSet> non_locals);
@@ -819,7 +879,11 @@
// 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_;
@@ -833,8 +897,48 @@
Variable* new_target_;
// Convenience variable; function scopes only.
Variable* arguments_;
- // Convenience variable; Subclass constructor only
- Variable* this_function_;
+
+ struct RareData : public ZoneObject {
+ // Convenience variable; Subclass constructor only
+ Variable* this_function = nullptr;
+
+ // Generator object, if any; generator function scopes and module scopes
+ // only.
+ Variable* generator_object = nullptr;
+ // Promise, if any; async function scopes only.
+ Variable* promise = nullptr;
+ };
+
+ enum class RareVariable {
+ kThisFunction = offsetof(RareData, this_function),
+ kGeneratorObject = offsetof(RareData, generator_object),
+ kPromise = offsetof(RareData, promise)
+ };
+
+ V8_INLINE RareData* EnsureRareData() {
+ if (rare_data_ == nullptr) {
+ rare_data_ = new (zone_) RareData;
+ }
+ return rare_data_;
+ }
+
+ V8_INLINE Variable* GetRareVariable(RareVariable id) const {
+ if (rare_data_ == nullptr) return nullptr;
+ return *reinterpret_cast<Variable**>(
+ reinterpret_cast<uint8_t*>(rare_data_) + static_cast<ptrdiff_t>(id));
+ }
+
+ // Set `var` to null if it's non-null and Predicate (Variable*) -> bool
+ // returns true.
+ template <typename Predicate>
+ V8_INLINE void NullifyRareVariableIf(RareVariable id, Predicate predicate) {
+ if (V8_LIKELY(rare_data_ == nullptr)) return;
+ Variable** var = reinterpret_cast<Variable**>(
+ reinterpret_cast<uint8_t*>(rare_data_) + static_cast<ptrdiff_t>(id));
+ if (*var && predicate(*var)) *var = nullptr;
+ }
+
+ RareData* rare_data_ = nullptr;
};
class ModuleScope final : public DeclarationScope {
diff --git a/src/ast/variables.cc b/src/ast/variables.cc
index 3771bfe..cd1d8f7 100644
--- a/src/ast/variables.cc
+++ b/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 {
@@ -36,9 +37,8 @@
bool Variable::IsGlobalObjectProperty() const {
// Temporaries are never global, they must always be allocated in the
// activation frame.
- return (IsDynamicVariableMode(mode()) ||
- (IsDeclaredVariableMode(mode()) && !IsLexicalVariableMode(mode()))) &&
- scope_ != NULL && scope_->is_script_scope();
+ return (IsDynamicVariableMode(mode()) || mode() == VAR) &&
+ scope_ != nullptr && scope_->is_script_scope();
}
} // namespace internal