summaryrefslogtreecommitdiff
path: root/deps/v8/src/ast
diff options
context:
space:
mode:
authorAli Ijaz Sheikh <ofrobots@google.com>2016-03-01 08:58:05 -0800
committerAli Sheikh <ofrobots@lemonhope.roam.corp.google.com>2016-03-03 20:35:20 -0800
commit069e02ab47656b3efd1b6829c65856b2e1c2d1db (patch)
treeeb643e0a2e88fd64bb9fc927423458d2ae96c2db /deps/v8/src/ast
parent8938355398c79f583a468284b768652d12ba9bc9 (diff)
downloadnode-new-069e02ab47656b3efd1b6829c65856b2e1c2d1db.tar.gz
deps: upgrade to V8 4.9.385.18
Pick up the current branch head for V8 4.9 https://github.com/v8/v8/commit/1ecba0f PR-URL: https://github.com/nodejs/node/pull/4722 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Michaƫl Zasso <mic.besace@gmail.com>
Diffstat (limited to 'deps/v8/src/ast')
-rw-r--r--deps/v8/src/ast/OWNERS7
-rw-r--r--deps/v8/src/ast/ast-expression-rewriter.cc409
-rw-r--r--deps/v8/src/ast/ast-expression-rewriter.h54
-rw-r--r--deps/v8/src/ast/ast-expression-visitor.cc410
-rw-r--r--deps/v8/src/ast/ast-expression-visitor.h50
-rw-r--r--deps/v8/src/ast/ast-literal-reindexer.cc331
-rw-r--r--deps/v8/src/ast/ast-literal-reindexer.h44
-rw-r--r--deps/v8/src/ast/ast-numbering.cc607
-rw-r--r--deps/v8/src/ast/ast-numbering.h25
-rw-r--r--deps/v8/src/ast/ast-value-factory.cc411
-rw-r--r--deps/v8/src/ast/ast-value-factory.h375
-rw-r--r--deps/v8/src/ast/ast.cc826
-rw-r--r--deps/v8/src/ast/ast.h3535
-rw-r--r--deps/v8/src/ast/modules.cc59
-rw-r--r--deps/v8/src/ast/modules.h121
-rw-r--r--deps/v8/src/ast/prettyprinter.cc1698
-rw-r--r--deps/v8/src/ast/prettyprinter.h140
-rw-r--r--deps/v8/src/ast/scopeinfo.cc858
-rw-r--r--deps/v8/src/ast/scopeinfo.h175
-rw-r--r--deps/v8/src/ast/scopes.cc1698
-rw-r--r--deps/v8/src/ast/scopes.h849
-rw-r--r--deps/v8/src/ast/variables.cc82
-rw-r--r--deps/v8/src/ast/variables.h218
23 files changed, 12982 insertions, 0 deletions
diff --git a/deps/v8/src/ast/OWNERS b/deps/v8/src/ast/OWNERS
new file mode 100644
index 0000000000..7cd947998d
--- /dev/null
+++ b/deps/v8/src/ast/OWNERS
@@ -0,0 +1,7 @@
+set noparent
+
+adamk@chromium.org
+bmeurer@chromium.org
+littledan@chromium.org
+mstarzinger@chromium.org
+rossberg@chromium.org
diff --git a/deps/v8/src/ast/ast-expression-rewriter.cc b/deps/v8/src/ast/ast-expression-rewriter.cc
new file mode 100644
index 0000000000..49cc7f6ff4
--- /dev/null
+++ b/deps/v8/src/ast/ast-expression-rewriter.cc
@@ -0,0 +1,409 @@
+// 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.h"
+#include "src/ast/ast-expression-rewriter.h"
+
+namespace v8 {
+namespace internal {
+
+// ----------------------------------------------------------------------------
+// Implementation of AstExpressionRewriter
+// The AST is traversed but no actual rewriting takes place, unless the
+// Visit methods are overriden in subclasses.
+
+#define REWRITE_THIS(node) \
+ do { \
+ if (!RewriteExpression(node)) return; \
+ } while (false)
+#define NOTHING() DCHECK_NULL(replacement_)
+
+
+void AstExpressionRewriter::VisitDeclarations(
+ ZoneList<Declaration*>* declarations) {
+ for (int i = 0; i < declarations->length(); i++) {
+ AST_REWRITE_LIST_ELEMENT(Declaration, declarations, i);
+ }
+}
+
+
+void AstExpressionRewriter::VisitStatements(ZoneList<Statement*>* statements) {
+ for (int i = 0; i < statements->length(); i++) {
+ AST_REWRITE_LIST_ELEMENT(Statement, statements, i);
+ // Not stopping when a jump statement is found.
+ }
+}
+
+
+void AstExpressionRewriter::VisitExpressions(
+ ZoneList<Expression*>* expressions) {
+ for (int i = 0; i < expressions->length(); i++) {
+ // The variable statement visiting code may pass NULL expressions
+ // to this code. Maybe this should be handled by introducing an
+ // undefined expression or literal? Revisit this code if this
+ // changes
+ if (expressions->at(i) != nullptr) {
+ AST_REWRITE_LIST_ELEMENT(Expression, expressions, i);
+ }
+ }
+}
+
+
+void AstExpressionRewriter::VisitVariableDeclaration(
+ VariableDeclaration* node) {
+ // Not visiting `proxy_`.
+ NOTHING();
+}
+
+
+void AstExpressionRewriter::VisitFunctionDeclaration(
+ FunctionDeclaration* node) {
+ // Not visiting `proxy_`.
+ AST_REWRITE_PROPERTY(FunctionLiteral, node, fun);
+}
+
+
+void AstExpressionRewriter::VisitImportDeclaration(ImportDeclaration* node) {
+ // Not visiting `proxy_`.
+ NOTHING();
+}
+
+
+void AstExpressionRewriter::VisitExportDeclaration(ExportDeclaration* node) {
+ // Not visiting `proxy_`.
+ NOTHING();
+}
+
+
+void AstExpressionRewriter::VisitBlock(Block* node) {
+ VisitStatements(node->statements());
+}
+
+
+void AstExpressionRewriter::VisitExpressionStatement(
+ ExpressionStatement* node) {
+ AST_REWRITE_PROPERTY(Expression, node, expression);
+}
+
+
+void AstExpressionRewriter::VisitEmptyStatement(EmptyStatement* node) {
+ NOTHING();
+}
+
+
+void AstExpressionRewriter::VisitSloppyBlockFunctionStatement(
+ SloppyBlockFunctionStatement* node) {
+ AST_REWRITE_PROPERTY(Statement, node, statement);
+}
+
+
+void AstExpressionRewriter::VisitIfStatement(IfStatement* node) {
+ AST_REWRITE_PROPERTY(Expression, node, condition);
+ AST_REWRITE_PROPERTY(Statement, node, then_statement);
+ AST_REWRITE_PROPERTY(Statement, node, else_statement);
+}
+
+
+void AstExpressionRewriter::VisitContinueStatement(ContinueStatement* node) {
+ NOTHING();
+}
+
+
+void AstExpressionRewriter::VisitBreakStatement(BreakStatement* node) {
+ NOTHING();
+}
+
+
+void AstExpressionRewriter::VisitReturnStatement(ReturnStatement* node) {
+ AST_REWRITE_PROPERTY(Expression, node, expression);
+}
+
+
+void AstExpressionRewriter::VisitWithStatement(WithStatement* node) {
+ AST_REWRITE_PROPERTY(Expression, node, expression);
+ AST_REWRITE_PROPERTY(Statement, node, statement);
+}
+
+
+void AstExpressionRewriter::VisitSwitchStatement(SwitchStatement* node) {
+ AST_REWRITE_PROPERTY(Expression, node, tag);
+ ZoneList<CaseClause*>* clauses = node->cases();
+ for (int i = 0; i < clauses->length(); i++) {
+ AST_REWRITE_LIST_ELEMENT(CaseClause, clauses, i);
+ }
+}
+
+
+void AstExpressionRewriter::VisitDoWhileStatement(DoWhileStatement* node) {
+ AST_REWRITE_PROPERTY(Expression, node, cond);
+ AST_REWRITE_PROPERTY(Statement, node, body);
+}
+
+
+void AstExpressionRewriter::VisitWhileStatement(WhileStatement* node) {
+ AST_REWRITE_PROPERTY(Expression, node, cond);
+ AST_REWRITE_PROPERTY(Statement, node, body);
+}
+
+
+void AstExpressionRewriter::VisitForStatement(ForStatement* node) {
+ if (node->init() != nullptr) {
+ AST_REWRITE_PROPERTY(Statement, node, init);
+ }
+ if (node->cond() != nullptr) {
+ AST_REWRITE_PROPERTY(Expression, node, cond);
+ }
+ if (node->next() != nullptr) {
+ AST_REWRITE_PROPERTY(Statement, node, next);
+ }
+ AST_REWRITE_PROPERTY(Statement, node, body);
+}
+
+
+void AstExpressionRewriter::VisitForInStatement(ForInStatement* node) {
+ AST_REWRITE_PROPERTY(Expression, node, each);
+ AST_REWRITE_PROPERTY(Expression, node, subject);
+ AST_REWRITE_PROPERTY(Statement, node, body);
+}
+
+
+void AstExpressionRewriter::VisitForOfStatement(ForOfStatement* node) {
+ AST_REWRITE_PROPERTY(Expression, node, each);
+ AST_REWRITE_PROPERTY(Expression, node, assign_iterator);
+ AST_REWRITE_PROPERTY(Expression, node, next_result);
+ AST_REWRITE_PROPERTY(Expression, node, result_done);
+ AST_REWRITE_PROPERTY(Expression, node, assign_each);
+ AST_REWRITE_PROPERTY(Expression, node, subject);
+ AST_REWRITE_PROPERTY(Statement, node, body);
+}
+
+
+void AstExpressionRewriter::VisitTryCatchStatement(TryCatchStatement* node) {
+ AST_REWRITE_PROPERTY(Block, node, try_block);
+ // Not visiting the variable.
+ AST_REWRITE_PROPERTY(Block, node, catch_block);
+}
+
+
+void AstExpressionRewriter::VisitTryFinallyStatement(
+ TryFinallyStatement* node) {
+ AST_REWRITE_PROPERTY(Block, node, try_block);
+ AST_REWRITE_PROPERTY(Block, node, finally_block);
+}
+
+
+void AstExpressionRewriter::VisitDebuggerStatement(DebuggerStatement* node) {
+ NOTHING();
+}
+
+
+void AstExpressionRewriter::VisitFunctionLiteral(FunctionLiteral* node) {
+ REWRITE_THIS(node);
+ VisitDeclarations(node->scope()->declarations());
+ ZoneList<Statement*>* body = node->body();
+ if (body != nullptr) VisitStatements(body);
+}
+
+
+void AstExpressionRewriter::VisitClassLiteral(ClassLiteral* node) {
+ REWRITE_THIS(node);
+ // Not visiting `class_variable_proxy_`.
+ if (node->extends() != nullptr) {
+ AST_REWRITE_PROPERTY(Expression, node, extends);
+ }
+ AST_REWRITE_PROPERTY(FunctionLiteral, node, constructor);
+ ZoneList<typename ClassLiteral::Property*>* properties = node->properties();
+ for (int i = 0; i < properties->length(); i++) {
+ VisitObjectLiteralProperty(properties->at(i));
+ }
+}
+
+
+void AstExpressionRewriter::VisitNativeFunctionLiteral(
+ NativeFunctionLiteral* node) {
+ REWRITE_THIS(node);
+ NOTHING();
+}
+
+
+void AstExpressionRewriter::VisitConditional(Conditional* node) {
+ REWRITE_THIS(node);
+ AST_REWRITE_PROPERTY(Expression, node, condition);
+ AST_REWRITE_PROPERTY(Expression, node, then_expression);
+ AST_REWRITE_PROPERTY(Expression, node, else_expression);
+}
+
+
+void AstExpressionRewriter::VisitVariableProxy(VariableProxy* node) {
+ REWRITE_THIS(node);
+ NOTHING();
+}
+
+
+void AstExpressionRewriter::VisitLiteral(Literal* node) {
+ REWRITE_THIS(node);
+ NOTHING();
+}
+
+
+void AstExpressionRewriter::VisitRegExpLiteral(RegExpLiteral* node) {
+ REWRITE_THIS(node);
+ NOTHING();
+}
+
+
+void AstExpressionRewriter::VisitObjectLiteral(ObjectLiteral* node) {
+ REWRITE_THIS(node);
+ ZoneList<typename ObjectLiteral::Property*>* properties = node->properties();
+ for (int i = 0; i < properties->length(); i++) {
+ VisitObjectLiteralProperty(properties->at(i));
+ }
+}
+
+
+void AstExpressionRewriter::VisitObjectLiteralProperty(
+ ObjectLiteralProperty* property) {
+ if (property == nullptr) return;
+ AST_REWRITE_PROPERTY(Expression, property, key);
+ AST_REWRITE_PROPERTY(Expression, property, value);
+}
+
+
+void AstExpressionRewriter::VisitArrayLiteral(ArrayLiteral* node) {
+ REWRITE_THIS(node);
+ VisitExpressions(node->values());
+}
+
+
+void AstExpressionRewriter::VisitAssignment(Assignment* node) {
+ REWRITE_THIS(node);
+ AST_REWRITE_PROPERTY(Expression, node, target);
+ AST_REWRITE_PROPERTY(Expression, node, value);
+}
+
+
+void AstExpressionRewriter::VisitYield(Yield* node) {
+ REWRITE_THIS(node);
+ AST_REWRITE_PROPERTY(Expression, node, generator_object);
+ AST_REWRITE_PROPERTY(Expression, node, expression);
+}
+
+
+void AstExpressionRewriter::VisitThrow(Throw* node) {
+ REWRITE_THIS(node);
+ AST_REWRITE_PROPERTY(Expression, node, exception);
+}
+
+
+void AstExpressionRewriter::VisitProperty(Property* node) {
+ REWRITE_THIS(node);
+ if (node == nullptr) return;
+ AST_REWRITE_PROPERTY(Expression, node, obj);
+ AST_REWRITE_PROPERTY(Expression, node, key);
+}
+
+
+void AstExpressionRewriter::VisitCall(Call* node) {
+ REWRITE_THIS(node);
+ AST_REWRITE_PROPERTY(Expression, node, expression);
+ VisitExpressions(node->arguments());
+}
+
+
+void AstExpressionRewriter::VisitCallNew(CallNew* node) {
+ REWRITE_THIS(node);
+ AST_REWRITE_PROPERTY(Expression, node, expression);
+ VisitExpressions(node->arguments());
+}
+
+
+void AstExpressionRewriter::VisitCallRuntime(CallRuntime* node) {
+ REWRITE_THIS(node);
+ VisitExpressions(node->arguments());
+}
+
+
+void AstExpressionRewriter::VisitUnaryOperation(UnaryOperation* node) {
+ REWRITE_THIS(node);
+ AST_REWRITE_PROPERTY(Expression, node, expression);
+}
+
+
+void AstExpressionRewriter::VisitCountOperation(CountOperation* node) {
+ REWRITE_THIS(node);
+ AST_REWRITE_PROPERTY(Expression, node, expression);
+}
+
+
+void AstExpressionRewriter::VisitBinaryOperation(BinaryOperation* node) {
+ REWRITE_THIS(node);
+ AST_REWRITE_PROPERTY(Expression, node, left);
+ AST_REWRITE_PROPERTY(Expression, node, right);
+}
+
+
+void AstExpressionRewriter::VisitCompareOperation(CompareOperation* node) {
+ REWRITE_THIS(node);
+ AST_REWRITE_PROPERTY(Expression, node, left);
+ AST_REWRITE_PROPERTY(Expression, node, right);
+}
+
+
+void AstExpressionRewriter::VisitSpread(Spread* node) {
+ REWRITE_THIS(node);
+ AST_REWRITE_PROPERTY(Expression, node, expression);
+}
+
+
+void AstExpressionRewriter::VisitThisFunction(ThisFunction* node) {
+ REWRITE_THIS(node);
+ NOTHING();
+}
+
+
+void AstExpressionRewriter::VisitSuperPropertyReference(
+ SuperPropertyReference* node) {
+ REWRITE_THIS(node);
+ AST_REWRITE_PROPERTY(VariableProxy, node, this_var);
+ AST_REWRITE_PROPERTY(Expression, node, home_object);
+}
+
+
+void AstExpressionRewriter::VisitSuperCallReference(SuperCallReference* node) {
+ REWRITE_THIS(node);
+ AST_REWRITE_PROPERTY(VariableProxy, node, this_var);
+ AST_REWRITE_PROPERTY(VariableProxy, node, new_target_var);
+ AST_REWRITE_PROPERTY(VariableProxy, node, this_function_var);
+}
+
+
+void AstExpressionRewriter::VisitCaseClause(CaseClause* node) {
+ if (!node->is_default()) {
+ AST_REWRITE_PROPERTY(Expression, node, label);
+ }
+ VisitStatements(node->statements());
+}
+
+
+void AstExpressionRewriter::VisitEmptyParentheses(EmptyParentheses* node) {
+ NOTHING();
+}
+
+
+void AstExpressionRewriter::VisitDoExpression(DoExpression* node) {
+ REWRITE_THIS(node);
+ AST_REWRITE_PROPERTY(Block, node, block);
+ AST_REWRITE_PROPERTY(VariableProxy, node, result);
+}
+
+
+void AstExpressionRewriter::VisitRewritableAssignmentExpression(
+ RewritableAssignmentExpression* node) {
+ REWRITE_THIS(node);
+ AST_REWRITE_PROPERTY(Expression, node, expression);
+}
+
+
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/ast/ast-expression-rewriter.h b/deps/v8/src/ast/ast-expression-rewriter.h
new file mode 100644
index 0000000000..916842ab20
--- /dev/null
+++ b/deps/v8/src/ast/ast-expression-rewriter.h
@@ -0,0 +1,54 @@
+// 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_EXPRESSION_REWRITER_H_
+#define V8_AST_AST_EXPRESSION_REWRITER_H_
+
+#include "src/allocation.h"
+#include "src/ast/ast.h"
+#include "src/ast/scopes.h"
+#include "src/effects.h"
+#include "src/type-info.h"
+#include "src/types.h"
+#include "src/zone.h"
+
+namespace v8 {
+namespace internal {
+
+// A rewriting Visitor over a CompilationInfo's AST that invokes
+// VisitExpression on each expression node.
+
+class AstExpressionRewriter : public AstVisitor {
+ public:
+ explicit AstExpressionRewriter(Isolate* isolate) : AstVisitor() {
+ InitializeAstRewriter(isolate);
+ }
+ explicit AstExpressionRewriter(uintptr_t stack_limit) : AstVisitor() {
+ InitializeAstRewriter(stack_limit);
+ }
+ ~AstExpressionRewriter() override {}
+
+ void VisitDeclarations(ZoneList<Declaration*>* declarations) override;
+ void VisitStatements(ZoneList<Statement*>* statements) override;
+ void VisitExpressions(ZoneList<Expression*>* expressions) override;
+
+ virtual void VisitObjectLiteralProperty(ObjectLiteralProperty* property);
+
+ protected:
+ virtual bool RewriteExpression(Expression* expr) = 0;
+
+ private:
+ DEFINE_AST_REWRITER_SUBCLASS_MEMBERS();
+
+#define DECLARE_VISIT(type) void Visit##type(type* node) override;
+ AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+ DISALLOW_COPY_AND_ASSIGN(AstExpressionRewriter);
+};
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_AST_AST_EXPRESSION_REWRITER_H_
diff --git a/deps/v8/src/ast/ast-expression-visitor.cc b/deps/v8/src/ast/ast-expression-visitor.cc
new file mode 100644
index 0000000000..6b2550c541
--- /dev/null
+++ b/deps/v8/src/ast/ast-expression-visitor.cc
@@ -0,0 +1,410 @@
+// 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/v8.h"
+
+#include "src/ast/ast-expression-visitor.h"
+
+#include "src/ast/ast.h"
+#include "src/ast/scopes.h"
+#include "src/codegen.h"
+
+namespace v8 {
+namespace internal {
+
+
+#define RECURSE(call) \
+ do { \
+ DCHECK(!HasStackOverflow()); \
+ call; \
+ if (HasStackOverflow()) return; \
+ } while (false)
+
+
+#define RECURSE_EXPRESSION(call) \
+ do { \
+ DCHECK(!HasStackOverflow()); \
+ ++depth_; \
+ call; \
+ --depth_; \
+ if (HasStackOverflow()) return; \
+ } while (false)
+
+
+AstExpressionVisitor::AstExpressionVisitor(Isolate* isolate, Expression* root)
+ : root_(root), depth_(0) {
+ InitializeAstVisitor(isolate);
+}
+
+
+AstExpressionVisitor::AstExpressionVisitor(uintptr_t stack_limit,
+ Expression* root)
+ : root_(root), depth_(0) {
+ InitializeAstVisitor(stack_limit);
+}
+
+
+void AstExpressionVisitor::Run() { RECURSE(Visit(root_)); }
+
+
+void AstExpressionVisitor::VisitVariableDeclaration(VariableDeclaration* decl) {
+}
+
+
+void AstExpressionVisitor::VisitFunctionDeclaration(FunctionDeclaration* decl) {
+ RECURSE(Visit(decl->fun()));
+}
+
+
+void AstExpressionVisitor::VisitImportDeclaration(ImportDeclaration* decl) {}
+
+
+void AstExpressionVisitor::VisitExportDeclaration(ExportDeclaration* decl) {}
+
+
+void AstExpressionVisitor::VisitStatements(ZoneList<Statement*>* stmts) {
+ for (int i = 0; i < stmts->length(); ++i) {
+ Statement* stmt = stmts->at(i);
+ RECURSE(Visit(stmt));
+ if (stmt->IsJump()) break;
+ }
+}
+
+
+void AstExpressionVisitor::VisitBlock(Block* stmt) {
+ RECURSE(VisitStatements(stmt->statements()));
+}
+
+
+void AstExpressionVisitor::VisitExpressionStatement(ExpressionStatement* stmt) {
+ RECURSE(Visit(stmt->expression()));
+}
+
+
+void AstExpressionVisitor::VisitEmptyStatement(EmptyStatement* stmt) {}
+
+
+void AstExpressionVisitor::VisitSloppyBlockFunctionStatement(
+ SloppyBlockFunctionStatement* stmt) {
+ RECURSE(Visit(stmt->statement()));
+}
+
+
+void AstExpressionVisitor::VisitIfStatement(IfStatement* stmt) {
+ RECURSE(Visit(stmt->condition()));
+ RECURSE(Visit(stmt->then_statement()));
+ RECURSE(Visit(stmt->else_statement()));
+}
+
+
+void AstExpressionVisitor::VisitContinueStatement(ContinueStatement* stmt) {}
+
+
+void AstExpressionVisitor::VisitBreakStatement(BreakStatement* stmt) {}
+
+
+void AstExpressionVisitor::VisitReturnStatement(ReturnStatement* stmt) {
+ RECURSE(Visit(stmt->expression()));
+}
+
+
+void AstExpressionVisitor::VisitWithStatement(WithStatement* stmt) {
+ RECURSE(stmt->expression());
+ RECURSE(stmt->statement());
+}
+
+
+void AstExpressionVisitor::VisitSwitchStatement(SwitchStatement* stmt) {
+ RECURSE(Visit(stmt->tag()));
+
+ ZoneList<CaseClause*>* clauses = stmt->cases();
+
+ for (int i = 0; i < clauses->length(); ++i) {
+ CaseClause* clause = clauses->at(i);
+ if (!clause->is_default()) {
+ Expression* label = clause->label();
+ RECURSE(Visit(label));
+ }
+ ZoneList<Statement*>* stmts = clause->statements();
+ RECURSE(VisitStatements(stmts));
+ }
+}
+
+
+void AstExpressionVisitor::VisitCaseClause(CaseClause* clause) {
+ UNREACHABLE();
+}
+
+
+void AstExpressionVisitor::VisitDoWhileStatement(DoWhileStatement* stmt) {
+ RECURSE(Visit(stmt->body()));
+ RECURSE(Visit(stmt->cond()));
+}
+
+
+void AstExpressionVisitor::VisitWhileStatement(WhileStatement* stmt) {
+ RECURSE(Visit(stmt->cond()));
+ RECURSE(Visit(stmt->body()));
+}
+
+
+void AstExpressionVisitor::VisitForStatement(ForStatement* stmt) {
+ if (stmt->init() != NULL) {
+ RECURSE(Visit(stmt->init()));
+ }
+ if (stmt->cond() != NULL) {
+ RECURSE(Visit(stmt->cond()));
+ }
+ if (stmt->next() != NULL) {
+ RECURSE(Visit(stmt->next()));
+ }
+ RECURSE(Visit(stmt->body()));
+}
+
+
+void AstExpressionVisitor::VisitForInStatement(ForInStatement* stmt) {
+ RECURSE(Visit(stmt->enumerable()));
+ RECURSE(Visit(stmt->body()));
+}
+
+
+void AstExpressionVisitor::VisitForOfStatement(ForOfStatement* stmt) {
+ RECURSE(Visit(stmt->iterable()));
+ RECURSE(Visit(stmt->each()));
+ RECURSE(Visit(stmt->assign_iterator()));
+ RECURSE(Visit(stmt->next_result()));
+ RECURSE(Visit(stmt->result_done()));
+ RECURSE(Visit(stmt->assign_each()));
+ RECURSE(Visit(stmt->body()));
+}
+
+
+void AstExpressionVisitor::VisitTryCatchStatement(TryCatchStatement* stmt) {
+ RECURSE(Visit(stmt->try_block()));
+ RECURSE(Visit(stmt->catch_block()));
+}
+
+
+void AstExpressionVisitor::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
+ RECURSE(Visit(stmt->try_block()));
+ RECURSE(Visit(stmt->finally_block()));
+}
+
+
+void AstExpressionVisitor::VisitDebuggerStatement(DebuggerStatement* stmt) {}
+
+
+void AstExpressionVisitor::VisitFunctionLiteral(FunctionLiteral* expr) {
+ Scope* scope = expr->scope();
+ VisitExpression(expr);
+ RECURSE_EXPRESSION(VisitDeclarations(scope->declarations()));
+ RECURSE_EXPRESSION(VisitStatements(expr->body()));
+}
+
+
+void AstExpressionVisitor::VisitNativeFunctionLiteral(
+ NativeFunctionLiteral* expr) {}
+
+
+void AstExpressionVisitor::VisitDoExpression(DoExpression* expr) {
+ RECURSE(VisitBlock(expr->block()));
+ RECURSE(VisitVariableProxy(expr->result()));
+}
+
+
+void AstExpressionVisitor::VisitConditional(Conditional* expr) {
+ VisitExpression(expr);
+ RECURSE_EXPRESSION(Visit(expr->condition()));
+ RECURSE_EXPRESSION(Visit(expr->then_expression()));
+ RECURSE_EXPRESSION(Visit(expr->else_expression()));
+}
+
+
+void AstExpressionVisitor::VisitVariableProxy(VariableProxy* expr) {
+ VisitExpression(expr);
+}
+
+
+void AstExpressionVisitor::VisitLiteral(Literal* expr) {
+ VisitExpression(expr);
+}
+
+
+void AstExpressionVisitor::VisitRegExpLiteral(RegExpLiteral* expr) {
+ VisitExpression(expr);
+}
+
+
+void AstExpressionVisitor::VisitObjectLiteral(ObjectLiteral* expr) {
+ VisitExpression(expr);
+ ZoneList<ObjectLiteralProperty*>* props = expr->properties();
+ for (int i = 0; i < props->length(); ++i) {
+ ObjectLiteralProperty* prop = props->at(i);
+ if (!prop->key()->IsLiteral()) {
+ RECURSE_EXPRESSION(Visit(prop->key()));
+ }
+ RECURSE_EXPRESSION(Visit(prop->value()));
+ }
+}
+
+
+void AstExpressionVisitor::VisitArrayLiteral(ArrayLiteral* expr) {
+ VisitExpression(expr);
+ ZoneList<Expression*>* values = expr->values();
+ for (int i = 0; i < values->length(); ++i) {
+ Expression* value = values->at(i);
+ RECURSE_EXPRESSION(Visit(value));
+ }
+}
+
+
+void AstExpressionVisitor::VisitAssignment(Assignment* expr) {
+ VisitExpression(expr);
+ RECURSE_EXPRESSION(Visit(expr->target()));
+ RECURSE_EXPRESSION(Visit(expr->value()));
+}
+
+
+void AstExpressionVisitor::VisitYield(Yield* expr) {
+ VisitExpression(expr);
+ RECURSE_EXPRESSION(Visit(expr->generator_object()));
+ RECURSE_EXPRESSION(Visit(expr->expression()));
+}
+
+
+void AstExpressionVisitor::VisitThrow(Throw* expr) {
+ VisitExpression(expr);
+ RECURSE_EXPRESSION(Visit(expr->exception()));
+}
+
+
+void AstExpressionVisitor::VisitProperty(Property* expr) {
+ VisitExpression(expr);
+ RECURSE_EXPRESSION(Visit(expr->obj()));
+ RECURSE_EXPRESSION(Visit(expr->key()));
+}
+
+
+void AstExpressionVisitor::VisitCall(Call* expr) {
+ VisitExpression(expr);
+ RECURSE_EXPRESSION(Visit(expr->expression()));
+ ZoneList<Expression*>* args = expr->arguments();
+ for (int i = 0; i < args->length(); ++i) {
+ Expression* arg = args->at(i);
+ RECURSE_EXPRESSION(Visit(arg));
+ }
+}
+
+
+void AstExpressionVisitor::VisitCallNew(CallNew* expr) {
+ VisitExpression(expr);
+ RECURSE_EXPRESSION(Visit(expr->expression()));
+ ZoneList<Expression*>* args = expr->arguments();
+ for (int i = 0; i < args->length(); ++i) {
+ Expression* arg = args->at(i);
+ RECURSE_EXPRESSION(Visit(arg));
+ }
+}
+
+
+void AstExpressionVisitor::VisitCallRuntime(CallRuntime* expr) {
+ VisitExpression(expr);
+ ZoneList<Expression*>* args = expr->arguments();
+ for (int i = 0; i < args->length(); ++i) {
+ Expression* arg = args->at(i);
+ RECURSE_EXPRESSION(Visit(arg));
+ }
+}
+
+
+void AstExpressionVisitor::VisitUnaryOperation(UnaryOperation* expr) {
+ VisitExpression(expr);
+ RECURSE_EXPRESSION(Visit(expr->expression()));
+}
+
+
+void AstExpressionVisitor::VisitCountOperation(CountOperation* expr) {
+ VisitExpression(expr);
+ RECURSE_EXPRESSION(Visit(expr->expression()));
+}
+
+
+void AstExpressionVisitor::VisitBinaryOperation(BinaryOperation* expr) {
+ VisitExpression(expr);
+ RECURSE_EXPRESSION(Visit(expr->left()));
+ RECURSE_EXPRESSION(Visit(expr->right()));
+}
+
+
+void AstExpressionVisitor::VisitCompareOperation(CompareOperation* expr) {
+ VisitExpression(expr);
+ RECURSE_EXPRESSION(Visit(expr->left()));
+ RECURSE_EXPRESSION(Visit(expr->right()));
+}
+
+
+void AstExpressionVisitor::VisitThisFunction(ThisFunction* expr) {
+ VisitExpression(expr);
+}
+
+
+void AstExpressionVisitor::VisitDeclarations(ZoneList<Declaration*>* decls) {
+ for (int i = 0; i < decls->length(); ++i) {
+ Declaration* decl = decls->at(i);
+ RECURSE(Visit(decl));
+ }
+}
+
+
+void AstExpressionVisitor::VisitClassLiteral(ClassLiteral* expr) {
+ VisitExpression(expr);
+ if (expr->extends() != nullptr) {
+ RECURSE_EXPRESSION(Visit(expr->extends()));
+ }
+ RECURSE_EXPRESSION(Visit(expr->constructor()));
+ ZoneList<ObjectLiteralProperty*>* props = expr->properties();
+ for (int i = 0; i < props->length(); ++i) {
+ ObjectLiteralProperty* prop = props->at(i);
+ if (!prop->key()->IsLiteral()) {
+ RECURSE_EXPRESSION(Visit(prop->key()));
+ }
+ RECURSE_EXPRESSION(Visit(prop->value()));
+ }
+}
+
+
+void AstExpressionVisitor::VisitSpread(Spread* expr) {
+ VisitExpression(expr);
+ RECURSE_EXPRESSION(Visit(expr->expression()));
+}
+
+
+void AstExpressionVisitor::VisitEmptyParentheses(EmptyParentheses* expr) {}
+
+
+void AstExpressionVisitor::VisitSuperPropertyReference(
+ SuperPropertyReference* expr) {
+ VisitExpression(expr);
+ RECURSE_EXPRESSION(VisitVariableProxy(expr->this_var()));
+ RECURSE_EXPRESSION(Visit(expr->home_object()));
+}
+
+
+void AstExpressionVisitor::VisitSuperCallReference(SuperCallReference* expr) {
+ VisitExpression(expr);
+ RECURSE_EXPRESSION(VisitVariableProxy(expr->this_var()));
+ RECURSE_EXPRESSION(VisitVariableProxy(expr->new_target_var()));
+ RECURSE_EXPRESSION(VisitVariableProxy(expr->this_function_var()));
+}
+
+
+void AstExpressionVisitor::VisitRewritableAssignmentExpression(
+ RewritableAssignmentExpression* expr) {
+ VisitExpression(expr);
+ RECURSE(Visit(expr->expression()));
+}
+
+
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/ast/ast-expression-visitor.h b/deps/v8/src/ast/ast-expression-visitor.h
new file mode 100644
index 0000000000..cda624d5b7
--- /dev/null
+++ b/deps/v8/src/ast/ast-expression-visitor.h
@@ -0,0 +1,50 @@
+// 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_EXPRESSION_VISITOR_H_
+#define V8_AST_AST_EXPRESSION_VISITOR_H_
+
+#include "src/allocation.h"
+#include "src/ast/ast.h"
+#include "src/ast/scopes.h"
+#include "src/effects.h"
+#include "src/type-info.h"
+#include "src/types.h"
+#include "src/zone.h"
+
+namespace v8 {
+namespace internal {
+
+// A Visitor over a CompilationInfo's AST that invokes
+// VisitExpression on each expression node.
+
+class AstExpressionVisitor : public AstVisitor {
+ public:
+ AstExpressionVisitor(Isolate* isolate, Expression* root);
+ AstExpressionVisitor(uintptr_t stack_limit, Expression* root);
+ void Run();
+
+ protected:
+ virtual void VisitExpression(Expression* expression) = 0;
+ int depth() { return depth_; }
+
+ private:
+ void VisitDeclarations(ZoneList<Declaration*>* d) override;
+ void VisitStatements(ZoneList<Statement*>* s) override;
+
+ DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
+
+#define DECLARE_VISIT(type) void Visit##type(type* node) override;
+ AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+ Expression* root_;
+ int depth_;
+
+ DISALLOW_COPY_AND_ASSIGN(AstExpressionVisitor);
+};
+} // namespace internal
+} // namespace v8
+
+#endif // V8_AST_AST_EXPRESSION_VISITOR_H_
diff --git a/deps/v8/src/ast/ast-literal-reindexer.cc b/deps/v8/src/ast/ast-literal-reindexer.cc
new file mode 100644
index 0000000000..fce33e70b8
--- /dev/null
+++ b/deps/v8/src/ast/ast-literal-reindexer.cc
@@ -0,0 +1,331 @@
+// 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::VisitExportDeclaration(ExportDeclaration* 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) {
+ // TODO(caitp): literals in do expressions need re-indexing too.
+}
+
+
+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::VisitRewritableAssignmentExpression(
+ RewritableAssignmentExpression* node) {
+ Visit(node->expression());
+}
+
+
+void AstLiteralReindexer::VisitImportDeclaration(ImportDeclaration* node) {
+ VisitVariableProxy(node->proxy());
+}
+
+
+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) {
+ 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++) {
+ VisitObjectLiteralProperty(node->properties()->at(i));
+ }
+}
+
+
+void AstLiteralReindexer::VisitObjectLiteral(ObjectLiteral* node) {
+ UpdateIndex(node);
+ for (int i = 0; i < node->properties()->length(); i++) {
+ VisitObjectLiteralProperty(node->properties()->at(i));
+ }
+}
+
+
+void AstLiteralReindexer::VisitObjectLiteralProperty(
+ ObjectLiteralProperty* 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) {
+ pattern->Accept(this);
+}
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/ast/ast-literal-reindexer.h b/deps/v8/src/ast/ast-literal-reindexer.h
new file mode 100644
index 0000000000..e2a71d3c47
--- /dev/null
+++ b/deps/v8/src/ast/ast-literal-reindexer.h
@@ -0,0 +1,44 @@
+// 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 {
+ public:
+ AstLiteralReindexer() : AstVisitor(), next_index_(0) {}
+
+ int count() const { return next_index_; }
+ void Reindex(Expression* pattern);
+
+ private:
+#define DEFINE_VISIT(type) void Visit##type(type* node) override;
+ AST_NODE_LIST(DEFINE_VISIT)
+#undef DEFINE_VISIT
+
+ void VisitStatements(ZoneList<Statement*>* statements) override;
+ void VisitDeclarations(ZoneList<Declaration*>* declarations) override;
+ void VisitArguments(ZoneList<Expression*>* arguments);
+ void VisitObjectLiteralProperty(ObjectLiteralProperty* property);
+
+ void UpdateIndex(MaterializedLiteral* literal) {
+ literal->literal_index_ = next_index_++;
+ }
+
+ void Visit(AstNode* node) override { node->Accept(this); }
+
+ int next_index_;
+
+ DISALLOW_COPY_AND_ASSIGN(AstLiteralReindexer);
+};
+} // namespace internal
+} // namespace v8
+
+#endif // V8_AST_AST_LITERAL_REINDEXER
diff --git a/deps/v8/src/ast/ast-numbering.cc b/deps/v8/src/ast/ast-numbering.cc
new file mode 100644
index 0000000000..6c2b696a5d
--- /dev/null
+++ b/deps/v8/src/ast/ast-numbering.cc
@@ -0,0 +1,607 @@
+// Copyright 2012 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-numbering.h"
+
+#include "src/ast/ast.h"
+#include "src/ast/scopes.h"
+
+namespace v8 {
+namespace internal {
+
+class AstNumberingVisitor final : public AstVisitor {
+ public:
+ AstNumberingVisitor(Isolate* isolate, Zone* zone)
+ : AstVisitor(),
+ isolate_(isolate),
+ zone_(zone),
+ next_id_(BailoutId::FirstUsable().ToInt()),
+ properties_(zone),
+ slot_cache_(zone),
+ dont_optimize_reason_(kNoReason) {
+ InitializeAstVisitor(isolate);
+ }
+
+ bool Renumber(FunctionLiteral* node);
+
+ private:
+// AST node visitor interface.
+#define DEFINE_VISIT(type) void Visit##type(type* node) override;
+ AST_NODE_LIST(DEFINE_VISIT)
+#undef DEFINE_VISIT
+
+ bool Finish(FunctionLiteral* node);
+
+ void VisitVariableProxyReference(VariableProxy* node);
+ void VisitPropertyReference(Property* node);
+ void VisitReference(Expression* expr);
+
+ void VisitStatements(ZoneList<Statement*>* statements) override;
+ void VisitDeclarations(ZoneList<Declaration*>* declarations) override;
+ void VisitArguments(ZoneList<Expression*>* arguments);
+ void VisitObjectLiteralProperty(ObjectLiteralProperty* property);
+
+ int ReserveIdRange(int n) {
+ int tmp = next_id_;
+ next_id_ += n;
+ return tmp;
+ }
+
+ void IncrementNodeCount() { properties_.add_node_count(1); }
+ void DisableSelfOptimization() {
+ properties_.flags() |= AstProperties::kDontSelfOptimize;
+ }
+ void DisableOptimization(BailoutReason reason) {
+ dont_optimize_reason_ = reason;
+ DisableSelfOptimization();
+ }
+ void DisableCrankshaft(BailoutReason reason) {
+ if (FLAG_turbo_shipping) {
+ properties_.flags() |= AstProperties::kDontCrankshaft;
+ } else {
+ dont_optimize_reason_ = reason;
+ DisableSelfOptimization();
+ }
+ }
+
+ template <typename Node>
+ void ReserveFeedbackSlots(Node* node) {
+ node->AssignFeedbackVectorSlots(isolate_, properties_.get_spec(),
+ &slot_cache_);
+ }
+
+ BailoutReason dont_optimize_reason() const { return dont_optimize_reason_; }
+
+ Isolate* isolate_;
+ Zone* zone_;
+ int next_id_;
+ AstProperties properties_;
+ // The slot cache allows us to reuse certain feedback vector slots.
+ FeedbackVectorSlotCache slot_cache_;
+ BailoutReason dont_optimize_reason_;
+
+ DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
+ DISALLOW_COPY_AND_ASSIGN(AstNumberingVisitor);
+};
+
+
+void AstNumberingVisitor::VisitVariableDeclaration(VariableDeclaration* node) {
+ IncrementNodeCount();
+ VisitVariableProxy(node->proxy());
+}
+
+
+void AstNumberingVisitor::VisitExportDeclaration(ExportDeclaration* node) {
+ IncrementNodeCount();
+ DisableOptimization(kExportDeclaration);
+ VisitVariableProxy(node->proxy());
+}
+
+
+void AstNumberingVisitor::VisitEmptyStatement(EmptyStatement* node) {
+ IncrementNodeCount();
+}
+
+
+void AstNumberingVisitor::VisitSloppyBlockFunctionStatement(
+ SloppyBlockFunctionStatement* node) {
+ IncrementNodeCount();
+ Visit(node->statement());
+}
+
+
+void AstNumberingVisitor::VisitContinueStatement(ContinueStatement* node) {
+ IncrementNodeCount();
+}
+
+
+void AstNumberingVisitor::VisitBreakStatement(BreakStatement* node) {
+ IncrementNodeCount();
+}
+
+
+void AstNumberingVisitor::VisitDebuggerStatement(DebuggerStatement* node) {
+ IncrementNodeCount();
+ DisableOptimization(kDebuggerStatement);
+ node->set_base_id(ReserveIdRange(DebuggerStatement::num_ids()));
+}
+
+
+void AstNumberingVisitor::VisitNativeFunctionLiteral(
+ NativeFunctionLiteral* node) {
+ IncrementNodeCount();
+ DisableOptimization(kNativeFunctionLiteral);
+ node->set_base_id(ReserveIdRange(NativeFunctionLiteral::num_ids()));
+}
+
+
+void AstNumberingVisitor::VisitDoExpression(DoExpression* node) {
+ IncrementNodeCount();
+ DisableCrankshaft(kDoExpression);
+ node->set_base_id(ReserveIdRange(DoExpression::num_ids()));
+ Visit(node->block());
+ Visit(node->result());
+}
+
+
+void AstNumberingVisitor::VisitLiteral(Literal* node) {
+ IncrementNodeCount();
+ node->set_base_id(ReserveIdRange(Literal::num_ids()));
+}
+
+
+void AstNumberingVisitor::VisitRegExpLiteral(RegExpLiteral* node) {
+ IncrementNodeCount();
+ node->set_base_id(ReserveIdRange(RegExpLiteral::num_ids()));
+}
+
+
+void AstNumberingVisitor::VisitVariableProxyReference(VariableProxy* node) {
+ IncrementNodeCount();
+ if (node->var()->IsLookupSlot()) {
+ DisableCrankshaft(kReferenceToAVariableWhichRequiresDynamicLookup);
+ }
+ node->set_base_id(ReserveIdRange(VariableProxy::num_ids()));
+}
+
+
+void AstNumberingVisitor::VisitVariableProxy(VariableProxy* node) {
+ VisitVariableProxyReference(node);
+ ReserveFeedbackSlots(node);
+}
+
+
+void AstNumberingVisitor::VisitThisFunction(ThisFunction* node) {
+ IncrementNodeCount();
+ node->set_base_id(ReserveIdRange(ThisFunction::num_ids()));
+}
+
+
+void AstNumberingVisitor::VisitSuperPropertyReference(
+ SuperPropertyReference* node) {
+ IncrementNodeCount();
+ DisableCrankshaft(kSuperReference);
+ node->set_base_id(ReserveIdRange(SuperPropertyReference::num_ids()));
+ Visit(node->this_var());
+ Visit(node->home_object());
+}
+
+
+void AstNumberingVisitor::VisitSuperCallReference(SuperCallReference* node) {
+ IncrementNodeCount();
+ DisableCrankshaft(kSuperReference);
+ node->set_base_id(ReserveIdRange(SuperCallReference::num_ids()));
+ Visit(node->this_var());
+ Visit(node->new_target_var());
+ Visit(node->this_function_var());
+}
+
+
+void AstNumberingVisitor::VisitImportDeclaration(ImportDeclaration* node) {
+ IncrementNodeCount();
+ DisableOptimization(kImportDeclaration);
+ VisitVariableProxy(node->proxy());
+}
+
+
+void AstNumberingVisitor::VisitExpressionStatement(ExpressionStatement* node) {
+ IncrementNodeCount();
+ Visit(node->expression());
+}
+
+
+void AstNumberingVisitor::VisitReturnStatement(ReturnStatement* node) {
+ IncrementNodeCount();
+ Visit(node->expression());
+}
+
+
+void AstNumberingVisitor::VisitYield(Yield* node) {
+ IncrementNodeCount();
+ DisableOptimization(kYield);
+ ReserveFeedbackSlots(node);
+ node->set_base_id(ReserveIdRange(Yield::num_ids()));
+ Visit(node->generator_object());
+ Visit(node->expression());
+}
+
+
+void AstNumberingVisitor::VisitThrow(Throw* node) {
+ IncrementNodeCount();
+ node->set_base_id(ReserveIdRange(Throw::num_ids()));
+ Visit(node->exception());
+}
+
+
+void AstNumberingVisitor::VisitUnaryOperation(UnaryOperation* node) {
+ IncrementNodeCount();
+ node->set_base_id(ReserveIdRange(UnaryOperation::num_ids()));
+ Visit(node->expression());
+}
+
+
+void AstNumberingVisitor::VisitCountOperation(CountOperation* node) {
+ IncrementNodeCount();
+ node->set_base_id(ReserveIdRange(CountOperation::num_ids()));
+ Visit(node->expression());
+ ReserveFeedbackSlots(node);
+}
+
+
+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());
+}
+
+
+void AstNumberingVisitor::VisitFunctionDeclaration(FunctionDeclaration* node) {
+ IncrementNodeCount();
+ VisitVariableProxy(node->proxy());
+ VisitFunctionLiteral(node->fun());
+}
+
+
+void AstNumberingVisitor::VisitCallRuntime(CallRuntime* node) {
+ IncrementNodeCount();
+ ReserveFeedbackSlots(node);
+ if (node->is_jsruntime()) {
+ // Don't try to optimize JS runtime calls because we bailout on them.
+ DisableOptimization(kCallToAJavaScriptRuntimeFunction);
+ }
+ node->set_base_id(ReserveIdRange(CallRuntime::num_ids()));
+ VisitArguments(node->arguments());
+}
+
+
+void AstNumberingVisitor::VisitWithStatement(WithStatement* node) {
+ IncrementNodeCount();
+ DisableCrankshaft(kWithStatement);
+ node->set_base_id(ReserveIdRange(WithStatement::num_ids()));
+ Visit(node->expression());
+ Visit(node->statement());
+}
+
+
+void AstNumberingVisitor::VisitDoWhileStatement(DoWhileStatement* node) {
+ IncrementNodeCount();
+ DisableSelfOptimization();
+ node->set_base_id(ReserveIdRange(DoWhileStatement::num_ids()));
+ Visit(node->body());
+ Visit(node->cond());
+}
+
+
+void AstNumberingVisitor::VisitWhileStatement(WhileStatement* node) {
+ IncrementNodeCount();
+ DisableSelfOptimization();
+ node->set_base_id(ReserveIdRange(WhileStatement::num_ids()));
+ Visit(node->cond());
+ Visit(node->body());
+}
+
+
+void AstNumberingVisitor::VisitTryCatchStatement(TryCatchStatement* node) {
+ IncrementNodeCount();
+ DisableOptimization(kTryCatchStatement);
+ node->set_base_id(ReserveIdRange(TryCatchStatement::num_ids()));
+ Visit(node->try_block());
+ Visit(node->catch_block());
+}
+
+
+void AstNumberingVisitor::VisitTryFinallyStatement(TryFinallyStatement* node) {
+ IncrementNodeCount();
+ DisableOptimization(kTryFinallyStatement);
+ node->set_base_id(ReserveIdRange(TryFinallyStatement::num_ids()));
+ Visit(node->try_block());
+ Visit(node->finally_block());
+}
+
+
+void AstNumberingVisitor::VisitPropertyReference(Property* node) {
+ IncrementNodeCount();
+ node->set_base_id(ReserveIdRange(Property::num_ids()));
+ Visit(node->key());
+ Visit(node->obj());
+}
+
+
+void AstNumberingVisitor::VisitReference(Expression* expr) {
+ DCHECK(expr->IsProperty() || expr->IsVariableProxy());
+ if (expr->IsProperty()) {
+ VisitPropertyReference(expr->AsProperty());
+ } else {
+ VisitVariableProxyReference(expr->AsVariableProxy());
+ }
+}
+
+
+void AstNumberingVisitor::VisitProperty(Property* node) {
+ VisitPropertyReference(node);
+ ReserveFeedbackSlots(node);
+}
+
+
+void AstNumberingVisitor::VisitAssignment(Assignment* node) {
+ IncrementNodeCount();
+ node->set_base_id(ReserveIdRange(Assignment::num_ids()));
+
+ if (node->is_compound()) VisitBinaryOperation(node->binary_operation());
+ VisitReference(node->target());
+ Visit(node->value());
+ ReserveFeedbackSlots(node);
+}
+
+
+void AstNumberingVisitor::VisitBinaryOperation(BinaryOperation* node) {
+ IncrementNodeCount();
+ node->set_base_id(ReserveIdRange(BinaryOperation::num_ids()));
+ Visit(node->left());
+ Visit(node->right());
+}
+
+
+void AstNumberingVisitor::VisitCompareOperation(CompareOperation* node) {
+ IncrementNodeCount();
+ node->set_base_id(ReserveIdRange(CompareOperation::num_ids()));
+ Visit(node->left());
+ Visit(node->right());
+}
+
+
+void AstNumberingVisitor::VisitSpread(Spread* node) {
+ IncrementNodeCount();
+ DisableCrankshaft(kSpread);
+ Visit(node->expression());
+}
+
+
+void AstNumberingVisitor::VisitEmptyParentheses(EmptyParentheses* node) {
+ UNREACHABLE();
+}
+
+
+void AstNumberingVisitor::VisitForInStatement(ForInStatement* node) {
+ IncrementNodeCount();
+ DisableSelfOptimization();
+ node->set_base_id(ReserveIdRange(ForInStatement::num_ids()));
+ Visit(node->each());
+ Visit(node->enumerable());
+ Visit(node->body());
+ ReserveFeedbackSlots(node);
+}
+
+
+void AstNumberingVisitor::VisitForOfStatement(ForOfStatement* node) {
+ IncrementNodeCount();
+ DisableCrankshaft(kForOfStatement);
+ node->set_base_id(ReserveIdRange(ForOfStatement::num_ids()));
+ Visit(node->assign_iterator());
+ Visit(node->next_result());
+ Visit(node->result_done());
+ Visit(node->assign_each());
+ Visit(node->body());
+ ReserveFeedbackSlots(node);
+}
+
+
+void AstNumberingVisitor::VisitConditional(Conditional* node) {
+ IncrementNodeCount();
+ node->set_base_id(ReserveIdRange(Conditional::num_ids()));
+ Visit(node->condition());
+ Visit(node->then_expression());
+ Visit(node->else_expression());
+}
+
+
+void AstNumberingVisitor::VisitIfStatement(IfStatement* node) {
+ IncrementNodeCount();
+ node->set_base_id(ReserveIdRange(IfStatement::num_ids()));
+ Visit(node->condition());
+ Visit(node->then_statement());
+ if (node->HasElseStatement()) {
+ Visit(node->else_statement());
+ }
+}
+
+
+void AstNumberingVisitor::VisitSwitchStatement(SwitchStatement* node) {
+ IncrementNodeCount();
+ node->set_base_id(ReserveIdRange(SwitchStatement::num_ids()));
+ Visit(node->tag());
+ ZoneList<CaseClause*>* cases = node->cases();
+ for (int i = 0; i < cases->length(); i++) {
+ VisitCaseClause(cases->at(i));
+ }
+}
+
+
+void AstNumberingVisitor::VisitCaseClause(CaseClause* node) {
+ IncrementNodeCount();
+ node->set_base_id(ReserveIdRange(CaseClause::num_ids()));
+ if (!node->is_default()) Visit(node->label());
+ VisitStatements(node->statements());
+}
+
+
+void AstNumberingVisitor::VisitForStatement(ForStatement* node) {
+ IncrementNodeCount();
+ DisableSelfOptimization();
+ node->set_base_id(ReserveIdRange(ForStatement::num_ids()));
+ 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 AstNumberingVisitor::VisitClassLiteral(ClassLiteral* node) {
+ IncrementNodeCount();
+ DisableCrankshaft(kClassLiteral);
+ node->set_base_id(ReserveIdRange(node->num_ids()));
+ 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++) {
+ VisitObjectLiteralProperty(node->properties()->at(i));
+ }
+ ReserveFeedbackSlots(node);
+}
+
+
+void AstNumberingVisitor::VisitObjectLiteral(ObjectLiteral* node) {
+ IncrementNodeCount();
+ node->set_base_id(ReserveIdRange(node->num_ids()));
+ for (int i = 0; i < node->properties()->length(); i++) {
+ VisitObjectLiteralProperty(node->properties()->at(i));
+ }
+ node->BuildConstantProperties(isolate_);
+ // 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.
+ node->CalculateEmitStore(zone_);
+ ReserveFeedbackSlots(node);
+}
+
+
+void AstNumberingVisitor::VisitObjectLiteralProperty(
+ ObjectLiteralProperty* node) {
+ if (node->is_computed_name()) DisableCrankshaft(kComputedPropertyName);
+ Visit(node->key());
+ Visit(node->value());
+}
+
+
+void AstNumberingVisitor::VisitArrayLiteral(ArrayLiteral* node) {
+ IncrementNodeCount();
+ node->set_base_id(ReserveIdRange(node->num_ids()));
+ for (int i = 0; i < node->values()->length(); i++) {
+ Visit(node->values()->at(i));
+ }
+ node->BuildConstantElements(isolate_);
+ ReserveFeedbackSlots(node);
+}
+
+
+void AstNumberingVisitor::VisitCall(Call* node) {
+ IncrementNodeCount();
+ ReserveFeedbackSlots(node);
+ node->set_base_id(ReserveIdRange(Call::num_ids()));
+ Visit(node->expression());
+ VisitArguments(node->arguments());
+}
+
+
+void AstNumberingVisitor::VisitCallNew(CallNew* node) {
+ IncrementNodeCount();
+ ReserveFeedbackSlots(node);
+ node->set_base_id(ReserveIdRange(CallNew::num_ids()));
+ Visit(node->expression());
+ VisitArguments(node->arguments());
+}
+
+
+void AstNumberingVisitor::VisitStatements(ZoneList<Statement*>* statements) {
+ if (statements == NULL) return;
+ for (int i = 0; i < statements->length(); i++) {
+ Visit(statements->at(i));
+ }
+}
+
+
+void AstNumberingVisitor::VisitDeclarations(
+ ZoneList<Declaration*>* declarations) {
+ for (int i = 0; i < declarations->length(); i++) {
+ Visit(declarations->at(i));
+ }
+}
+
+
+void AstNumberingVisitor::VisitArguments(ZoneList<Expression*>* arguments) {
+ for (int i = 0; i < arguments->length(); i++) {
+ Visit(arguments->at(i));
+ }
+}
+
+
+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.
+}
+
+
+void AstNumberingVisitor::VisitRewritableAssignmentExpression(
+ RewritableAssignmentExpression* node) {
+ IncrementNodeCount();
+ node->set_base_id(ReserveIdRange(RewritableAssignmentExpression::num_ids()));
+ Visit(node->expression());
+}
+
+
+bool AstNumberingVisitor::Finish(FunctionLiteral* node) {
+ node->set_ast_properties(&properties_);
+ node->set_dont_optimize_reason(dont_optimize_reason());
+ return !HasStackOverflow();
+}
+
+
+bool AstNumberingVisitor::Renumber(FunctionLiteral* node) {
+ Scope* scope = node->scope();
+
+ if (scope->HasIllegalRedeclaration()) {
+ Visit(scope->GetIllegalRedeclaration());
+ DisableOptimization(kFunctionWithIllegalRedeclaration);
+ return Finish(node);
+ }
+ if (scope->new_target_var()) DisableCrankshaft(kSuperReference);
+ if (scope->calls_eval()) DisableOptimization(kFunctionCallsEval);
+ if (scope->arguments() != NULL && !scope->arguments()->IsStackAllocated()) {
+ DisableCrankshaft(kContextAllocatedArguments);
+ }
+
+ int rest_index;
+ if (scope->rest_parameter(&rest_index)) {
+ DisableCrankshaft(kRestParameter);
+ }
+
+ VisitDeclarations(scope->declarations());
+ VisitStatements(node->body());
+
+ return Finish(node);
+}
+
+
+bool AstNumbering::Renumber(Isolate* isolate, Zone* zone,
+ FunctionLiteral* function) {
+ AstNumberingVisitor visitor(isolate, zone);
+ return visitor.Renumber(function);
+}
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/ast/ast-numbering.h b/deps/v8/src/ast/ast-numbering.h
new file mode 100644
index 0000000000..0ac1ef2134
--- /dev/null
+++ b/deps/v8/src/ast/ast-numbering.h
@@ -0,0 +1,25 @@
+// Copyright 2014 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_NUMBERING_H_
+#define V8_AST_AST_NUMBERING_H_
+
+namespace v8 {
+namespace internal {
+
+// Forward declarations.
+class FunctionLiteral;
+class Isolate;
+class Zone;
+
+namespace AstNumbering {
+// Assign type feedback IDs and bailout IDs to an AST node tree.
+//
+bool Renumber(Isolate* isolate, Zone* zone, FunctionLiteral* function);
+}
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_AST_AST_NUMBERING_H_
diff --git a/deps/v8/src/ast/ast-value-factory.cc b/deps/v8/src/ast/ast-value-factory.cc
new file mode 100644
index 0000000000..2e17fbcfaf
--- /dev/null
+++ b/deps/v8/src/ast/ast-value-factory.cc
@@ -0,0 +1,411 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/ast/ast-value-factory.h"
+
+#include "src/api.h"
+#include "src/objects.h"
+#include "src/utils.h"
+
+namespace v8 {
+namespace internal {
+
+namespace {
+
+// For using StringToArrayIndex.
+class OneByteStringStream {
+ public:
+ explicit OneByteStringStream(Vector<const byte> lb) :
+ literal_bytes_(lb), pos_(0) {}
+
+ bool HasMore() { return pos_ < literal_bytes_.length(); }
+ uint16_t GetNext() { return literal_bytes_[pos_++]; }
+
+ private:
+ Vector<const byte> literal_bytes_;
+ int pos_;
+};
+
+} // namespace
+
+class AstRawStringInternalizationKey : public HashTableKey {
+ public:
+ explicit AstRawStringInternalizationKey(const AstRawString* string)
+ : string_(string) {}
+
+ bool IsMatch(Object* other) override {
+ if (string_->is_one_byte_)
+ return String::cast(other)->IsOneByteEqualTo(string_->literal_bytes_);
+ return String::cast(other)->IsTwoByteEqualTo(
+ Vector<const uint16_t>::cast(string_->literal_bytes_));
+ }
+
+ uint32_t Hash() override { return string_->hash() >> Name::kHashShift; }
+
+ uint32_t HashForObject(Object* key) override {
+ return String::cast(key)->Hash();
+ }
+
+ Handle<Object> AsHandle(Isolate* isolate) override {
+ if (string_->is_one_byte_)
+ return isolate->factory()->NewOneByteInternalizedString(
+ string_->literal_bytes_, string_->hash());
+ return isolate->factory()->NewTwoByteInternalizedString(
+ Vector<const uint16_t>::cast(string_->literal_bytes_), string_->hash());
+ }
+
+ private:
+ const AstRawString* string_;
+};
+
+
+void AstRawString::Internalize(Isolate* isolate) {
+ if (!string_.is_null()) return;
+ if (literal_bytes_.length() == 0) {
+ string_ = isolate->factory()->empty_string();
+ } else {
+ AstRawStringInternalizationKey key(this);
+ string_ = StringTable::LookupKey(isolate, &key);
+ }
+}
+
+
+bool AstRawString::AsArrayIndex(uint32_t* index) const {
+ if (!string_.is_null())
+ return string_->AsArrayIndex(index);
+ if (!is_one_byte_ || literal_bytes_.length() == 0 ||
+ literal_bytes_.length() > String::kMaxArrayIndexSize)
+ return false;
+ OneByteStringStream stream(literal_bytes_);
+ return StringToArrayIndex(&stream, index);
+}
+
+
+bool AstRawString::IsOneByteEqualTo(const char* data) const {
+ int length = static_cast<int>(strlen(data));
+ if (is_one_byte_ && literal_bytes_.length() == length) {
+ const char* token = reinterpret_cast<const char*>(literal_bytes_.start());
+ return !strncmp(token, data, length);
+ }
+ return false;
+}
+
+
+void AstConsString::Internalize(Isolate* isolate) {
+ // AstRawStrings are internalized before AstConsStrings so left and right are
+ // already internalized.
+ string_ = isolate->factory()
+ ->NewConsString(left_->string(), right_->string())
+ .ToHandleChecked();
+}
+
+
+bool AstValue::IsPropertyName() const {
+ if (type_ == STRING) {
+ uint32_t index;
+ return !string_->AsArrayIndex(&index);
+ }
+ return false;
+}
+
+
+bool AstValue::BooleanValue() const {
+ switch (type_) {
+ case STRING:
+ DCHECK(string_ != NULL);
+ return !string_->IsEmpty();
+ case SYMBOL:
+ UNREACHABLE();
+ break;
+ case NUMBER_WITH_DOT:
+ case NUMBER:
+ return DoubleToBoolean(number_);
+ case SMI:
+ return smi_ != 0;
+ case BOOLEAN:
+ return bool_;
+ case NULL_TYPE:
+ return false;
+ case THE_HOLE:
+ UNREACHABLE();
+ break;
+ case UNDEFINED:
+ return false;
+ }
+ UNREACHABLE();
+ return false;
+}
+
+
+void AstValue::Internalize(Isolate* isolate) {
+ switch (type_) {
+ case STRING:
+ DCHECK(string_ != NULL);
+ // Strings are already internalized.
+ DCHECK(!string_->string().is_null());
+ break;
+ case SYMBOL:
+ if (symbol_name_[0] == 'i') {
+ DCHECK_EQ(0, strcmp(symbol_name_, "iterator_symbol"));
+ value_ = isolate->factory()->iterator_symbol();
+ } else {
+ DCHECK_EQ(0, strcmp(symbol_name_, "home_object_symbol"));
+ value_ = isolate->factory()->home_object_symbol();
+ }
+ break;
+ case NUMBER_WITH_DOT:
+ case NUMBER:
+ value_ = isolate->factory()->NewNumber(number_, TENURED);
+ break;
+ case SMI:
+ value_ = handle(Smi::FromInt(smi_), isolate);
+ break;
+ case BOOLEAN:
+ if (bool_) {
+ value_ = isolate->factory()->true_value();
+ } else {
+ value_ = isolate->factory()->false_value();
+ }
+ break;
+ case NULL_TYPE:
+ value_ = isolate->factory()->null_value();
+ break;
+ case THE_HOLE:
+ value_ = isolate->factory()->the_hole_value();
+ break;
+ case UNDEFINED:
+ value_ = isolate->factory()->undefined_value();
+ break;
+ }
+}
+
+
+AstRawString* AstValueFactory::GetOneByteStringInternal(
+ Vector<const uint8_t> literal) {
+ uint32_t hash = StringHasher::HashSequentialString<uint8_t>(
+ literal.start(), literal.length(), hash_seed_);
+ return GetString(hash, true, literal);
+}
+
+
+AstRawString* AstValueFactory::GetTwoByteStringInternal(
+ Vector<const uint16_t> literal) {
+ uint32_t hash = StringHasher::HashSequentialString<uint16_t>(
+ literal.start(), literal.length(), hash_seed_);
+ return GetString(hash, false, Vector<const byte>::cast(literal));
+}
+
+
+const AstRawString* AstValueFactory::GetString(Handle<String> literal) {
+ // For the FlatContent to stay valid, we shouldn't do any heap
+ // allocation. Make sure we won't try to internalize the string in GetString.
+ AstRawString* result = NULL;
+ Isolate* saved_isolate = isolate_;
+ isolate_ = NULL;
+ {
+ DisallowHeapAllocation no_gc;
+ String::FlatContent content = literal->GetFlatContent();
+ if (content.IsOneByte()) {
+ result = GetOneByteStringInternal(content.ToOneByteVector());
+ } else {
+ DCHECK(content.IsTwoByte());
+ result = GetTwoByteStringInternal(content.ToUC16Vector());
+ }
+ }
+ isolate_ = saved_isolate;
+ if (isolate_) result->Internalize(isolate_);
+ return result;
+}
+
+
+const AstConsString* AstValueFactory::NewConsString(
+ const AstString* left, const AstString* right) {
+ // This Vector will be valid as long as the Collector is alive (meaning that
+ // the AstRawString will not be moved).
+ AstConsString* new_string = new (zone_) AstConsString(left, right);
+ strings_.Add(new_string);
+ if (isolate_) {
+ new_string->Internalize(isolate_);
+ }
+ return new_string;
+}
+
+
+void AstValueFactory::Internalize(Isolate* isolate) {
+ if (isolate_) {
+ // Everything is already internalized.
+ return;
+ }
+ // Strings need to be internalized before values, because values refer to
+ // strings.
+ for (int i = 0; i < strings_.length(); ++i) {
+ strings_[i]->Internalize(isolate);
+ }
+ for (int i = 0; i < values_.length(); ++i) {
+ values_[i]->Internalize(isolate);
+ }
+ isolate_ = isolate;
+}
+
+
+const AstValue* AstValueFactory::NewString(const AstRawString* string) {
+ AstValue* value = new (zone_) AstValue(string);
+ DCHECK(string != NULL);
+ if (isolate_) {
+ value->Internalize(isolate_);
+ }
+ values_.Add(value);
+ return value;
+}
+
+
+const AstValue* AstValueFactory::NewSymbol(const char* name) {
+ AstValue* value = new (zone_) AstValue(name);
+ if (isolate_) {
+ value->Internalize(isolate_);
+ }
+ values_.Add(value);
+ return value;
+}
+
+
+const AstValue* AstValueFactory::NewNumber(double number, bool with_dot) {
+ AstValue* value = new (zone_) AstValue(number, with_dot);
+ if (isolate_) {
+ value->Internalize(isolate_);
+ }
+ values_.Add(value);
+ return value;
+}
+
+
+const AstValue* AstValueFactory::NewSmi(int number) {
+ AstValue* value =
+ new (zone_) AstValue(AstValue::SMI, number);
+ if (isolate_) {
+ value->Internalize(isolate_);
+ }
+ values_.Add(value);
+ return value;
+}
+
+
+#define GENERATE_VALUE_GETTER(value, initializer) \
+ if (!value) { \
+ value = new (zone_) AstValue(initializer); \
+ if (isolate_) { \
+ value->Internalize(isolate_); \
+ } \
+ values_.Add(value); \
+ } \
+ return value;
+
+
+const AstValue* AstValueFactory::NewBoolean(bool b) {
+ if (b) {
+ GENERATE_VALUE_GETTER(true_value_, true);
+ } else {
+ GENERATE_VALUE_GETTER(false_value_, false);
+ }
+}
+
+
+const AstValue* AstValueFactory::NewNull() {
+ GENERATE_VALUE_GETTER(null_value_, AstValue::NULL_TYPE);
+}
+
+
+const AstValue* AstValueFactory::NewUndefined() {
+ GENERATE_VALUE_GETTER(undefined_value_, AstValue::UNDEFINED);
+}
+
+
+const AstValue* AstValueFactory::NewTheHole() {
+ GENERATE_VALUE_GETTER(the_hole_value_, AstValue::THE_HOLE);
+}
+
+
+#undef GENERATE_VALUE_GETTER
+
+AstRawString* AstValueFactory::GetString(uint32_t hash, bool is_one_byte,
+ Vector<const byte> literal_bytes) {
+ // literal_bytes here points to whatever the user passed, and this is OK
+ // because we use vector_compare (which checks the contents) to compare
+ // against the AstRawStrings which are in the string_table_. We should not
+ // return this AstRawString.
+ AstRawString key(is_one_byte, literal_bytes, hash);
+ HashMap::Entry* entry = string_table_.LookupOrInsert(&key, hash);
+ if (entry->value == NULL) {
+ // Copy literal contents for later comparison.
+ int length = literal_bytes.length();
+ byte* new_literal_bytes = zone_->NewArray<byte>(length);
+ memcpy(new_literal_bytes, literal_bytes.start(), length);
+ AstRawString* new_string = new (zone_) AstRawString(
+ is_one_byte, Vector<const byte>(new_literal_bytes, length), hash);
+ entry->key = new_string;
+ strings_.Add(new_string);
+ if (isolate_) {
+ new_string->Internalize(isolate_);
+ }
+ entry->value = reinterpret_cast<void*>(1);
+ }
+ 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);
+ if (lhs->length() != rhs->length()) return false;
+ if (lhs->hash() != rhs->hash()) 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/deps/v8/src/ast/ast-value-factory.h b/deps/v8/src/ast/ast-value-factory.h
new file mode 100644
index 0000000000..4ae912ea82
--- /dev/null
+++ b/deps/v8/src/ast/ast-value-factory.h
@@ -0,0 +1,375 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_AST_AST_VALUE_FACTORY_H_
+#define V8_AST_AST_VALUE_FACTORY_H_
+
+#include "src/api.h"
+#include "src/hashmap.h"
+#include "src/utils.h"
+
+// AstString, AstValue and AstValueFactory are for storing strings and values
+// independent of the V8 heap and internalizing them later. During parsing,
+// AstStrings and AstValues are created and stored outside the heap, in
+// AstValueFactory. After parsing, the strings and values are internalized
+// (moved into the V8 heap).
+namespace v8 {
+namespace internal {
+
+class AstString : public ZoneObject {
+ public:
+ virtual ~AstString() {}
+
+ virtual int length() const = 0;
+ bool IsEmpty() const { return length() == 0; }
+
+ // Puts the string into the V8 heap.
+ virtual void Internalize(Isolate* isolate) = 0;
+
+ // This function can be called after internalizing.
+ V8_INLINE Handle<String> string() const {
+ DCHECK(!string_.is_null());
+ return string_;
+ }
+
+ protected:
+ // This is null until the string is internalized.
+ Handle<String> string_;
+};
+
+
+class AstRawString final : public AstString {
+ public:
+ int length() const override {
+ if (is_one_byte_)
+ return literal_bytes_.length();
+ return literal_bytes_.length() / 2;
+ }
+
+ int byte_length() const { return literal_bytes_.length(); }
+
+ void Internalize(Isolate* isolate) override;
+
+ bool AsArrayIndex(uint32_t* index) const;
+
+ // The string is not null-terminated, use length() to find out the length.
+ const unsigned char* raw_data() const {
+ return literal_bytes_.start();
+ }
+ bool is_one_byte() const { return is_one_byte_; }
+ bool IsOneByteEqualTo(const char* data) const;
+ uint16_t FirstCharacter() const {
+ if (is_one_byte_)
+ return literal_bytes_[0];
+ const uint16_t* c =
+ reinterpret_cast<const uint16_t*>(literal_bytes_.start());
+ return *c;
+ }
+
+ // For storing AstRawStrings in a hash map.
+ uint32_t hash() const {
+ return hash_;
+ }
+
+ private:
+ friend class AstValueFactory;
+ friend class AstRawStringInternalizationKey;
+
+ AstRawString(bool is_one_byte, const Vector<const byte>& literal_bytes,
+ uint32_t hash)
+ : is_one_byte_(is_one_byte), literal_bytes_(literal_bytes), hash_(hash) {}
+
+ AstRawString()
+ : is_one_byte_(true),
+ hash_(0) {}
+
+ bool is_one_byte_;
+
+ // Points to memory owned by Zone.
+ Vector<const byte> literal_bytes_;
+ uint32_t hash_;
+};
+
+
+class AstConsString final : public AstString {
+ public:
+ AstConsString(const AstString* left, const AstString* right)
+ : length_(left->length() + right->length()), left_(left), right_(right) {}
+
+ int length() const override { return length_; }
+
+ void Internalize(Isolate* isolate) override;
+
+ private:
+ const int length_;
+ const AstString* left_;
+ const AstString* right_;
+};
+
+
+// AstValue is either a string, 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;
+ }
+
+ bool ContainsDot() const { return type_ == NUMBER_WITH_DOT; }
+
+ const AstRawString* AsString() const {
+ if (type_ == STRING)
+ return string_;
+ UNREACHABLE();
+ return 0;
+ }
+
+ double AsNumber() const {
+ if (type_ == NUMBER || type_ == NUMBER_WITH_DOT)
+ return number_;
+ if (type_ == SMI)
+ return smi_;
+ UNREACHABLE();
+ return 0;
+ }
+
+ bool EqualsString(const AstRawString* string) const {
+ return type_ == STRING && string_ == string;
+ }
+
+ bool IsPropertyName() const;
+
+ bool BooleanValue() const;
+
+ bool IsTheHole() const { return type_ == THE_HOLE; }
+
+ void Internalize(Isolate* isolate);
+
+ // Can be called after Internalize has been called.
+ V8_INLINE Handle<Object> value() const {
+ if (type_ == STRING) {
+ return string_->string();
+ }
+ DCHECK(!value_.is_null());
+ return value_;
+ }
+
+ private:
+ friend class AstValueFactory;
+
+ enum Type {
+ STRING,
+ SYMBOL,
+ NUMBER,
+ NUMBER_WITH_DOT,
+ SMI,
+ BOOLEAN,
+ NULL_TYPE,
+ UNDEFINED,
+ THE_HOLE
+ };
+
+ explicit AstValue(const AstRawString* s) : type_(STRING) { string_ = s; }
+
+ explicit AstValue(const char* name) : type_(SYMBOL) { symbol_name_ = name; }
+
+ explicit AstValue(double n, bool with_dot) {
+ if (with_dot) {
+ type_ = NUMBER_WITH_DOT;
+ } else {
+ type_ = NUMBER;
+ }
+ number_ = n;
+ }
+
+ AstValue(Type t, int i) : type_(t) {
+ DCHECK(type_ == SMI);
+ smi_ = i;
+ }
+
+ explicit AstValue(bool b) : type_(BOOLEAN) { bool_ = b; }
+
+ explicit AstValue(Type t) : type_(t) {
+ DCHECK(t == NULL_TYPE || t == UNDEFINED || t == THE_HOLE);
+ }
+
+ Type type_;
+
+ // Uninternalized value.
+ union {
+ const AstRawString* string_;
+ double number_;
+ int smi_;
+ bool bool_;
+ ZoneList<const AstRawString*>* strings_;
+ const char* symbol_name_;
+ };
+
+ // Internalized value (empty before internalized).
+ Handle<Object> value_;
+};
+
+
+// For generating constants.
+#define STRING_CONSTANTS(F) \
+ F(anonymous_function, "(anonymous function)") \
+ F(arguments, "arguments") \
+ F(constructor, "constructor") \
+ F(default, "default") \
+ F(done, "done") \
+ F(dot, ".") \
+ F(dot_for, ".for") \
+ F(dot_generator, ".generator") \
+ F(dot_generator_object, ".generator_object") \
+ F(dot_iterator, ".iterator") \
+ F(dot_result, ".result") \
+ F(dot_switch_tag, ".switch_tag") \
+ F(dot_catch, ".catch") \
+ F(empty, "") \
+ F(eval, "eval") \
+ F(get_space, "get ") \
+ F(let, "let") \
+ F(native, "native") \
+ F(new_target, ".new.target") \
+ F(next, "next") \
+ F(proto, "__proto__") \
+ F(prototype, "prototype") \
+ F(rest_parameter, ".rest_parameter") \
+ F(set_space, "set ") \
+ F(this, "this") \
+ F(this_function, ".this_function") \
+ F(undefined, "undefined") \
+ F(use_asm, "use asm") \
+ F(use_strong, "use strong") \
+ F(use_strict, "use strict") \
+ F(value, "value")
+
+#define OTHER_CONSTANTS(F) \
+ F(true_value) \
+ F(false_value) \
+ F(null_value) \
+ F(undefined_value) \
+ F(the_hole_value)
+
+class AstValueFactory {
+ public:
+ AstValueFactory(Zone* zone, uint32_t hash_seed)
+ : string_table_(AstRawStringCompare),
+ zone_(zone),
+ isolate_(NULL),
+ hash_seed_(hash_seed) {
+#define F(name, str) name##_string_ = NULL;
+ STRING_CONSTANTS(F)
+#undef F
+#define F(name) name##_ = NULL;
+ OTHER_CONSTANTS(F)
+#undef F
+ }
+
+ Zone* zone() const { return zone_; }
+
+ const AstRawString* GetOneByteString(Vector<const uint8_t> literal) {
+ return GetOneByteStringInternal(literal);
+ }
+ const AstRawString* GetOneByteString(const char* string) {
+ return GetOneByteString(Vector<const uint8_t>(
+ reinterpret_cast<const uint8_t*>(string), StrLength(string)));
+ }
+ const AstRawString* GetTwoByteString(Vector<const uint16_t> literal) {
+ return GetTwoByteStringInternal(literal);
+ }
+ const AstRawString* GetString(Handle<String> literal);
+ const AstConsString* NewConsString(const AstString* left,
+ const AstString* right);
+
+ void Internalize(Isolate* isolate);
+ bool IsInternalized() {
+ return isolate_ != NULL;
+ }
+
+#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_; \
+ }
+ STRING_CONSTANTS(F)
+#undef F
+
+ 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* NewSmi(int number);
+ const AstValue* NewBoolean(bool b);
+ const AstValue* NewStringList(ZoneList<const AstRawString*>* strings);
+ const AstValue* NewNull();
+ const AstValue* NewUndefined();
+ const AstValue* NewTheHole();
+
+ private:
+ AstRawString* GetOneByteStringInternal(Vector<const uint8_t> literal);
+ AstRawString* GetTwoByteStringInternal(Vector<const uint16_t> literal);
+ 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).
+ HashMap string_table_;
+ // For keeping track of all AstValues and AstRawStrings we've created (so that
+ // they can be internalized later).
+ List<AstValue*> values_;
+ List<AstString*> strings_;
+ Zone* zone_;
+ Isolate* isolate_;
+
+ 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
+};
+} // namespace internal
+} // namespace v8
+
+#undef STRING_CONSTANTS
+#undef OTHER_CONSTANTS
+
+#endif // V8_AST_AST_VALUE_FACTORY_H_
diff --git a/deps/v8/src/ast/ast.cc b/deps/v8/src/ast/ast.cc
new file mode 100644
index 0000000000..69e7351a7d
--- /dev/null
+++ b/deps/v8/src/ast/ast.cc
@@ -0,0 +1,826 @@
+// Copyright 2012 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.h"
+
+#include <cmath> // For isfinite.
+#include "src/ast/scopes.h"
+#include "src/builtins.h"
+#include "src/code-stubs.h"
+#include "src/contexts.h"
+#include "src/conversions.h"
+#include "src/hashmap.h"
+#include "src/parsing/parser.h"
+#include "src/property.h"
+#include "src/property-details.h"
+#include "src/string-stream.h"
+#include "src/type-info.h"
+
+namespace v8 {
+namespace internal {
+
+// ----------------------------------------------------------------------------
+// All the Accept member functions for each syntax tree node type.
+
+#define DECL_ACCEPT(type) \
+ void type::Accept(AstVisitor* v) { v->Visit##type(this); }
+AST_NODE_LIST(DECL_ACCEPT)
+#undef DECL_ACCEPT
+
+
+// ----------------------------------------------------------------------------
+// Implementation of other node functionality.
+
+
+bool Expression::IsSmiLiteral() const {
+ return IsLiteral() && AsLiteral()->value()->IsSmi();
+}
+
+
+bool Expression::IsStringLiteral() const {
+ return IsLiteral() && AsLiteral()->value()->IsString();
+}
+
+
+bool Expression::IsNullLiteral() const {
+ return IsLiteral() && AsLiteral()->value()->IsNull();
+}
+
+
+bool Expression::IsUndefinedLiteral(Isolate* isolate) const {
+ const VariableProxy* var_proxy = AsVariableProxy();
+ if (var_proxy == NULL) return false;
+ Variable* var = var_proxy->var();
+ // The global identifier "undefined" is immutable. Everything
+ // else could be reassigned.
+ return var != NULL && var->IsUnallocatedOrGlobalSlot() &&
+ var_proxy->raw_name()->IsOneByteEqualTo("undefined");
+}
+
+
+bool Expression::IsValidReferenceExpressionOrThis() const {
+ return IsValidReferenceExpression() ||
+ (IsVariableProxy() && AsVariableProxy()->is_this());
+}
+
+
+VariableProxy::VariableProxy(Zone* zone, Variable* var, int start_position,
+ int end_position)
+ : Expression(zone, start_position),
+ bit_field_(IsThisField::encode(var->is_this()) |
+ IsAssignedField::encode(false) |
+ IsResolvedField::encode(false)),
+ raw_name_(var->raw_name()),
+ end_position_(end_position) {
+ BindTo(var);
+}
+
+
+VariableProxy::VariableProxy(Zone* zone, const AstRawString* name,
+ Variable::Kind variable_kind, int start_position,
+ int end_position)
+ : Expression(zone, start_position),
+ bit_field_(IsThisField::encode(variable_kind == Variable::THIS) |
+ IsAssignedField::encode(false) |
+ IsResolvedField::encode(false)),
+ raw_name_(name),
+ end_position_(end_position) {}
+
+
+void VariableProxy::BindTo(Variable* var) {
+ DCHECK((is_this() && var->is_this()) || raw_name() == var->raw_name());
+ set_var(var);
+ set_is_resolved();
+ var->set_is_used();
+}
+
+
+void VariableProxy::AssignFeedbackVectorSlots(Isolate* isolate,
+ FeedbackVectorSpec* spec,
+ FeedbackVectorSlotCache* 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()) {
+ ZoneHashMap::Entry* entry = cache->Get(var());
+ if (entry != NULL) {
+ variable_feedback_slot_ = FeedbackVectorSlot(
+ static_cast<int>(reinterpret_cast<intptr_t>(entry->value)));
+ return;
+ }
+ }
+ variable_feedback_slot_ = spec->AddLoadICSlot();
+ if (var()->IsUnallocated()) {
+ cache->Put(var(), variable_feedback_slot_);
+ }
+ }
+}
+
+
+static void AssignVectorSlots(Expression* expr, FeedbackVectorSpec* spec,
+ FeedbackVectorSlot* 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);
+ }
+}
+
+
+void ForEachStatement::AssignFeedbackVectorSlots(
+ Isolate* isolate, FeedbackVectorSpec* spec,
+ FeedbackVectorSlotCache* cache) {
+ // TODO(adamk): for-of statements do not make use of this feedback slot.
+ // The each_slot_ should be specific to ForInStatement, and this work moved
+ // there.
+ if (IsForOfStatement()) return;
+ AssignVectorSlots(each(), spec, &each_slot_);
+}
+
+
+Assignment::Assignment(Zone* zone, Token::Value op, Expression* target,
+ Expression* value, int pos)
+ : Expression(zone, pos),
+ bit_field_(
+ IsUninitializedField::encode(false) | KeyTypeField::encode(ELEMENT) |
+ StoreModeField::encode(STANDARD_STORE) | TokenField::encode(op)),
+ target_(target),
+ value_(value),
+ binary_operation_(NULL) {}
+
+
+void Assignment::AssignFeedbackVectorSlots(Isolate* isolate,
+ FeedbackVectorSpec* spec,
+ FeedbackVectorSlotCache* cache) {
+ AssignVectorSlots(target(), spec, &slot_);
+}
+
+
+void CountOperation::AssignFeedbackVectorSlots(Isolate* isolate,
+ FeedbackVectorSpec* spec,
+ FeedbackVectorSlotCache* cache) {
+ AssignVectorSlots(expression(), spec, &slot_);
+}
+
+
+Token::Value Assignment::binary_op() const {
+ switch (op()) {
+ case Token::ASSIGN_BIT_OR: return Token::BIT_OR;
+ case Token::ASSIGN_BIT_XOR: return Token::BIT_XOR;
+ case Token::ASSIGN_BIT_AND: return Token::BIT_AND;
+ case Token::ASSIGN_SHL: return Token::SHL;
+ case Token::ASSIGN_SAR: return Token::SAR;
+ case Token::ASSIGN_SHR: return Token::SHR;
+ case Token::ASSIGN_ADD: return Token::ADD;
+ case Token::ASSIGN_SUB: return Token::SUB;
+ case Token::ASSIGN_MUL: return Token::MUL;
+ case Token::ASSIGN_DIV: return Token::DIV;
+ case Token::ASSIGN_MOD: return Token::MOD;
+ default: UNREACHABLE();
+ }
+ return Token::ILLEGAL;
+}
+
+
+bool FunctionLiteral::AllowsLazyCompilation() {
+ return scope()->AllowsLazyCompilation();
+}
+
+
+bool FunctionLiteral::AllowsLazyCompilationWithoutContext() {
+ return scope()->AllowsLazyCompilationWithoutContext();
+}
+
+
+int FunctionLiteral::start_position() const {
+ return scope()->start_position();
+}
+
+
+int FunctionLiteral::end_position() const {
+ return scope()->end_position();
+}
+
+
+LanguageMode FunctionLiteral::language_mode() const {
+ return scope()->language_mode();
+}
+
+
+bool FunctionLiteral::NeedsHomeObject(Expression* expr) {
+ if (expr == nullptr || !expr->IsFunctionLiteral()) return false;
+ DCHECK_NOT_NULL(expr->AsFunctionLiteral()->scope());
+ return expr->AsFunctionLiteral()->scope()->NeedsHomeObject();
+}
+
+
+ObjectLiteralProperty::ObjectLiteralProperty(Expression* key, Expression* value,
+ Kind kind, bool is_static,
+ bool is_computed_name)
+ : key_(key),
+ value_(value),
+ kind_(kind),
+ emit_store_(true),
+ is_static_(is_static),
+ is_computed_name_(is_computed_name) {}
+
+
+ObjectLiteralProperty::ObjectLiteralProperty(AstValueFactory* ast_value_factory,
+ Expression* key, Expression* value,
+ bool is_static,
+ bool is_computed_name)
+ : key_(key),
+ value_(value),
+ emit_store_(true),
+ is_static_(is_static),
+ is_computed_name_(is_computed_name) {
+ if (!is_computed_name &&
+ key->AsLiteral()->raw_value()->EqualsString(
+ ast_value_factory->proto_string())) {
+ kind_ = PROTOTYPE;
+ } else if (value_->AsMaterializedLiteral() != NULL) {
+ kind_ = MATERIALIZED_LITERAL;
+ } else if (value_->IsLiteral()) {
+ kind_ = CONSTANT;
+ } else {
+ kind_ = COMPUTED;
+ }
+}
+
+
+void ClassLiteral::AssignFeedbackVectorSlots(Isolate* isolate,
+ FeedbackVectorSpec* spec,
+ FeedbackVectorSlotCache* cache) {
+ // This logic that computes the number of slots needed for vector store
+ // ICs must mirror FullCodeGenerator::VisitClassLiteral.
+ if (NeedsProxySlot()) {
+ slot_ = spec->AddStoreICSlot();
+ }
+
+ for (int i = 0; i < properties()->length(); i++) {
+ ObjectLiteral::Property* property = properties()->at(i);
+ Expression* value = property->value();
+ if (FunctionLiteral::NeedsHomeObject(value)) {
+ property->SetSlot(spec->AddStoreICSlot());
+ }
+ }
+}
+
+
+bool ObjectLiteral::Property::IsCompileTimeValue() {
+ return kind_ == CONSTANT ||
+ (kind_ == MATERIALIZED_LITERAL &&
+ CompileTimeValue::IsCompileTimeValue(value_));
+}
+
+
+void ObjectLiteral::Property::set_emit_store(bool emit_store) {
+ emit_store_ = emit_store;
+}
+
+
+bool ObjectLiteral::Property::emit_store() {
+ return emit_store_;
+}
+
+
+void ObjectLiteral::AssignFeedbackVectorSlots(Isolate* isolate,
+ FeedbackVectorSpec* spec,
+ FeedbackVectorSlotCache* cache) {
+ // This logic that computes the number of slots needed for vector store
+ // ics must mirror FullCodeGenerator::VisitObjectLiteral.
+ int property_index = 0;
+ for (; property_index < properties()->length(); property_index++) {
+ ObjectLiteral::Property* property = properties()->at(property_index);
+ if (property->is_computed_name()) break;
+ if (property->IsCompileTimeValue()) continue;
+
+ Literal* key = property->key()->AsLiteral();
+ Expression* value = property->value();
+ switch (property->kind()) {
+ case ObjectLiteral::Property::CONSTANT:
+ UNREACHABLE();
+ case ObjectLiteral::Property::MATERIALIZED_LITERAL:
+ // Fall through.
+ 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 (property->emit_store()) {
+ property->SetSlot(spec->AddStoreICSlot());
+ if (FunctionLiteral::NeedsHomeObject(value)) {
+ property->SetSlot(spec->AddStoreICSlot(), 1);
+ }
+ }
+ break;
+ }
+ if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) {
+ property->SetSlot(spec->AddStoreICSlot());
+ }
+ break;
+ case ObjectLiteral::Property::PROTOTYPE:
+ break;
+ case ObjectLiteral::Property::GETTER:
+ if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) {
+ property->SetSlot(spec->AddStoreICSlot());
+ }
+ break;
+ case ObjectLiteral::Property::SETTER:
+ if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) {
+ property->SetSlot(spec->AddStoreICSlot());
+ }
+ break;
+ }
+ }
+
+ for (; property_index < properties()->length(); property_index++) {
+ ObjectLiteral::Property* property = properties()->at(property_index);
+
+ Expression* value = property->value();
+ if (property->kind() != ObjectLiteral::Property::PROTOTYPE) {
+ if (FunctionLiteral::NeedsHomeObject(value)) {
+ property->SetSlot(spec->AddStoreICSlot());
+ }
+ }
+ }
+}
+
+
+void ObjectLiteral::CalculateEmitStore(Zone* zone) {
+ const auto GETTER = ObjectLiteral::Property::GETTER;
+ const auto SETTER = ObjectLiteral::Property::SETTER;
+
+ ZoneAllocationPolicy allocator(zone);
+
+ ZoneHashMap table(Literal::Match, ZoneHashMap::kDefaultHashMapCapacity,
+ allocator);
+ for (int i = properties()->length() - 1; i >= 0; i--) {
+ ObjectLiteral::Property* property = properties()->at(i);
+ if (property->is_computed_name()) continue;
+ if (property->kind() == ObjectLiteral::Property::PROTOTYPE) continue;
+ Literal* literal = property->key()->AsLiteral();
+ DCHECK(!literal->value()->IsNull());
+
+ // If there is an existing entry do not emit a store unless the previous
+ // entry was also an accessor.
+ uint32_t hash = literal->Hash();
+ ZoneHashMap::Entry* entry = table.LookupOrInsert(literal, hash, allocator);
+ if (entry->value != NULL) {
+ auto previous_kind =
+ static_cast<ObjectLiteral::Property*>(entry->value)->kind();
+ if (!((property->kind() == GETTER && previous_kind == SETTER) ||
+ (property->kind() == SETTER && previous_kind == GETTER))) {
+ property->set_emit_store(false);
+ }
+ }
+ entry->value = property;
+ }
+}
+
+
+bool ObjectLiteral::IsBoilerplateProperty(ObjectLiteral::Property* property) {
+ return property != NULL &&
+ 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);
+
+ int position = 0;
+ // Accumulate the value in local variables and store it at the end.
+ bool is_simple = true;
+ int depth_acc = 1;
+ uint32_t max_element_index = 0;
+ uint32_t elements = 0;
+ for (int i = 0; i < properties()->length(); i++) {
+ ObjectLiteral::Property* property = properties()->at(i);
+ if (!IsBoilerplateProperty(property)) {
+ is_simple = false;
+ continue;
+ }
+
+ if (position == boilerplate_properties_ * 2) {
+ DCHECK(property->is_computed_name());
+ is_simple = false;
+ break;
+ }
+ DCHECK(!property->is_computed_name());
+
+ MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
+ if (m_literal != NULL) {
+ m_literal->BuildConstants(isolate);
+ 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);
+
+ // 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()).
+ // TODO(verwaest): Remove once we can store them inline.
+ if (FLAG_track_double_fields &&
+ (value->IsNumber() || value->IsUninitialized())) {
+ may_store_doubles_ = true;
+ }
+
+ is_simple = is_simple && !value->IsUninitialized();
+
+ // 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()
+ && Handle<String>::cast(key)->AsArrayIndex(&element_index)
+ && element_index > max_element_index) {
+ max_element_index = element_index;
+ elements++;
+ } else if (key->IsSmi()) {
+ int key_value = Smi::cast(*key)->value();
+ if (key_value > 0
+ && static_cast<uint32_t>(key_value) > max_element_index) {
+ max_element_index = key_value;
+ }
+ elements++;
+ }
+
+ // Add name, value pair to the fixed array.
+ constant_properties->set(position++, *key);
+ constant_properties->set(position++, *value);
+ }
+
+ constant_properties_ = constant_properties;
+ fast_elements_ =
+ (max_element_index <= 32) || ((2 * elements) >= max_element_index);
+ has_elements_ = elements > 0;
+ set_is_simple(is_simple);
+ set_depth(depth_acc);
+}
+
+
+void ArrayLiteral::BuildConstantElements(Isolate* isolate) {
+ if (!constant_elements_.is_null()) return;
+
+ int constants_length =
+ first_spread_index_ >= 0 ? first_spread_index_ : values()->length();
+
+ // Allocate a fixed array to hold all the object literals.
+ Handle<JSArray> array = isolate->factory()->NewJSArray(
+ FAST_HOLEY_SMI_ELEMENTS, constants_length, constants_length,
+ Strength::WEAK, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
+
+ // Fill in the literals.
+ bool is_simple = (first_spread_index_ < 0);
+ int depth_acc = 1;
+ bool is_holey = false;
+ 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->BuildConstants(isolate);
+ if (m_literal->depth() + 1 > depth_acc) {
+ depth_acc = m_literal->depth() + 1;
+ }
+ }
+
+ // New handle scope here, needs to be after BuildContants().
+ HandleScope scope(isolate);
+ Handle<Object> boilerplate_value = GetBoilerplateValue(element, isolate);
+ if (boilerplate_value->IsTheHole()) {
+ is_holey = true;
+ continue;
+ }
+
+ if (boilerplate_value->IsUninitialized()) {
+ boilerplate_value = handle(Smi::FromInt(0), isolate);
+ is_simple = false;
+ }
+
+ JSObject::AddDataElement(array, array_index, boilerplate_value, NONE)
+ .Assert();
+ }
+
+ JSObject::ValidateElements(array);
+ Handle<FixedArrayBase> element_values(array->elements());
+
+ // 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 &&
+ array->HasFastSmiOrObjectElements()) {
+ element_values->set_map(isolate->heap()->fixed_cow_array_map());
+ }
+
+ // 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);
+
+ ElementsKind kind = array->GetElementsKind();
+ kind = is_holey ? GetHoleyElementsKind(kind) : GetPackedElementsKind(kind);
+
+ literals->set(0, Smi::FromInt(kind));
+ literals->set(1, *element_values);
+
+ constant_elements_ = literals;
+ set_is_simple(is_simple);
+ set_depth(depth_acc);
+}
+
+
+void ArrayLiteral::AssignFeedbackVectorSlots(Isolate* isolate,
+ FeedbackVectorSpec* spec,
+ FeedbackVectorSlotCache* cache) {
+ // This logic that computes the number of slots needed for vector store
+ // ics must mirror FullCodeGenerator::VisitArrayLiteral.
+ int array_index = 0;
+ for (; array_index < values()->length(); array_index++) {
+ Expression* subexpr = values()->at(array_index);
+ if (subexpr->IsSpread()) break;
+ if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
+
+ // We'll reuse the same literal slot for all of the non-constant
+ // subexpressions that use a keyed store IC.
+ literal_slot_ = spec->AddKeyedStoreICSlot();
+ return;
+ }
+}
+
+
+Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression,
+ Isolate* isolate) {
+ if (expression->IsLiteral()) {
+ return expression->AsLiteral()->value();
+ }
+ if (CompileTimeValue::IsCompileTimeValue(expression)) {
+ return CompileTimeValue::GetValue(isolate, expression);
+ }
+ return isolate->factory()->uninitialized_value();
+}
+
+
+void MaterializedLiteral::BuildConstants(Isolate* isolate) {
+ if (IsArrayLiteral()) {
+ return AsArrayLiteral()->BuildConstantElements(isolate);
+ }
+ if (IsObjectLiteral()) {
+ return AsObjectLiteral()->BuildConstantProperties(isolate);
+ }
+ DCHECK(IsRegExpLiteral());
+ DCHECK(depth() >= 1); // Depth should be initialized.
+}
+
+
+void UnaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
+ // TODO(olivf) If this Operation is used in a test context, then the
+ // expression has a ToBoolean stub and we want to collect the type
+ // information. However the GraphBuilder expects it to be on the instruction
+ // corresponding to the TestContext, therefore we have to store it here and
+ // not on the operand.
+ set_to_boolean_types(oracle->ToBooleanTypes(expression()->test_id()));
+}
+
+
+void BinaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
+ // TODO(olivf) If this Operation is used in a test context, then the right
+ // hand side has a ToBoolean stub and we want to collect the type information.
+ // However the GraphBuilder expects it to be on the instruction corresponding
+ // to the TestContext, therefore we have to store it here and not on the
+ // right hand operand.
+ set_to_boolean_types(oracle->ToBooleanTypes(right()->test_id()));
+}
+
+
+static bool IsTypeof(Expression* expr) {
+ UnaryOperation* maybe_unary = expr->AsUnaryOperation();
+ return maybe_unary != NULL && maybe_unary->op() == Token::TYPEOF;
+}
+
+
+// Check for the pattern: typeof <expression> equals <string literal>.
+static bool MatchLiteralCompareTypeof(Expression* left,
+ Token::Value op,
+ Expression* right,
+ Expression** expr,
+ Handle<String>* check) {
+ if (IsTypeof(left) && right->IsStringLiteral() && Token::IsEqualityOp(op)) {
+ *expr = left->AsUnaryOperation()->expression();
+ *check = Handle<String>::cast(right->AsLiteral()->value());
+ return true;
+ }
+ return false;
+}
+
+
+bool CompareOperation::IsLiteralCompareTypeof(Expression** expr,
+ Handle<String>* check) {
+ return MatchLiteralCompareTypeof(left_, op_, right_, expr, check) ||
+ MatchLiteralCompareTypeof(right_, op_, left_, expr, check);
+}
+
+
+static bool IsVoidOfLiteral(Expression* expr) {
+ UnaryOperation* maybe_unary = expr->AsUnaryOperation();
+ return maybe_unary != NULL &&
+ maybe_unary->op() == Token::VOID &&
+ maybe_unary->expression()->IsLiteral();
+}
+
+
+// Check for the pattern: void <literal> equals <expression> or
+// undefined equals <expression>
+static bool MatchLiteralCompareUndefined(Expression* left,
+ Token::Value op,
+ Expression* right,
+ Expression** expr,
+ Isolate* isolate) {
+ if (IsVoidOfLiteral(left) && Token::IsEqualityOp(op)) {
+ *expr = right;
+ return true;
+ }
+ if (left->IsUndefinedLiteral(isolate) && Token::IsEqualityOp(op)) {
+ *expr = right;
+ return true;
+ }
+ return false;
+}
+
+
+bool CompareOperation::IsLiteralCompareUndefined(
+ Expression** expr, Isolate* isolate) {
+ return MatchLiteralCompareUndefined(left_, op_, right_, expr, isolate) ||
+ MatchLiteralCompareUndefined(right_, op_, left_, expr, isolate);
+}
+
+
+// Check for the pattern: null equals <expression>
+static bool MatchLiteralCompareNull(Expression* left,
+ Token::Value op,
+ Expression* right,
+ Expression** expr) {
+ if (left->IsNullLiteral() && Token::IsEqualityOp(op)) {
+ *expr = right;
+ return true;
+ }
+ return false;
+}
+
+
+bool CompareOperation::IsLiteralCompareNull(Expression** expr) {
+ return MatchLiteralCompareNull(left_, op_, right_, expr) ||
+ MatchLiteralCompareNull(right_, op_, left_, expr);
+}
+
+
+// ----------------------------------------------------------------------------
+// Inlining support
+
+bool Declaration::IsInlineable() const {
+ return proxy()->var()->IsStackAllocated();
+}
+
+bool FunctionDeclaration::IsInlineable() const {
+ return false;
+}
+
+
+// ----------------------------------------------------------------------------
+// Recording of type feedback
+
+// TODO(rossberg): all RecordTypeFeedback functions should disappear
+// once we use the common type field in the AST consistently.
+
+void Expression::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
+ set_to_boolean_types(oracle->ToBooleanTypes(test_id()));
+}
+
+
+bool Call::IsUsingCallFeedbackICSlot(Isolate* isolate) const {
+ CallType call_type = GetCallType(isolate);
+ if (call_type == POSSIBLY_EVAL_CALL) {
+ return false;
+ }
+ return true;
+}
+
+
+bool Call::IsUsingCallFeedbackSlot(Isolate* isolate) const {
+ // SuperConstructorCall uses a CallConstructStub, which wants
+ // a Slot, in addition to any IC slots requested elsewhere.
+ return GetCallType(isolate) == SUPER_CALL;
+}
+
+
+void Call::AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
+ FeedbackVectorSlotCache* cache) {
+ if (IsUsingCallFeedbackICSlot(isolate)) {
+ ic_slot_ = spec->AddCallICSlot();
+ }
+ if (IsUsingCallFeedbackSlot(isolate)) {
+ stub_slot_ = spec->AddGeneralSlot();
+ }
+}
+
+
+Call::CallType Call::GetCallType(Isolate* isolate) const {
+ VariableProxy* proxy = expression()->AsVariableProxy();
+ if (proxy != NULL) {
+ if (proxy->var()->is_possibly_eval(isolate)) {
+ return POSSIBLY_EVAL_CALL;
+ } else if (proxy->var()->IsUnallocatedOrGlobalSlot()) {
+ return GLOBAL_CALL;
+ } else if (proxy->var()->IsLookupSlot()) {
+ return LOOKUP_SLOT_CALL;
+ }
+ }
+
+ if (expression()->IsSuperCallReference()) return SUPER_CALL;
+
+ Property* property = expression()->AsProperty();
+ if (property != nullptr) {
+ bool is_super = property->IsSuperAccess();
+ if (property->key()->IsPropertyName()) {
+ return is_super ? NAMED_SUPER_PROPERTY_CALL : NAMED_PROPERTY_CALL;
+ } else {
+ return is_super ? KEYED_SUPER_PROPERTY_CALL : KEYED_PROPERTY_CALL;
+ }
+ }
+
+ return OTHER_CALL;
+}
+
+
+// ----------------------------------------------------------------------------
+// Implementation of AstVisitor
+
+void AstVisitor::VisitDeclarations(ZoneList<Declaration*>* declarations) {
+ for (int i = 0; i < declarations->length(); i++) {
+ Visit(declarations->at(i));
+ }
+}
+
+
+void AstVisitor::VisitStatements(ZoneList<Statement*>* statements) {
+ for (int i = 0; i < statements->length(); i++) {
+ Statement* stmt = statements->at(i);
+ Visit(stmt);
+ if (stmt->IsJump()) break;
+ }
+}
+
+
+void AstVisitor::VisitExpressions(ZoneList<Expression*>* expressions) {
+ for (int i = 0; i < expressions->length(); i++) {
+ // The variable statement visiting code may pass NULL expressions
+ // to this code. Maybe this should be handled by introducing an
+ // undefined expression or literal? Revisit this code if this
+ // changes
+ Expression* expression = expressions->at(i);
+ if (expression != NULL) Visit(expression);
+ }
+}
+
+
+CaseClause::CaseClause(Zone* zone, Expression* label,
+ ZoneList<Statement*>* statements, int pos)
+ : Expression(zone, pos),
+ label_(label),
+ statements_(statements),
+ compare_type_(Type::None(zone)) {}
+
+
+uint32_t Literal::Hash() {
+ return raw_value()->IsString()
+ ? raw_value()->AsString()->hash()
+ : ComputeLongHash(double_to_uint64(raw_value()->AsNumber()));
+}
+
+
+// static
+bool Literal::Match(void* literal1, void* literal2) {
+ const AstValue* x = static_cast<Literal*>(literal1)->raw_value();
+ const AstValue* y = static_cast<Literal*>(literal2)->raw_value();
+ return (x->IsString() && y->IsString() && x->AsString() == y->AsString()) ||
+ (x->IsNumber() && y->IsNumber() && x->AsNumber() == y->AsNumber());
+}
+
+
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/ast/ast.h b/deps/v8/src/ast/ast.h
new file mode 100644
index 0000000000..7f00955a64
--- /dev/null
+++ b/deps/v8/src/ast/ast.h
@@ -0,0 +1,3535 @@
+// Copyright 2012 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_H_
+#define V8_AST_AST_H_
+
+#include "src/assembler.h"
+#include "src/ast/ast-value-factory.h"
+#include "src/ast/modules.h"
+#include "src/ast/variables.h"
+#include "src/bailout-reason.h"
+#include "src/base/flags.h"
+#include "src/base/smart-pointers.h"
+#include "src/factory.h"
+#include "src/isolate.h"
+#include "src/list.h"
+#include "src/parsing/token.h"
+#include "src/runtime/runtime.h"
+#include "src/small-pointer-list.h"
+#include "src/types.h"
+#include "src/utils.h"
+
+namespace v8 {
+namespace internal {
+
+// The abstract syntax tree is an intermediate, light-weight
+// representation of the parsed JavaScript code suitable for
+// compilation to native code.
+
+// Nodes are allocated in a separate zone, which allows faster
+// allocation and constant-time deallocation of the entire syntax
+// tree.
+
+
+// ----------------------------------------------------------------------------
+// Nodes of the abstract syntax tree. Only concrete classes are
+// enumerated here.
+
+#define DECLARATION_NODE_LIST(V) \
+ V(VariableDeclaration) \
+ V(FunctionDeclaration) \
+ V(ImportDeclaration) \
+ V(ExportDeclaration)
+
+#define STATEMENT_NODE_LIST(V) \
+ V(Block) \
+ V(ExpressionStatement) \
+ V(EmptyStatement) \
+ V(SloppyBlockFunctionStatement) \
+ V(IfStatement) \
+ V(ContinueStatement) \
+ V(BreakStatement) \
+ V(ReturnStatement) \
+ V(WithStatement) \
+ V(SwitchStatement) \
+ V(DoWhileStatement) \
+ V(WhileStatement) \
+ V(ForStatement) \
+ V(ForInStatement) \
+ V(ForOfStatement) \
+ V(TryCatchStatement) \
+ V(TryFinallyStatement) \
+ V(DebuggerStatement)
+
+#define EXPRESSION_NODE_LIST(V) \
+ V(FunctionLiteral) \
+ V(ClassLiteral) \
+ V(NativeFunctionLiteral) \
+ V(Conditional) \
+ V(VariableProxy) \
+ V(Literal) \
+ V(RegExpLiteral) \
+ V(ObjectLiteral) \
+ V(ArrayLiteral) \
+ V(Assignment) \
+ V(Yield) \
+ V(Throw) \
+ V(Property) \
+ V(Call) \
+ V(CallNew) \
+ V(CallRuntime) \
+ V(UnaryOperation) \
+ V(CountOperation) \
+ V(BinaryOperation) \
+ V(CompareOperation) \
+ V(Spread) \
+ V(ThisFunction) \
+ V(SuperPropertyReference) \
+ V(SuperCallReference) \
+ V(CaseClause) \
+ V(EmptyParentheses) \
+ V(DoExpression) \
+ V(RewritableAssignmentExpression)
+
+#define AST_NODE_LIST(V) \
+ DECLARATION_NODE_LIST(V) \
+ STATEMENT_NODE_LIST(V) \
+ EXPRESSION_NODE_LIST(V)
+
+// Forward declarations
+class AstNodeFactory;
+class AstVisitor;
+class Declaration;
+class Module;
+class BreakableStatement;
+class Expression;
+class IterationStatement;
+class MaterializedLiteral;
+class Statement;
+class TypeFeedbackOracle;
+
+#define DEF_FORWARD_DECLARATION(type) class type;
+AST_NODE_LIST(DEF_FORWARD_DECLARATION)
+#undef DEF_FORWARD_DECLARATION
+
+
+// Typedef only introduced to avoid unreadable code.
+typedef ZoneList<Handle<String>> ZoneStringList;
+typedef ZoneList<Handle<Object>> ZoneObjectList;
+
+
+#define DECLARE_NODE_TYPE(type) \
+ void Accept(AstVisitor* v) override; \
+ AstNode::NodeType node_type() const final { return AstNode::k##type; } \
+ friend class AstNodeFactory;
+
+
+class FeedbackVectorSlotCache {
+ public:
+ explicit FeedbackVectorSlotCache(Zone* zone)
+ : zone_(zone),
+ hash_map_(HashMap::PointersMatch, ZoneHashMap::kDefaultHashMapCapacity,
+ ZoneAllocationPolicy(zone)) {}
+
+ void Put(Variable* variable, FeedbackVectorSlot slot) {
+ ZoneHashMap::Entry* entry = hash_map_.LookupOrInsert(
+ variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone_));
+ entry->value = reinterpret_cast<void*>(slot.ToInt());
+ }
+
+ ZoneHashMap::Entry* Get(Variable* variable) const {
+ return hash_map_.Lookup(variable, ComputePointerHash(variable));
+ }
+
+ private:
+ Zone* zone_;
+ ZoneHashMap hash_map_;
+};
+
+
+class AstProperties final BASE_EMBEDDED {
+ public:
+ enum Flag {
+ kNoFlags = 0,
+ kDontSelfOptimize = 1 << 0,
+ kDontCrankshaft = 1 << 1
+ };
+
+ typedef base::Flags<Flag> Flags;
+
+ explicit AstProperties(Zone* zone) : node_count_(0), spec_(zone) {}
+
+ Flags& flags() { return flags_; }
+ Flags flags() const { return flags_; }
+ int node_count() { return node_count_; }
+ void add_node_count(int count) { node_count_ += count; }
+
+ const FeedbackVectorSpec* get_spec() const { return &spec_; }
+ FeedbackVectorSpec* get_spec() { return &spec_; }
+
+ private:
+ Flags flags_;
+ int node_count_;
+ FeedbackVectorSpec spec_;
+};
+
+DEFINE_OPERATORS_FOR_FLAGS(AstProperties::Flags)
+
+
+class AstNode: public ZoneObject {
+ public:
+#define DECLARE_TYPE_ENUM(type) k##type,
+ enum NodeType {
+ AST_NODE_LIST(DECLARE_TYPE_ENUM)
+ kInvalid = -1
+ };
+#undef DECLARE_TYPE_ENUM
+
+ void* operator new(size_t size, Zone* zone) { return zone->New(size); }
+
+ explicit AstNode(int position): position_(position) {}
+ virtual ~AstNode() {}
+
+ virtual void Accept(AstVisitor* v) = 0;
+ virtual NodeType node_type() const = 0;
+ int position() const { return position_; }
+
+ // Type testing & conversion functions overridden by concrete subclasses.
+#define DECLARE_NODE_FUNCTIONS(type) \
+ bool Is##type() const { return node_type() == AstNode::k##type; } \
+ type* As##type() { \
+ return Is##type() ? reinterpret_cast<type*>(this) : NULL; \
+ } \
+ const type* As##type() const { \
+ return Is##type() ? reinterpret_cast<const type*>(this) : NULL; \
+ }
+ AST_NODE_LIST(DECLARE_NODE_FUNCTIONS)
+#undef DECLARE_NODE_FUNCTIONS
+
+ virtual BreakableStatement* AsBreakableStatement() { return NULL; }
+ virtual IterationStatement* AsIterationStatement() { return NULL; }
+ virtual MaterializedLiteral* AsMaterializedLiteral() { return NULL; }
+
+ // The interface for feedback slots, with default no-op implementations for
+ // node types which don't actually have this. Note that this is conceptually
+ // not really nice, but multiple inheritance would introduce yet another
+ // vtable entry per node, something we don't want for space reasons.
+ virtual void AssignFeedbackVectorSlots(Isolate* isolate,
+ FeedbackVectorSpec* spec,
+ FeedbackVectorSlotCache* cache) {}
+
+ private:
+ // Hidden to prevent accidental usage. It would have to load the
+ // current zone from the TLS.
+ void* operator new(size_t size);
+
+ friend class CaseClause; // Generates AST IDs.
+
+ int position_;
+};
+
+
+class Statement : public AstNode {
+ public:
+ explicit Statement(Zone* zone, int position) : AstNode(position) {}
+
+ bool IsEmpty() { return AsEmptyStatement() != NULL; }
+ virtual bool IsJump() const { return false; }
+ virtual void MarkTail() {}
+};
+
+
+class SmallMapList final {
+ public:
+ SmallMapList() {}
+ SmallMapList(int capacity, Zone* zone) : list_(capacity, zone) {}
+
+ void Reserve(int capacity, Zone* zone) { list_.Reserve(capacity, zone); }
+ void Clear() { list_.Clear(); }
+ void Sort() { list_.Sort(); }
+
+ bool is_empty() const { return list_.is_empty(); }
+ int length() const { return list_.length(); }
+
+ void AddMapIfMissing(Handle<Map> map, Zone* zone) {
+ if (!Map::TryUpdate(map).ToHandle(&map)) return;
+ for (int i = 0; i < length(); ++i) {
+ if (at(i).is_identical_to(map)) return;
+ }
+ Add(map, zone);
+ }
+
+ void FilterForPossibleTransitions(Map* root_map) {
+ for (int i = list_.length() - 1; i >= 0; i--) {
+ if (at(i)->FindRootMap() != root_map) {
+ list_.RemoveElement(list_.at(i));
+ }
+ }
+ }
+
+ void Add(Handle<Map> handle, Zone* zone) {
+ list_.Add(handle.location(), zone);
+ }
+
+ Handle<Map> at(int i) const {
+ return Handle<Map>(list_.at(i));
+ }
+
+ Handle<Map> first() const { return at(0); }
+ Handle<Map> last() const { return at(length() - 1); }
+
+ private:
+ // The list stores pointers to Map*, that is Map**, so it's GC safe.
+ SmallPointerList<Map*> list_;
+
+ DISALLOW_COPY_AND_ASSIGN(SmallMapList);
+};
+
+
+class Expression : public AstNode {
+ public:
+ enum Context {
+ // Not assigned a context yet, or else will not be visited during
+ // code generation.
+ kUninitialized,
+ // Evaluated for its side effects.
+ kEffect,
+ // Evaluated for its value (and side effects).
+ kValue,
+ // Evaluated for control flow (and side effects).
+ kTest
+ };
+
+ // Mark this expression as being in tail position.
+ virtual void MarkTail() {}
+
+ // True iff the expression is a valid reference expression.
+ virtual bool IsValidReferenceExpression() const { return false; }
+
+ // Helpers for ToBoolean conversion.
+ virtual bool ToBooleanIsTrue() const { return false; }
+ virtual bool ToBooleanIsFalse() const { return false; }
+
+ // Symbols that cannot be parsed as array indices are considered property
+ // names. We do not treat symbols that can be array indexes as property
+ // names because [] for string objects is handled only by keyed ICs.
+ virtual bool IsPropertyName() const { return false; }
+
+ // True iff the expression is a literal represented as a smi.
+ bool IsSmiLiteral() const;
+
+ // True iff the expression is a string literal.
+ bool IsStringLiteral() const;
+
+ // True iff the expression is the null literal.
+ bool IsNullLiteral() const;
+
+ // True if we can prove that the expression is the undefined literal.
+ bool IsUndefinedLiteral(Isolate* isolate) const;
+
+ // True iff the expression is a valid target for an assignment.
+ bool IsValidReferenceExpressionOrThis() const;
+
+ // Expression type bounds
+ Bounds bounds() const { return bounds_; }
+ void set_bounds(Bounds bounds) { bounds_ = bounds; }
+
+ // Type feedback information for assignments and properties.
+ virtual bool IsMonomorphic() {
+ UNREACHABLE();
+ return false;
+ }
+ virtual SmallMapList* GetReceiverTypes() {
+ UNREACHABLE();
+ return NULL;
+ }
+ virtual KeyedAccessStoreMode GetStoreMode() const {
+ UNREACHABLE();
+ return STANDARD_STORE;
+ }
+ virtual IcCheckType GetKeyType() const {
+ UNREACHABLE();
+ return ELEMENT;
+ }
+
+ // TODO(rossberg): this should move to its own AST node eventually.
+ virtual void RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle);
+ uint16_t to_boolean_types() const {
+ return ToBooleanTypesField::decode(bit_field_);
+ }
+
+ void set_base_id(int id) { base_id_ = id; }
+ static int num_ids() { return parent_num_ids() + 2; }
+ BailoutId id() const { return BailoutId(local_id(0)); }
+ TypeFeedbackId test_id() const { return TypeFeedbackId(local_id(1)); }
+
+ // Parenthesized expressions in the form `( Expression )`.
+ void set_is_parenthesized() {
+ bit_field_ = ParenthesizedField::update(bit_field_, true);
+ }
+ bool is_parenthesized() const {
+ return ParenthesizedField::decode(bit_field_);
+ }
+
+ protected:
+ Expression(Zone* zone, int pos)
+ : AstNode(pos),
+ base_id_(BailoutId::None().ToInt()),
+ bounds_(Bounds::Unbounded()),
+ bit_field_(0) {}
+ static int parent_num_ids() { return 0; }
+ void set_to_boolean_types(uint16_t types) {
+ bit_field_ = ToBooleanTypesField::update(bit_field_, types);
+ }
+
+ int base_id() const {
+ DCHECK(!BailoutId(base_id_).IsNone());
+ return base_id_;
+ }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ int base_id_;
+ Bounds bounds_;
+ class ToBooleanTypesField : public BitField16<uint16_t, 0, 9> {};
+ class ParenthesizedField
+ : public BitField16<bool, ToBooleanTypesField::kNext, 1> {};
+ uint16_t bit_field_;
+ // Ends with 16-bit field; deriving classes in turn begin with
+ // 16-bit fields for optimum packing efficiency.
+};
+
+
+class BreakableStatement : public Statement {
+ public:
+ enum BreakableType {
+ TARGET_FOR_ANONYMOUS,
+ TARGET_FOR_NAMED_ONLY
+ };
+
+ // The labels associated with this statement. May be NULL;
+ // if it is != NULL, guaranteed to contain at least one entry.
+ ZoneList<const AstRawString*>* labels() const { return labels_; }
+
+ // Type testing & conversion.
+ BreakableStatement* AsBreakableStatement() final { return this; }
+
+ // Code generation
+ Label* break_target() { return &break_target_; }
+
+ // Testers.
+ bool is_target_for_anonymous() const {
+ return breakable_type_ == TARGET_FOR_ANONYMOUS;
+ }
+
+ void set_base_id(int id) { base_id_ = id; }
+ static int num_ids() { return parent_num_ids() + 2; }
+ BailoutId EntryId() const { return BailoutId(local_id(0)); }
+ BailoutId ExitId() const { return BailoutId(local_id(1)); }
+
+ protected:
+ BreakableStatement(Zone* zone, ZoneList<const AstRawString*>* labels,
+ BreakableType breakable_type, int position)
+ : Statement(zone, position),
+ labels_(labels),
+ breakable_type_(breakable_type),
+ base_id_(BailoutId::None().ToInt()) {
+ DCHECK(labels == NULL || labels->length() > 0);
+ }
+ static int parent_num_ids() { return 0; }
+
+ int base_id() const {
+ DCHECK(!BailoutId(base_id_).IsNone());
+ return base_id_;
+ }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ ZoneList<const AstRawString*>* labels_;
+ BreakableType breakable_type_;
+ Label break_target_;
+ int base_id_;
+};
+
+
+class Block final : public BreakableStatement {
+ public:
+ DECLARE_NODE_TYPE(Block)
+
+ ZoneList<Statement*>* statements() { return &statements_; }
+ bool ignore_completion_value() const { return ignore_completion_value_; }
+
+ static int num_ids() { return parent_num_ids() + 1; }
+ BailoutId DeclsId() const { return BailoutId(local_id(0)); }
+
+ bool IsJump() const override {
+ return !statements_.is_empty() && statements_.last()->IsJump()
+ && labels() == NULL; // Good enough as an approximation...
+ }
+
+ void MarkTail() override {
+ if (!statements_.is_empty()) statements_.last()->MarkTail();
+ }
+
+ Scope* scope() const { return scope_; }
+ void set_scope(Scope* scope) { scope_ = scope; }
+
+ protected:
+ Block(Zone* zone, ZoneList<const AstRawString*>* labels, int capacity,
+ bool ignore_completion_value, int pos)
+ : BreakableStatement(zone, labels, TARGET_FOR_NAMED_ONLY, pos),
+ statements_(capacity, zone),
+ ignore_completion_value_(ignore_completion_value),
+ scope_(NULL) {}
+ static int parent_num_ids() { return BreakableStatement::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ ZoneList<Statement*> statements_;
+ bool ignore_completion_value_;
+ Scope* scope_;
+};
+
+
+class DoExpression final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(DoExpression)
+
+ Block* block() { return block_; }
+ void set_block(Block* b) { block_ = b; }
+ VariableProxy* result() { return result_; }
+ void set_result(VariableProxy* v) { result_ = v; }
+
+ void MarkTail() override { block_->MarkTail(); }
+
+ protected:
+ DoExpression(Zone* zone, Block* block, VariableProxy* result, int pos)
+ : Expression(zone, pos), block_(block), result_(result) {
+ DCHECK_NOT_NULL(block_);
+ DCHECK_NOT_NULL(result_);
+ }
+ static int parent_num_ids() { return Expression::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ Block* block_;
+ VariableProxy* result_;
+};
+
+
+class Declaration : public AstNode {
+ public:
+ VariableProxy* proxy() const { return proxy_; }
+ VariableMode mode() const { return mode_; }
+ Scope* scope() const { return scope_; }
+ virtual InitializationFlag initialization() const = 0;
+ virtual bool IsInlineable() const;
+
+ protected:
+ Declaration(Zone* zone, VariableProxy* proxy, VariableMode mode, Scope* scope,
+ int pos)
+ : AstNode(pos), mode_(mode), proxy_(proxy), scope_(scope) {
+ DCHECK(IsDeclaredVariableMode(mode));
+ }
+
+ private:
+ VariableMode mode_;
+ VariableProxy* proxy_;
+
+ // Nested scope from which the declaration originated.
+ Scope* scope_;
+};
+
+
+class VariableDeclaration final : public Declaration {
+ public:
+ DECLARE_NODE_TYPE(VariableDeclaration)
+
+ InitializationFlag initialization() const override {
+ return mode() == VAR ? kCreatedInitialized : kNeedsInitialization;
+ }
+
+ bool is_class_declaration() const { return is_class_declaration_; }
+
+ // VariableDeclarations can be grouped into consecutive declaration
+ // groups. Each VariableDeclaration is associated with the start position of
+ // the group it belongs to. The positions are used for strong mode scope
+ // checks for classes and functions.
+ int declaration_group_start() const { return declaration_group_start_; }
+
+ protected:
+ VariableDeclaration(Zone* zone, VariableProxy* proxy, VariableMode mode,
+ Scope* scope, int pos, bool is_class_declaration = false,
+ int declaration_group_start = -1)
+ : Declaration(zone, proxy, mode, scope, pos),
+ is_class_declaration_(is_class_declaration),
+ declaration_group_start_(declaration_group_start) {}
+
+ bool is_class_declaration_;
+ int declaration_group_start_;
+};
+
+
+class FunctionDeclaration final : public Declaration {
+ public:
+ DECLARE_NODE_TYPE(FunctionDeclaration)
+
+ FunctionLiteral* fun() const { return fun_; }
+ void set_fun(FunctionLiteral* f) { fun_ = f; }
+ InitializationFlag initialization() const override {
+ return kCreatedInitialized;
+ }
+ bool IsInlineable() const override;
+
+ protected:
+ FunctionDeclaration(Zone* zone,
+ VariableProxy* proxy,
+ VariableMode mode,
+ FunctionLiteral* fun,
+ Scope* scope,
+ int pos)
+ : Declaration(zone, proxy, mode, scope, pos),
+ fun_(fun) {
+ DCHECK(mode == VAR || mode == LET || mode == CONST);
+ DCHECK(fun != NULL);
+ }
+
+ private:
+ FunctionLiteral* fun_;
+};
+
+
+class ImportDeclaration final : public Declaration {
+ public:
+ DECLARE_NODE_TYPE(ImportDeclaration)
+
+ const AstRawString* import_name() const { return import_name_; }
+ const AstRawString* module_specifier() const { return module_specifier_; }
+ void set_module_specifier(const AstRawString* module_specifier) {
+ DCHECK(module_specifier_ == NULL);
+ module_specifier_ = module_specifier;
+ }
+ InitializationFlag initialization() const override {
+ return kNeedsInitialization;
+ }
+
+ protected:
+ ImportDeclaration(Zone* zone, VariableProxy* proxy,
+ const AstRawString* import_name,
+ const AstRawString* module_specifier, Scope* scope, int pos)
+ : Declaration(zone, proxy, IMPORT, scope, pos),
+ import_name_(import_name),
+ module_specifier_(module_specifier) {}
+
+ private:
+ const AstRawString* import_name_;
+ const AstRawString* module_specifier_;
+};
+
+
+class ExportDeclaration final : public Declaration {
+ public:
+ DECLARE_NODE_TYPE(ExportDeclaration)
+
+ InitializationFlag initialization() const override {
+ return kCreatedInitialized;
+ }
+
+ protected:
+ ExportDeclaration(Zone* zone, VariableProxy* proxy, Scope* scope, int pos)
+ : Declaration(zone, proxy, LET, scope, pos) {}
+};
+
+
+class Module : public AstNode {
+ public:
+ ModuleDescriptor* descriptor() const { return descriptor_; }
+ Block* body() const { return body_; }
+
+ protected:
+ Module(Zone* zone, int pos)
+ : AstNode(pos), descriptor_(ModuleDescriptor::New(zone)), body_(NULL) {}
+ Module(Zone* zone, ModuleDescriptor* descriptor, int pos, Block* body = NULL)
+ : AstNode(pos), descriptor_(descriptor), body_(body) {}
+
+ private:
+ ModuleDescriptor* descriptor_;
+ Block* body_;
+};
+
+
+class IterationStatement : public BreakableStatement {
+ public:
+ // Type testing & conversion.
+ IterationStatement* AsIterationStatement() final { return this; }
+
+ Statement* body() const { return body_; }
+ void set_body(Statement* s) { body_ = s; }
+
+ static int num_ids() { return parent_num_ids() + 1; }
+ BailoutId OsrEntryId() const { return BailoutId(local_id(0)); }
+ virtual BailoutId ContinueId() const = 0;
+ virtual BailoutId StackCheckId() const = 0;
+
+ // Code generation
+ Label* continue_target() { return &continue_target_; }
+
+ protected:
+ IterationStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
+ : BreakableStatement(zone, labels, TARGET_FOR_ANONYMOUS, pos),
+ body_(NULL) {}
+ static int parent_num_ids() { return BreakableStatement::num_ids(); }
+ void Initialize(Statement* body) { body_ = body; }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ Statement* body_;
+ Label continue_target_;
+};
+
+
+class DoWhileStatement final : public IterationStatement {
+ public:
+ DECLARE_NODE_TYPE(DoWhileStatement)
+
+ void Initialize(Expression* cond, Statement* body) {
+ IterationStatement::Initialize(body);
+ cond_ = cond;
+ }
+
+ Expression* cond() const { return cond_; }
+ void set_cond(Expression* e) { cond_ = e; }
+
+ static int num_ids() { return parent_num_ids() + 2; }
+ BailoutId ContinueId() const override { return BailoutId(local_id(0)); }
+ BailoutId StackCheckId() const override { return BackEdgeId(); }
+ BailoutId BackEdgeId() const { return BailoutId(local_id(1)); }
+
+ protected:
+ DoWhileStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
+ : IterationStatement(zone, labels, pos), cond_(NULL) {}
+ static int parent_num_ids() { return IterationStatement::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ Expression* cond_;
+};
+
+
+class WhileStatement final : public IterationStatement {
+ public:
+ DECLARE_NODE_TYPE(WhileStatement)
+
+ void Initialize(Expression* cond, Statement* body) {
+ IterationStatement::Initialize(body);
+ cond_ = cond;
+ }
+
+ Expression* cond() const { return cond_; }
+ void set_cond(Expression* e) { cond_ = e; }
+
+ static int num_ids() { return parent_num_ids() + 1; }
+ BailoutId ContinueId() const override { return EntryId(); }
+ BailoutId StackCheckId() const override { return BodyId(); }
+ BailoutId BodyId() const { return BailoutId(local_id(0)); }
+
+ protected:
+ WhileStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
+ : IterationStatement(zone, labels, pos), cond_(NULL) {}
+ static int parent_num_ids() { return IterationStatement::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ Expression* cond_;
+};
+
+
+class ForStatement final : public IterationStatement {
+ public:
+ DECLARE_NODE_TYPE(ForStatement)
+
+ void Initialize(Statement* init,
+ Expression* cond,
+ Statement* next,
+ Statement* body) {
+ IterationStatement::Initialize(body);
+ init_ = init;
+ cond_ = cond;
+ next_ = next;
+ }
+
+ Statement* init() const { return init_; }
+ Expression* cond() const { return cond_; }
+ Statement* next() const { return next_; }
+
+ void set_init(Statement* s) { init_ = s; }
+ void set_cond(Expression* e) { cond_ = e; }
+ void set_next(Statement* s) { next_ = s; }
+
+ static int num_ids() { return parent_num_ids() + 2; }
+ BailoutId ContinueId() const override { return BailoutId(local_id(0)); }
+ BailoutId StackCheckId() const override { return BodyId(); }
+ BailoutId BodyId() const { return BailoutId(local_id(1)); }
+
+ protected:
+ ForStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
+ : IterationStatement(zone, labels, pos),
+ init_(NULL),
+ cond_(NULL),
+ next_(NULL) {}
+ static int parent_num_ids() { return IterationStatement::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ Statement* init_;
+ Expression* cond_;
+ Statement* next_;
+};
+
+
+class ForEachStatement : public IterationStatement {
+ public:
+ enum VisitMode {
+ ENUMERATE, // for (each in subject) body;
+ ITERATE // for (each of subject) body;
+ };
+
+ void Initialize(Expression* each, Expression* subject, Statement* body) {
+ IterationStatement::Initialize(body);
+ each_ = each;
+ subject_ = subject;
+ }
+
+ Expression* each() const { return each_; }
+ Expression* subject() const { return subject_; }
+
+ void set_each(Expression* e) { each_ = e; }
+ void set_subject(Expression* e) { subject_ = e; }
+
+ void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
+ FeedbackVectorSlotCache* cache) override;
+ FeedbackVectorSlot EachFeedbackSlot() const { return each_slot_; }
+
+ protected:
+ ForEachStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
+ : IterationStatement(zone, labels, pos), each_(NULL), subject_(NULL) {}
+
+ private:
+ Expression* each_;
+ Expression* subject_;
+ FeedbackVectorSlot each_slot_;
+};
+
+
+class ForInStatement final : public ForEachStatement {
+ public:
+ DECLARE_NODE_TYPE(ForInStatement)
+
+ Expression* enumerable() const {
+ return subject();
+ }
+
+ // Type feedback information.
+ void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
+ FeedbackVectorSlotCache* cache) override {
+ ForEachStatement::AssignFeedbackVectorSlots(isolate, spec, cache);
+ for_in_feedback_slot_ = spec->AddGeneralSlot();
+ }
+
+ FeedbackVectorSlot ForInFeedbackSlot() {
+ DCHECK(!for_in_feedback_slot_.IsInvalid());
+ return for_in_feedback_slot_;
+ }
+
+ enum ForInType { FAST_FOR_IN, SLOW_FOR_IN };
+ ForInType for_in_type() const { return for_in_type_; }
+ void set_for_in_type(ForInType type) { for_in_type_ = type; }
+
+ static int num_ids() { return parent_num_ids() + 6; }
+ BailoutId BodyId() const { return BailoutId(local_id(0)); }
+ BailoutId PrepareId() const { return BailoutId(local_id(1)); }
+ BailoutId EnumId() const { return BailoutId(local_id(2)); }
+ BailoutId ToObjectId() const { return BailoutId(local_id(3)); }
+ BailoutId FilterId() const { return BailoutId(local_id(4)); }
+ BailoutId AssignmentId() const { return BailoutId(local_id(5)); }
+ BailoutId ContinueId() const override { return EntryId(); }
+ BailoutId StackCheckId() const override { return BodyId(); }
+
+ protected:
+ ForInStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
+ : ForEachStatement(zone, labels, pos), for_in_type_(SLOW_FOR_IN) {}
+ static int parent_num_ids() { return ForEachStatement::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ ForInType for_in_type_;
+ FeedbackVectorSlot for_in_feedback_slot_;
+};
+
+
+class ForOfStatement final : public ForEachStatement {
+ public:
+ DECLARE_NODE_TYPE(ForOfStatement)
+
+ void Initialize(Expression* each,
+ Expression* subject,
+ Statement* body,
+ Expression* assign_iterator,
+ Expression* next_result,
+ Expression* result_done,
+ Expression* assign_each) {
+ ForEachStatement::Initialize(each, subject, body);
+ assign_iterator_ = assign_iterator;
+ next_result_ = next_result;
+ result_done_ = result_done;
+ assign_each_ = assign_each;
+ }
+
+ Expression* iterable() const {
+ return subject();
+ }
+
+ // iterator = subject[Symbol.iterator]()
+ Expression* assign_iterator() const {
+ return assign_iterator_;
+ }
+
+ // result = iterator.next() // with type check
+ Expression* next_result() const {
+ return next_result_;
+ }
+
+ // result.done
+ Expression* result_done() const {
+ return result_done_;
+ }
+
+ // each = result.value
+ Expression* assign_each() const {
+ return assign_each_;
+ }
+
+ void set_assign_iterator(Expression* e) { assign_iterator_ = e; }
+ void set_next_result(Expression* e) { next_result_ = e; }
+ void set_result_done(Expression* e) { result_done_ = e; }
+ void set_assign_each(Expression* e) { assign_each_ = e; }
+
+ BailoutId ContinueId() const override { return EntryId(); }
+ BailoutId StackCheckId() const override { return BackEdgeId(); }
+
+ static int num_ids() { return parent_num_ids() + 1; }
+ BailoutId BackEdgeId() const { return BailoutId(local_id(0)); }
+
+ protected:
+ ForOfStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
+ : ForEachStatement(zone, labels, pos),
+ assign_iterator_(NULL),
+ next_result_(NULL),
+ result_done_(NULL),
+ assign_each_(NULL) {}
+ static int parent_num_ids() { return ForEachStatement::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ Expression* assign_iterator_;
+ Expression* next_result_;
+ Expression* result_done_;
+ Expression* assign_each_;
+};
+
+
+class ExpressionStatement final : public Statement {
+ public:
+ DECLARE_NODE_TYPE(ExpressionStatement)
+
+ void set_expression(Expression* e) { expression_ = e; }
+ Expression* expression() const { return expression_; }
+ bool IsJump() const override { return expression_->IsThrow(); }
+ void MarkTail() override { expression_->MarkTail(); }
+
+ protected:
+ ExpressionStatement(Zone* zone, Expression* expression, int pos)
+ : Statement(zone, pos), expression_(expression) { }
+
+ private:
+ Expression* expression_;
+};
+
+
+class JumpStatement : public Statement {
+ public:
+ bool IsJump() const final { return true; }
+
+ protected:
+ explicit JumpStatement(Zone* zone, int pos) : Statement(zone, pos) {}
+};
+
+
+class ContinueStatement final : public JumpStatement {
+ public:
+ DECLARE_NODE_TYPE(ContinueStatement)
+
+ IterationStatement* target() const { return target_; }
+
+ protected:
+ explicit ContinueStatement(Zone* zone, IterationStatement* target, int pos)
+ : JumpStatement(zone, pos), target_(target) { }
+
+ private:
+ IterationStatement* target_;
+};
+
+
+class BreakStatement final : public JumpStatement {
+ public:
+ DECLARE_NODE_TYPE(BreakStatement)
+
+ BreakableStatement* target() const { return target_; }
+
+ protected:
+ explicit BreakStatement(Zone* zone, BreakableStatement* target, int pos)
+ : JumpStatement(zone, pos), target_(target) { }
+
+ private:
+ BreakableStatement* target_;
+};
+
+
+class ReturnStatement final : public JumpStatement {
+ public:
+ DECLARE_NODE_TYPE(ReturnStatement)
+
+ Expression* expression() const { return expression_; }
+
+ void set_expression(Expression* e) { expression_ = e; }
+
+ protected:
+ explicit ReturnStatement(Zone* zone, Expression* expression, int pos)
+ : JumpStatement(zone, pos), expression_(expression) { }
+
+ private:
+ Expression* expression_;
+};
+
+
+class WithStatement final : public Statement {
+ public:
+ DECLARE_NODE_TYPE(WithStatement)
+
+ Scope* scope() { return scope_; }
+ Expression* expression() const { return expression_; }
+ void set_expression(Expression* e) { expression_ = e; }
+ 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)); }
+
+ void MarkTail() override { statement_->MarkTail(); }
+
+ protected:
+ WithStatement(Zone* zone, Scope* scope, Expression* expression,
+ Statement* statement, int pos)
+ : Statement(zone, pos),
+ scope_(scope),
+ expression_(expression),
+ statement_(statement),
+ base_id_(BailoutId::None().ToInt()) {}
+ static int parent_num_ids() { return 0; }
+
+ int base_id() const {
+ DCHECK(!BailoutId(base_id_).IsNone());
+ return base_id_;
+ }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ Scope* scope_;
+ Expression* expression_;
+ Statement* statement_;
+ int base_id_;
+};
+
+
+class CaseClause final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(CaseClause)
+
+ bool is_default() const { return label_ == NULL; }
+ Expression* label() const {
+ CHECK(!is_default());
+ return label_;
+ }
+ void set_label(Expression* e) { label_ = e; }
+ Label* body_target() { return &body_target_; }
+ ZoneList<Statement*>* statements() const { return statements_; }
+
+ static int num_ids() { return parent_num_ids() + 2; }
+ BailoutId EntryId() const { return BailoutId(local_id(0)); }
+ TypeFeedbackId CompareId() { return TypeFeedbackId(local_id(1)); }
+
+ void MarkTail() override {
+ if (!statements_->is_empty()) statements_->last()->MarkTail();
+ }
+
+ Type* compare_type() { return compare_type_; }
+ void set_compare_type(Type* type) { compare_type_ = type; }
+
+ protected:
+ static int parent_num_ids() { return Expression::num_ids(); }
+
+ private:
+ CaseClause(Zone* zone, Expression* label, ZoneList<Statement*>* statements,
+ int pos);
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ Expression* label_;
+ Label body_target_;
+ ZoneList<Statement*>* statements_;
+ Type* compare_type_;
+};
+
+
+class SwitchStatement final : public BreakableStatement {
+ public:
+ DECLARE_NODE_TYPE(SwitchStatement)
+
+ void Initialize(Expression* tag, ZoneList<CaseClause*>* cases) {
+ tag_ = tag;
+ cases_ = cases;
+ }
+
+ Expression* tag() const { return tag_; }
+ ZoneList<CaseClause*>* cases() const { return cases_; }
+
+ void set_tag(Expression* t) { tag_ = t; }
+
+ void MarkTail() override {
+ if (!cases_->is_empty()) cases_->last()->MarkTail();
+ }
+
+ protected:
+ SwitchStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
+ : BreakableStatement(zone, labels, TARGET_FOR_ANONYMOUS, pos),
+ tag_(NULL),
+ cases_(NULL) {}
+
+ private:
+ Expression* tag_;
+ ZoneList<CaseClause*>* cases_;
+};
+
+
+// If-statements always have non-null references to their then- and
+// else-parts. When parsing if-statements with no explicit else-part,
+// the parser implicitly creates an empty statement. Use the
+// HasThenStatement() and HasElseStatement() functions to check if a
+// given if-statement has a then- or an else-part containing code.
+class IfStatement final : public Statement {
+ public:
+ DECLARE_NODE_TYPE(IfStatement)
+
+ bool HasThenStatement() const { return !then_statement()->IsEmpty(); }
+ bool HasElseStatement() const { return !else_statement()->IsEmpty(); }
+
+ Expression* condition() const { return condition_; }
+ Statement* then_statement() const { return then_statement_; }
+ Statement* else_statement() const { return else_statement_; }
+
+ void set_condition(Expression* e) { condition_ = e; }
+ void set_then_statement(Statement* s) { then_statement_ = s; }
+ void set_else_statement(Statement* s) { else_statement_ = s; }
+
+ bool IsJump() const override {
+ return HasThenStatement() && then_statement()->IsJump()
+ && HasElseStatement() && else_statement()->IsJump();
+ }
+
+ void MarkTail() override {
+ then_statement_->MarkTail();
+ else_statement_->MarkTail();
+ }
+
+ void set_base_id(int id) { base_id_ = id; }
+ static int num_ids() { return parent_num_ids() + 3; }
+ BailoutId IfId() const { return BailoutId(local_id(0)); }
+ BailoutId ThenId() const { return BailoutId(local_id(1)); }
+ BailoutId ElseId() const { return BailoutId(local_id(2)); }
+
+ protected:
+ IfStatement(Zone* zone, Expression* condition, Statement* then_statement,
+ Statement* else_statement, int pos)
+ : Statement(zone, pos),
+ condition_(condition),
+ then_statement_(then_statement),
+ else_statement_(else_statement),
+ base_id_(BailoutId::None().ToInt()) {}
+ static int parent_num_ids() { return 0; }
+
+ int base_id() const {
+ DCHECK(!BailoutId(base_id_).IsNone());
+ return base_id_;
+ }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ Expression* condition_;
+ Statement* then_statement_;
+ Statement* else_statement_;
+ int base_id_;
+};
+
+
+class TryStatement : public Statement {
+ public:
+ Block* try_block() const { return try_block_; }
+ void set_try_block(Block* b) { try_block_ = b; }
+
+ void set_base_id(int id) { base_id_ = id; }
+ static int num_ids() { return parent_num_ids() + 1; }
+ BailoutId HandlerId() const { return BailoutId(local_id(0)); }
+
+ protected:
+ TryStatement(Zone* zone, Block* try_block, int pos)
+ : Statement(zone, pos),
+ try_block_(try_block),
+ base_id_(BailoutId::None().ToInt()) {}
+ static int parent_num_ids() { return 0; }
+
+ int base_id() const {
+ DCHECK(!BailoutId(base_id_).IsNone());
+ return base_id_;
+ }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ Block* try_block_;
+ int base_id_;
+};
+
+
+class TryCatchStatement final : public TryStatement {
+ public:
+ DECLARE_NODE_TYPE(TryCatchStatement)
+
+ Scope* scope() { return scope_; }
+ Variable* variable() { return variable_; }
+ Block* catch_block() const { return catch_block_; }
+ void set_catch_block(Block* b) { catch_block_ = b; }
+
+ void MarkTail() override { catch_block_->MarkTail(); }
+
+ protected:
+ TryCatchStatement(Zone* zone, Block* try_block, Scope* scope,
+ Variable* variable, Block* catch_block, int pos)
+ : TryStatement(zone, try_block, pos),
+ scope_(scope),
+ variable_(variable),
+ catch_block_(catch_block) {}
+
+ private:
+ Scope* scope_;
+ Variable* variable_;
+ Block* catch_block_;
+};
+
+
+class TryFinallyStatement final : public TryStatement {
+ public:
+ DECLARE_NODE_TYPE(TryFinallyStatement)
+
+ Block* finally_block() const { return finally_block_; }
+ void set_finally_block(Block* b) { finally_block_ = b; }
+
+ void MarkTail() override { finally_block_->MarkTail(); }
+
+ protected:
+ TryFinallyStatement(Zone* zone, Block* try_block, Block* finally_block,
+ int pos)
+ : TryStatement(zone, try_block, pos), finally_block_(finally_block) {}
+
+ private:
+ Block* finally_block_;
+};
+
+
+class DebuggerStatement final : public Statement {
+ public:
+ DECLARE_NODE_TYPE(DebuggerStatement)
+
+ 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)); }
+
+ protected:
+ explicit DebuggerStatement(Zone* zone, int pos)
+ : Statement(zone, pos), base_id_(BailoutId::None().ToInt()) {}
+ static int parent_num_ids() { return 0; }
+
+ int base_id() const {
+ DCHECK(!BailoutId(base_id_).IsNone());
+ return base_id_;
+ }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ int base_id_;
+};
+
+
+class EmptyStatement final : public Statement {
+ public:
+ DECLARE_NODE_TYPE(EmptyStatement)
+
+ protected:
+ explicit EmptyStatement(Zone* zone, int pos): Statement(zone, pos) {}
+};
+
+
+// Delegates to another statement, which may be overwritten.
+// This was introduced to implement ES2015 Annex B3.3 for conditionally making
+// sloppy-mode block-scoped functions have a var binding, which is changed
+// from one statement to another during parsing.
+class SloppyBlockFunctionStatement final : public Statement {
+ public:
+ DECLARE_NODE_TYPE(SloppyBlockFunctionStatement)
+
+ Statement* statement() const { return statement_; }
+ void set_statement(Statement* statement) { statement_ = statement; }
+ Scope* scope() const { return scope_; }
+
+ private:
+ SloppyBlockFunctionStatement(Zone* zone, Statement* statement, Scope* scope)
+ : Statement(zone, RelocInfo::kNoPosition),
+ statement_(statement),
+ scope_(scope) {}
+
+ Statement* statement_;
+ Scope* const scope_;
+};
+
+
+class Literal final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(Literal)
+
+ bool IsPropertyName() const override { return value_->IsPropertyName(); }
+
+ Handle<String> AsPropertyName() {
+ DCHECK(IsPropertyName());
+ return Handle<String>::cast(value());
+ }
+
+ const AstRawString* AsRawPropertyName() {
+ DCHECK(IsPropertyName());
+ return value_->AsString();
+ }
+
+ bool ToBooleanIsTrue() const override { return value()->BooleanValue(); }
+ bool ToBooleanIsFalse() const override { return !value()->BooleanValue(); }
+
+ Handle<Object> value() const { return value_->value(); }
+ const AstValue* raw_value() const { return value_; }
+
+ // Support for using Literal as a HashMap key. NOTE: Currently, this works
+ // only for string and number literals!
+ uint32_t Hash();
+ static bool Match(void* literal1, void* literal2);
+
+ static int num_ids() { return parent_num_ids() + 1; }
+ TypeFeedbackId LiteralFeedbackId() const {
+ return TypeFeedbackId(local_id(0));
+ }
+
+ protected:
+ Literal(Zone* zone, const AstValue* value, int position)
+ : Expression(zone, position), value_(value) {}
+ static int parent_num_ids() { return Expression::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ const AstValue* value_;
+};
+
+
+class AstLiteralReindexer;
+
+// Base class for literals that needs space in the corresponding JSFunction.
+class MaterializedLiteral : public Expression {
+ public:
+ MaterializedLiteral* AsMaterializedLiteral() final { return this; }
+
+ int literal_index() { return literal_index_; }
+
+ int depth() const {
+ // only callable after initialization.
+ DCHECK(depth_ >= 1);
+ return depth_;
+ }
+
+ bool is_strong() const { return is_strong_; }
+
+ protected:
+ MaterializedLiteral(Zone* zone, int literal_index, bool is_strong, int pos)
+ : Expression(zone, pos),
+ literal_index_(literal_index),
+ is_simple_(false),
+ is_strong_(is_strong),
+ depth_(0) {}
+
+ // A materialized literal is simple if the values consist of only
+ // constants and simple object and array literals.
+ bool is_simple() const { return is_simple_; }
+ void set_is_simple(bool is_simple) { is_simple_ = is_simple; }
+ friend class CompileTimeValue;
+
+ void set_depth(int depth) {
+ DCHECK(depth >= 1);
+ depth_ = depth;
+ }
+
+ // Populate the constant properties/elements fixed array.
+ void BuildConstants(Isolate* isolate);
+ friend class ArrayLiteral;
+ friend class ObjectLiteral;
+
+ // If the expression is a literal, return the literal value;
+ // if the expression is a materialized literal and is simple return a
+ // compile time value as encoded by CompileTimeValue::GetValue().
+ // Otherwise, return undefined literal as the placeholder
+ // in the object literal boilerplate.
+ Handle<Object> GetBoilerplateValue(Expression* expression, Isolate* isolate);
+
+ private:
+ int literal_index_;
+ bool is_simple_;
+ bool is_strong_;
+ int depth_;
+
+ friend class AstLiteralReindexer;
+};
+
+
+// Property is used for passing information
+// about an object literal's properties from the parser
+// to the code generator.
+class ObjectLiteralProperty final : public ZoneObject {
+ public:
+ enum Kind {
+ CONSTANT, // Property with constant value (compile time).
+ 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__.
+ };
+
+ Expression* key() { return key_; }
+ Expression* value() { return value_; }
+ Kind kind() { return kind_; }
+
+ void set_key(Expression* e) { key_ = e; }
+ void set_value(Expression* e) { value_ = e; }
+
+ // Type feedback information.
+ bool IsMonomorphic() { return !receiver_type_.is_null(); }
+ Handle<Map> GetReceiverType() { return receiver_type_; }
+
+ bool IsCompileTimeValue();
+
+ void set_emit_store(bool emit_store);
+ bool emit_store();
+
+ bool is_static() const { return is_static_; }
+ bool is_computed_name() const { return is_computed_name_; }
+
+ FeedbackVectorSlot GetSlot(int offset = 0) const {
+ DCHECK_LT(offset, static_cast<int>(arraysize(slots_)));
+ return slots_[offset];
+ }
+ void SetSlot(FeedbackVectorSlot slot, int offset = 0) {
+ DCHECK_LT(offset, static_cast<int>(arraysize(slots_)));
+ slots_[offset] = slot;
+ }
+
+ void set_receiver_type(Handle<Map> map) { receiver_type_ = map; }
+
+ protected:
+ friend class AstNodeFactory;
+
+ ObjectLiteralProperty(Expression* key, Expression* value, Kind kind,
+ bool is_static, bool is_computed_name);
+ ObjectLiteralProperty(AstValueFactory* ast_value_factory, Expression* key,
+ Expression* value, bool is_static,
+ bool is_computed_name);
+
+ private:
+ Expression* key_;
+ Expression* value_;
+ FeedbackVectorSlot slots_[2];
+ Kind kind_;
+ bool emit_store_;
+ bool is_static_;
+ bool is_computed_name_;
+ Handle<Map> receiver_type_;
+};
+
+
+// An object literal has a boilerplate object that is used
+// for minimizing the work when constructing it at runtime.
+class ObjectLiteral final : public MaterializedLiteral {
+ public:
+ typedef ObjectLiteralProperty Property;
+
+ DECLARE_NODE_TYPE(ObjectLiteral)
+
+ Handle<FixedArray> constant_properties() const {
+ return constant_properties_;
+ }
+ int properties_count() const { return constant_properties_->length() / 2; }
+ ZoneList<Property*>* properties() const { return properties_; }
+ bool fast_elements() const { return fast_elements_; }
+ bool may_store_doubles() const { return may_store_doubles_; }
+ bool has_function() const { return has_function_; }
+ bool has_elements() const { return has_elements_; }
+
+ // Decide if a property should be in the object boilerplate.
+ static bool IsBoilerplateProperty(Property* property);
+
+ // Populate the constant properties fixed array.
+ void BuildConstantProperties(Isolate* isolate);
+
+ // 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 is emitted.
+ void CalculateEmitStore(Zone* zone);
+
+ // Assemble bitfield of flags for the CreateObjectLiteral helper.
+ int ComputeFlags(bool disable_mementos = false) const {
+ int flags = fast_elements() ? kFastElements : kNoFlags;
+ flags |= has_function() ? kHasFunction : kNoFlags;
+ if (depth() == 1 && !has_elements() && !may_store_doubles()) {
+ flags |= kShallowProperties;
+ }
+ if (disable_mementos) {
+ flags |= kDisableMementos;
+ }
+ if (is_strong()) {
+ flags |= kIsStrong;
+ }
+ return flags;
+ }
+
+ enum Flags {
+ kNoFlags = 0,
+ kFastElements = 1,
+ kHasFunction = 1 << 1,
+ kShallowProperties = 1 << 2,
+ kDisableMementos = 1 << 3,
+ kIsStrong = 1 << 4
+ };
+
+ struct Accessors: public ZoneObject {
+ Accessors() : getter(NULL), setter(NULL) {}
+ ObjectLiteralProperty* getter;
+ ObjectLiteralProperty* setter;
+ };
+
+ 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));
+ }
+
+ // 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();
+ }
+
+ // 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) override;
+
+ protected:
+ ObjectLiteral(Zone* zone, ZoneList<Property*>* properties, int literal_index,
+ int boilerplate_properties, bool has_function, bool is_strong,
+ int pos)
+ : MaterializedLiteral(zone, literal_index, is_strong, pos),
+ properties_(properties),
+ boilerplate_properties_(boilerplate_properties),
+ fast_elements_(false),
+ has_elements_(false),
+ may_store_doubles_(false),
+ has_function_(has_function) {}
+ static int parent_num_ids() { return MaterializedLiteral::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+ Handle<FixedArray> constant_properties_;
+ ZoneList<Property*>* properties_;
+ int boilerplate_properties_;
+ bool fast_elements_;
+ bool has_elements_;
+ bool may_store_doubles_;
+ bool has_function_;
+ FeedbackVectorSlot slot_;
+};
+
+
+// A map from property names to getter/setter pairs allocated in the zone.
+class AccessorTable : public TemplateHashMap<Literal, ObjectLiteral::Accessors,
+ ZoneAllocationPolicy> {
+ public:
+ explicit AccessorTable(Zone* zone)
+ : TemplateHashMap<Literal, ObjectLiteral::Accessors,
+ ZoneAllocationPolicy>(Literal::Match,
+ ZoneAllocationPolicy(zone)),
+ zone_(zone) {}
+
+ Iterator lookup(Literal* literal) {
+ Iterator it = find(literal, true, ZoneAllocationPolicy(zone_));
+ if (it->second == NULL) it->second = new (zone_) ObjectLiteral::Accessors();
+ return it;
+ }
+
+ private:
+ Zone* zone_;
+};
+
+
+// Node for capturing a regexp literal.
+class RegExpLiteral final : public MaterializedLiteral {
+ public:
+ DECLARE_NODE_TYPE(RegExpLiteral)
+
+ Handle<String> pattern() const { return pattern_->string(); }
+ int flags() const { return flags_; }
+
+ protected:
+ RegExpLiteral(Zone* zone, const AstRawString* pattern, int flags,
+ int literal_index, bool is_strong, int pos)
+ : MaterializedLiteral(zone, literal_index, is_strong, pos),
+ pattern_(pattern),
+ flags_(flags) {
+ set_depth(1);
+ }
+
+ private:
+ const AstRawString* const pattern_;
+ int const flags_;
+};
+
+
+// An array literal has a literals object that is used
+// for minimizing the work when constructing it at runtime.
+class ArrayLiteral final : public MaterializedLiteral {
+ public:
+ DECLARE_NODE_TYPE(ArrayLiteral)
+
+ 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());
+ }
+
+ ZoneList<Expression*>* values() const { return values_; }
+
+ BailoutId CreateLiteralId() const { return BailoutId(local_id(0)); }
+
+ // Return an AST id for an element that is used in simulate instructions.
+ BailoutId GetIdForElement(int i) { return BailoutId(local_id(i + 1)); }
+
+ // Unlike other AST nodes, this number of bailout IDs allocated for an
+ // ArrayLiteral can vary, so num_ids() is not a static method.
+ int num_ids() const { return parent_num_ids() + 1 + values()->length(); }
+
+ // Populate the constant elements fixed array.
+ void BuildConstantElements(Isolate* isolate);
+
+ // Assemble bitfield of flags for the CreateArrayLiteral helper.
+ int ComputeFlags(bool disable_mementos = false) const {
+ int flags = depth() == 1 ? kShallowElements : kNoFlags;
+ if (disable_mementos) {
+ flags |= kDisableMementos;
+ }
+ if (is_strong()) {
+ flags |= kIsStrong;
+ }
+ return flags;
+ }
+
+ enum Flags {
+ kNoFlags = 0,
+ kShallowElements = 1,
+ kDisableMementos = 1 << 1,
+ kIsStrong = 1 << 2
+ };
+
+ void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
+ FeedbackVectorSlotCache* cache) override;
+ FeedbackVectorSlot LiteralFeedbackSlot() const { return literal_slot_; }
+
+ protected:
+ ArrayLiteral(Zone* zone, ZoneList<Expression*>* values,
+ int first_spread_index, int literal_index, bool is_strong,
+ int pos)
+ : MaterializedLiteral(zone, literal_index, is_strong, pos),
+ values_(values),
+ first_spread_index_(first_spread_index) {}
+ static int parent_num_ids() { return MaterializedLiteral::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ Handle<FixedArray> constant_elements_;
+ ZoneList<Expression*>* values_;
+ int first_spread_index_;
+ FeedbackVectorSlot literal_slot_;
+};
+
+
+class VariableProxy final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(VariableProxy)
+
+ bool IsValidReferenceExpression() const override {
+ return !is_this() && !is_new_target();
+ }
+
+ bool IsArguments() const { return is_resolved() && var()->is_arguments(); }
+
+ Handle<String> name() const { return raw_name()->string(); }
+ const AstRawString* raw_name() const {
+ return is_resolved() ? var_->raw_name() : raw_name_;
+ }
+
+ Variable* var() const {
+ DCHECK(is_resolved());
+ return var_;
+ }
+ void set_var(Variable* v) {
+ DCHECK(!is_resolved());
+ DCHECK_NOT_NULL(v);
+ var_ = v;
+ }
+
+ bool is_this() const { return IsThisField::decode(bit_field_); }
+
+ bool is_assigned() const { return IsAssignedField::decode(bit_field_); }
+ void set_is_assigned() {
+ bit_field_ = IsAssignedField::update(bit_field_, true);
+ }
+
+ bool is_resolved() const { return IsResolvedField::decode(bit_field_); }
+ void set_is_resolved() {
+ bit_field_ = IsResolvedField::update(bit_field_, true);
+ }
+
+ bool is_new_target() const { return IsNewTargetField::decode(bit_field_); }
+ void set_is_new_target() {
+ bit_field_ = IsNewTargetField::update(bit_field_, true);
+ }
+
+ int end_position() const { return end_position_; }
+
+ // Bind this proxy to the variable var.
+ void BindTo(Variable* var);
+
+ bool UsesVariableFeedbackSlot() const {
+ return var()->IsUnallocated() || var()->IsLookupSlot();
+ }
+
+ void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
+ FeedbackVectorSlotCache* cache) override;
+
+ FeedbackVectorSlot VariableFeedbackSlot() { return variable_feedback_slot_; }
+
+ static int num_ids() { return parent_num_ids() + 1; }
+ BailoutId BeforeId() const { return BailoutId(local_id(0)); }
+
+ protected:
+ VariableProxy(Zone* zone, Variable* var, int start_position,
+ int end_position);
+
+ VariableProxy(Zone* zone, const AstRawString* name,
+ Variable::Kind variable_kind, int start_position,
+ int end_position);
+ static int parent_num_ids() { return Expression::num_ids(); }
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ class IsThisField : public BitField8<bool, 0, 1> {};
+ class IsAssignedField : public BitField8<bool, 1, 1> {};
+ class IsResolvedField : public BitField8<bool, 2, 1> {};
+ class IsNewTargetField : public BitField8<bool, 3, 1> {};
+
+ // Start with 16-bit (or smaller) field, which should get packed together
+ // with Expression's trailing 16-bit field.
+ uint8_t bit_field_;
+ FeedbackVectorSlot variable_feedback_slot_;
+ union {
+ const AstRawString* raw_name_; // if !is_resolved_
+ Variable* var_; // if is_resolved_
+ };
+ // Position is stored in the AstNode superclass, but VariableProxy needs to
+ // know its end position too (for error messages). It cannot be inferred from
+ // the variable name length because it can contain escapes.
+ int end_position_;
+};
+
+
+// Left-hand side can only be a property, a global or a (parameter or local)
+// slot.
+enum LhsKind {
+ VARIABLE,
+ NAMED_PROPERTY,
+ KEYED_PROPERTY,
+ NAMED_SUPER_PROPERTY,
+ KEYED_SUPER_PROPERTY
+};
+
+
+class Property final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(Property)
+
+ bool IsValidReferenceExpression() const override { return true; }
+
+ Expression* obj() const { return obj_; }
+ Expression* key() const { return key_; }
+
+ void set_obj(Expression* e) { obj_ = e; }
+ void set_key(Expression* e) { key_ = e; }
+
+ static int num_ids() { return parent_num_ids() + 1; }
+ BailoutId LoadId() const { return BailoutId(local_id(0)); }
+
+ bool IsStringAccess() const {
+ return IsStringAccessField::decode(bit_field_);
+ }
+
+ // Type feedback information.
+ bool IsMonomorphic() override { return receiver_types_.length() == 1; }
+ SmallMapList* GetReceiverTypes() override { return &receiver_types_; }
+ KeyedAccessStoreMode GetStoreMode() const override { return STANDARD_STORE; }
+ IcCheckType GetKeyType() const override {
+ return KeyTypeField::decode(bit_field_);
+ }
+ bool IsUninitialized() const {
+ return !is_for_call() && HasNoTypeInformation();
+ }
+ bool HasNoTypeInformation() const {
+ return GetInlineCacheState() == UNINITIALIZED;
+ }
+ InlineCacheState GetInlineCacheState() const {
+ return InlineCacheStateField::decode(bit_field_);
+ }
+ void set_is_string_access(bool b) {
+ bit_field_ = IsStringAccessField::update(bit_field_, b);
+ }
+ void set_key_type(IcCheckType key_type) {
+ bit_field_ = KeyTypeField::update(bit_field_, key_type);
+ }
+ void set_inline_cache_state(InlineCacheState state) {
+ bit_field_ = InlineCacheStateField::update(bit_field_, state);
+ }
+ void mark_for_call() {
+ bit_field_ = IsForCallField::update(bit_field_, true);
+ }
+ bool is_for_call() const { return IsForCallField::decode(bit_field_); }
+
+ bool IsSuperAccess() { return obj()->IsSuperPropertyReference(); }
+
+ void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
+ FeedbackVectorSlotCache* cache) override {
+ FeedbackVectorSlotKind kind = key()->IsPropertyName()
+ ? FeedbackVectorSlotKind::LOAD_IC
+ : FeedbackVectorSlotKind::KEYED_LOAD_IC;
+ property_feedback_slot_ = spec->AddSlot(kind);
+ }
+
+ FeedbackVectorSlot PropertyFeedbackSlot() const {
+ return property_feedback_slot_;
+ }
+
+ static LhsKind GetAssignType(Property* property) {
+ if (property == NULL) return VARIABLE;
+ bool super_access = property->IsSuperAccess();
+ return (property->key()->IsPropertyName())
+ ? (super_access ? NAMED_SUPER_PROPERTY : NAMED_PROPERTY)
+ : (super_access ? KEYED_SUPER_PROPERTY : KEYED_PROPERTY);
+ }
+
+ protected:
+ Property(Zone* zone, Expression* obj, Expression* key, int pos)
+ : Expression(zone, pos),
+ bit_field_(IsForCallField::encode(false) |
+ IsStringAccessField::encode(false) |
+ InlineCacheStateField::encode(UNINITIALIZED)),
+ obj_(obj),
+ key_(key) {}
+ static int parent_num_ids() { return Expression::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ class IsForCallField : public BitField8<bool, 0, 1> {};
+ class IsStringAccessField : public BitField8<bool, 1, 1> {};
+ class KeyTypeField : public BitField8<IcCheckType, 2, 1> {};
+ class InlineCacheStateField : public BitField8<InlineCacheState, 3, 4> {};
+ uint8_t bit_field_;
+ FeedbackVectorSlot property_feedback_slot_;
+ Expression* obj_;
+ Expression* key_;
+ SmallMapList receiver_types_;
+};
+
+
+class Call final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(Call)
+
+ Expression* expression() const { return expression_; }
+ ZoneList<Expression*>* arguments() const { return arguments_; }
+
+ void set_expression(Expression* e) { expression_ = e; }
+
+ // Type feedback information.
+ void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
+ FeedbackVectorSlotCache* cache) override;
+
+ FeedbackVectorSlot CallFeedbackSlot() const { return stub_slot_; }
+
+ FeedbackVectorSlot CallFeedbackICSlot() const { return ic_slot_; }
+
+ SmallMapList* GetReceiverTypes() override {
+ if (expression()->IsProperty()) {
+ return expression()->AsProperty()->GetReceiverTypes();
+ }
+ return NULL;
+ }
+
+ bool IsMonomorphic() override {
+ if (expression()->IsProperty()) {
+ return expression()->AsProperty()->IsMonomorphic();
+ }
+ return !target_.is_null();
+ }
+
+ bool global_call() const {
+ VariableProxy* proxy = expression_->AsVariableProxy();
+ return proxy != NULL && proxy->var()->IsUnallocatedOrGlobalSlot();
+ }
+
+ bool known_global_function() const {
+ return global_call() && !target_.is_null();
+ }
+
+ Handle<JSFunction> target() { return target_; }
+
+ Handle<AllocationSite> allocation_site() { return allocation_site_; }
+
+ void SetKnownGlobalTarget(Handle<JSFunction> target) {
+ target_ = target;
+ set_is_uninitialized(false);
+ }
+ void set_target(Handle<JSFunction> target) { target_ = target; }
+ void set_allocation_site(Handle<AllocationSite> site) {
+ allocation_site_ = site;
+ }
+
+ static int num_ids() { return parent_num_ids() + 4; }
+ 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)); }
+
+ bool is_uninitialized() const {
+ return IsUninitializedField::decode(bit_field_);
+ }
+ void set_is_uninitialized(bool b) {
+ bit_field_ = IsUninitializedField::update(bit_field_, b);
+ }
+
+ bool is_tail() const { return IsTailField::decode(bit_field_); }
+ void MarkTail() override {
+ bit_field_ = IsTailField::update(bit_field_, true);
+ }
+
+ enum CallType {
+ POSSIBLY_EVAL_CALL,
+ GLOBAL_CALL,
+ LOOKUP_SLOT_CALL,
+ NAMED_PROPERTY_CALL,
+ KEYED_PROPERTY_CALL,
+ NAMED_SUPER_PROPERTY_CALL,
+ KEYED_SUPER_PROPERTY_CALL,
+ SUPER_CALL,
+ OTHER_CALL
+ };
+
+ // Helpers to determine how to handle the call.
+ CallType GetCallType(Isolate* isolate) const;
+ bool IsUsingCallFeedbackSlot(Isolate* isolate) const;
+ bool IsUsingCallFeedbackICSlot(Isolate* isolate) const;
+
+#ifdef DEBUG
+ // Used to assert that the FullCodeGenerator records the return site.
+ bool return_is_recorded_;
+#endif
+
+ protected:
+ Call(Zone* zone, Expression* expression, ZoneList<Expression*>* arguments,
+ int pos)
+ : Expression(zone, pos),
+ expression_(expression),
+ arguments_(arguments),
+ bit_field_(IsUninitializedField::encode(false)) {
+ if (expression->IsProperty()) {
+ expression->AsProperty()->mark_for_call();
+ }
+ }
+ static int parent_num_ids() { return Expression::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ FeedbackVectorSlot ic_slot_;
+ FeedbackVectorSlot stub_slot_;
+ Expression* expression_;
+ ZoneList<Expression*>* arguments_;
+ Handle<JSFunction> target_;
+ Handle<AllocationSite> allocation_site_;
+ class IsUninitializedField : public BitField8<bool, 0, 1> {};
+ class IsTailField : public BitField8<bool, 1, 1> {};
+ uint8_t bit_field_;
+};
+
+
+class CallNew final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(CallNew)
+
+ Expression* expression() const { return expression_; }
+ ZoneList<Expression*>* arguments() const { return arguments_; }
+
+ void set_expression(Expression* e) { expression_ = e; }
+
+ // Type feedback information.
+ void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
+ FeedbackVectorSlotCache* cache) override {
+ callnew_feedback_slot_ = spec->AddGeneralSlot();
+ }
+
+ FeedbackVectorSlot CallNewFeedbackSlot() {
+ DCHECK(!callnew_feedback_slot_.IsInvalid());
+ return callnew_feedback_slot_;
+ }
+
+ bool IsMonomorphic() override { return is_monomorphic_; }
+ Handle<JSFunction> target() const { return target_; }
+ Handle<AllocationSite> allocation_site() const {
+ return allocation_site_;
+ }
+
+ static int num_ids() { return parent_num_ids() + 1; }
+ static int feedback_slots() { return 1; }
+ BailoutId ReturnId() const { return BailoutId(local_id(0)); }
+
+ void set_allocation_site(Handle<AllocationSite> site) {
+ allocation_site_ = site;
+ }
+ void set_is_monomorphic(bool monomorphic) { is_monomorphic_ = monomorphic; }
+ void set_target(Handle<JSFunction> target) { target_ = target; }
+ void SetKnownGlobalTarget(Handle<JSFunction> target) {
+ target_ = target;
+ is_monomorphic_ = true;
+ }
+
+ protected:
+ CallNew(Zone* zone, Expression* expression, ZoneList<Expression*>* arguments,
+ int pos)
+ : Expression(zone, pos),
+ expression_(expression),
+ arguments_(arguments),
+ is_monomorphic_(false) {}
+
+ static int parent_num_ids() { return Expression::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ Expression* expression_;
+ ZoneList<Expression*>* arguments_;
+ bool is_monomorphic_;
+ Handle<JSFunction> target_;
+ Handle<AllocationSite> allocation_site_;
+ FeedbackVectorSlot callnew_feedback_slot_;
+};
+
+
+// The CallRuntime class does not represent any official JavaScript
+// language construct. Instead it is used to call a C or JS function
+// with a set of arguments. This is used from the builtins that are
+// implemented in JavaScript (see "v8natives.js").
+class CallRuntime final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(CallRuntime)
+
+ ZoneList<Expression*>* arguments() const { return arguments_; }
+ bool is_jsruntime() const { return function_ == NULL; }
+
+ int context_index() const {
+ DCHECK(is_jsruntime());
+ return context_index_;
+ }
+ const Runtime::Function* function() const {
+ DCHECK(!is_jsruntime());
+ return function_;
+ }
+
+ 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;
+ }
+
+ protected:
+ CallRuntime(Zone* zone, const Runtime::Function* function,
+ ZoneList<Expression*>* arguments, int pos)
+ : Expression(zone, pos), function_(function), arguments_(arguments) {}
+
+ CallRuntime(Zone* zone, int context_index, ZoneList<Expression*>* arguments,
+ int pos)
+ : Expression(zone, pos),
+ function_(NULL),
+ context_index_(context_index),
+ arguments_(arguments) {}
+
+ static int parent_num_ids() { return Expression::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ const Runtime::Function* function_;
+ int context_index_;
+ ZoneList<Expression*>* arguments_;
+};
+
+
+class UnaryOperation final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(UnaryOperation)
+
+ Token::Value op() const { return op_; }
+ Expression* expression() const { return expression_; }
+ void set_expression(Expression* e) { expression_ = e; }
+
+ // For unary not (Token::NOT), the AST ids where true and false will
+ // actually be materialized, respectively.
+ static int num_ids() { return parent_num_ids() + 2; }
+ BailoutId MaterializeTrueId() const { return BailoutId(local_id(0)); }
+ BailoutId MaterializeFalseId() const { return BailoutId(local_id(1)); }
+
+ void RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) override;
+
+ protected:
+ UnaryOperation(Zone* zone, Token::Value op, Expression* expression, int pos)
+ : Expression(zone, pos), op_(op), expression_(expression) {
+ DCHECK(Token::IsUnaryOp(op));
+ }
+ static int parent_num_ids() { return Expression::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ Token::Value op_;
+ Expression* expression_;
+};
+
+
+class BinaryOperation final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(BinaryOperation)
+
+ Token::Value op() const { return static_cast<Token::Value>(op_); }
+ Expression* left() const { return left_; }
+ void set_left(Expression* e) { left_ = e; }
+ Expression* right() const { return right_; }
+ void set_right(Expression* e) { right_ = e; }
+ Handle<AllocationSite> allocation_site() const { return allocation_site_; }
+ void set_allocation_site(Handle<AllocationSite> allocation_site) {
+ allocation_site_ = allocation_site;
+ }
+
+ void MarkTail() override {
+ switch (op()) {
+ case Token::COMMA:
+ case Token::AND:
+ case Token::OR:
+ right_->MarkTail();
+ default:
+ break;
+ }
+ }
+
+ // The short-circuit logical operations need an AST ID for their
+ // right-hand subexpression.
+ static int num_ids() { return parent_num_ids() + 2; }
+ BailoutId RightId() const { return BailoutId(local_id(0)); }
+
+ TypeFeedbackId BinaryOperationFeedbackId() const {
+ return TypeFeedbackId(local_id(1));
+ }
+ Maybe<int> fixed_right_arg() const {
+ return has_fixed_right_arg_ ? Just(fixed_right_arg_value_) : Nothing<int>();
+ }
+ void set_fixed_right_arg(Maybe<int> arg) {
+ has_fixed_right_arg_ = arg.IsJust();
+ if (arg.IsJust()) fixed_right_arg_value_ = arg.FromJust();
+ }
+
+ void RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) override;
+
+ protected:
+ BinaryOperation(Zone* zone, Token::Value op, Expression* left,
+ Expression* right, int pos)
+ : Expression(zone, pos),
+ op_(static_cast<byte>(op)),
+ has_fixed_right_arg_(false),
+ fixed_right_arg_value_(0),
+ left_(left),
+ right_(right) {
+ DCHECK(Token::IsBinaryOp(op));
+ }
+ static int parent_num_ids() { return Expression::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ const byte op_; // actually Token::Value
+ // TODO(rossberg): the fixed arg should probably be represented as a Constant
+ // type for the RHS. Currenty it's actually a Maybe<int>
+ bool has_fixed_right_arg_;
+ int fixed_right_arg_value_;
+ Expression* left_;
+ Expression* right_;
+ Handle<AllocationSite> allocation_site_;
+};
+
+
+class CountOperation final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(CountOperation)
+
+ bool is_prefix() const { return IsPrefixField::decode(bit_field_); }
+ bool is_postfix() const { return !is_prefix(); }
+
+ Token::Value op() const { return TokenField::decode(bit_field_); }
+ Token::Value binary_op() {
+ return (op() == Token::INC) ? Token::ADD : Token::SUB;
+ }
+
+ Expression* expression() const { return expression_; }
+ void set_expression(Expression* e) { expression_ = e; }
+
+ bool IsMonomorphic() override { return receiver_types_.length() == 1; }
+ SmallMapList* GetReceiverTypes() override { return &receiver_types_; }
+ IcCheckType GetKeyType() const override {
+ return KeyTypeField::decode(bit_field_);
+ }
+ KeyedAccessStoreMode GetStoreMode() const override {
+ return StoreModeField::decode(bit_field_);
+ }
+ Type* type() const { return type_; }
+ void set_key_type(IcCheckType type) {
+ bit_field_ = KeyTypeField::update(bit_field_, type);
+ }
+ void set_store_mode(KeyedAccessStoreMode mode) {
+ bit_field_ = StoreModeField::update(bit_field_, mode);
+ }
+ void set_type(Type* type) { type_ = type; }
+
+ static int num_ids() { return parent_num_ids() + 4; }
+ BailoutId AssignmentId() const { return BailoutId(local_id(0)); }
+ BailoutId ToNumberId() const { return BailoutId(local_id(1)); }
+ TypeFeedbackId CountBinOpFeedbackId() const {
+ return TypeFeedbackId(local_id(2));
+ }
+ TypeFeedbackId CountStoreFeedbackId() const {
+ return TypeFeedbackId(local_id(3));
+ }
+
+ void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
+ FeedbackVectorSlotCache* cache) override;
+ FeedbackVectorSlot CountSlot() const { return slot_; }
+
+ protected:
+ CountOperation(Zone* zone, Token::Value op, bool is_prefix, Expression* expr,
+ int pos)
+ : Expression(zone, pos),
+ bit_field_(
+ IsPrefixField::encode(is_prefix) | KeyTypeField::encode(ELEMENT) |
+ StoreModeField::encode(STANDARD_STORE) | TokenField::encode(op)),
+ type_(NULL),
+ expression_(expr) {}
+ static int parent_num_ids() { return Expression::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ class IsPrefixField : public BitField16<bool, 0, 1> {};
+ class KeyTypeField : public BitField16<IcCheckType, 1, 1> {};
+ class StoreModeField : public BitField16<KeyedAccessStoreMode, 2, 3> {};
+ class TokenField : public BitField16<Token::Value, 5, 8> {};
+
+ // Starts with 16-bit field, which should get packed together with
+ // Expression's trailing 16-bit field.
+ uint16_t bit_field_;
+ Type* type_;
+ Expression* expression_;
+ SmallMapList receiver_types_;
+ FeedbackVectorSlot slot_;
+};
+
+
+class CompareOperation final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(CompareOperation)
+
+ Token::Value op() const { return op_; }
+ Expression* left() const { return left_; }
+ Expression* right() const { return right_; }
+
+ void set_left(Expression* e) { left_ = e; }
+ void set_right(Expression* e) { right_ = e; }
+
+ // Type feedback information.
+ static int num_ids() { return parent_num_ids() + 1; }
+ TypeFeedbackId CompareOperationFeedbackId() const {
+ return TypeFeedbackId(local_id(0));
+ }
+ Type* combined_type() const { return combined_type_; }
+ void set_combined_type(Type* type) { combined_type_ = type; }
+
+ // Match special cases.
+ bool IsLiteralCompareTypeof(Expression** expr, Handle<String>* check);
+ bool IsLiteralCompareUndefined(Expression** expr, Isolate* isolate);
+ bool IsLiteralCompareNull(Expression** expr);
+
+ protected:
+ CompareOperation(Zone* zone, Token::Value op, Expression* left,
+ Expression* right, int pos)
+ : Expression(zone, pos),
+ op_(op),
+ left_(left),
+ right_(right),
+ combined_type_(Type::None(zone)) {
+ DCHECK(Token::IsCompareOp(op));
+ }
+ static int parent_num_ids() { return Expression::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ Token::Value op_;
+ Expression* left_;
+ Expression* right_;
+
+ Type* combined_type_;
+};
+
+
+class Spread final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(Spread)
+
+ Expression* expression() const { return expression_; }
+ void set_expression(Expression* e) { expression_ = e; }
+
+ static int num_ids() { return parent_num_ids(); }
+
+ protected:
+ Spread(Zone* zone, Expression* expression, int pos)
+ : Expression(zone, pos), expression_(expression) {}
+ static int parent_num_ids() { return Expression::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ Expression* expression_;
+};
+
+
+class Conditional final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(Conditional)
+
+ Expression* condition() const { return condition_; }
+ Expression* then_expression() const { return then_expression_; }
+ Expression* else_expression() const { return else_expression_; }
+
+ void set_condition(Expression* e) { condition_ = e; }
+ void set_then_expression(Expression* e) { then_expression_ = e; }
+ void set_else_expression(Expression* e) { else_expression_ = e; }
+
+ void MarkTail() override {
+ then_expression_->MarkTail();
+ else_expression_->MarkTail();
+ }
+
+ static int num_ids() { return parent_num_ids() + 2; }
+ BailoutId ThenId() const { return BailoutId(local_id(0)); }
+ BailoutId ElseId() const { return BailoutId(local_id(1)); }
+
+ protected:
+ Conditional(Zone* zone, Expression* condition, Expression* then_expression,
+ Expression* else_expression, int position)
+ : Expression(zone, position),
+ condition_(condition),
+ then_expression_(then_expression),
+ else_expression_(else_expression) {}
+ static int parent_num_ids() { return Expression::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ Expression* condition_;
+ Expression* then_expression_;
+ Expression* else_expression_;
+};
+
+
+class Assignment final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(Assignment)
+
+ Assignment* AsSimpleAssignment() { return !is_compound() ? this : NULL; }
+
+ Token::Value binary_op() const;
+
+ Token::Value op() const { return TokenField::decode(bit_field_); }
+ Expression* target() const { return target_; }
+ Expression* value() const { return value_; }
+
+ void set_target(Expression* e) { target_ = e; }
+ void set_value(Expression* e) { value_ = e; }
+
+ BinaryOperation* binary_operation() const { return binary_operation_; }
+
+ // This check relies on the definition order of token in token.h.
+ bool is_compound() const { return op() > Token::ASSIGN; }
+
+ static int num_ids() { return parent_num_ids() + 2; }
+ BailoutId AssignmentId() const { return BailoutId(local_id(0)); }
+
+ // Type feedback information.
+ TypeFeedbackId AssignmentFeedbackId() { return TypeFeedbackId(local_id(1)); }
+ bool IsMonomorphic() override { return receiver_types_.length() == 1; }
+ bool IsUninitialized() const {
+ return IsUninitializedField::decode(bit_field_);
+ }
+ bool HasNoTypeInformation() {
+ return IsUninitializedField::decode(bit_field_);
+ }
+ SmallMapList* GetReceiverTypes() override { return &receiver_types_; }
+ IcCheckType GetKeyType() const override {
+ return KeyTypeField::decode(bit_field_);
+ }
+ KeyedAccessStoreMode GetStoreMode() const override {
+ return StoreModeField::decode(bit_field_);
+ }
+ void set_is_uninitialized(bool b) {
+ bit_field_ = IsUninitializedField::update(bit_field_, b);
+ }
+ void set_key_type(IcCheckType key_type) {
+ bit_field_ = KeyTypeField::update(bit_field_, key_type);
+ }
+ void set_store_mode(KeyedAccessStoreMode mode) {
+ bit_field_ = StoreModeField::update(bit_field_, mode);
+ }
+
+ void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
+ FeedbackVectorSlotCache* cache) override;
+ FeedbackVectorSlot AssignmentSlot() const { return slot_; }
+
+ protected:
+ Assignment(Zone* zone, Token::Value op, Expression* target, Expression* value,
+ int pos);
+ static int parent_num_ids() { return Expression::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ class IsUninitializedField : public BitField16<bool, 0, 1> {};
+ class KeyTypeField
+ : public BitField16<IcCheckType, IsUninitializedField::kNext, 1> {};
+ class StoreModeField
+ : public BitField16<KeyedAccessStoreMode, KeyTypeField::kNext, 3> {};
+ class TokenField : public BitField16<Token::Value, StoreModeField::kNext, 8> {
+ };
+
+ // Starts with 16-bit field, which should get packed together with
+ // Expression's trailing 16-bit field.
+ uint16_t bit_field_;
+ Expression* target_;
+ Expression* value_;
+ BinaryOperation* binary_operation_;
+ SmallMapList receiver_types_;
+ FeedbackVectorSlot slot_;
+};
+
+
+class RewritableAssignmentExpression : public Expression {
+ public:
+ DECLARE_NODE_TYPE(RewritableAssignmentExpression)
+
+ Expression* expression() { return expr_; }
+ bool is_rewritten() const { return is_rewritten_; }
+
+ void set_expression(Expression* e) { expr_ = e; }
+
+ void Rewrite(Expression* new_expression) {
+ DCHECK(!is_rewritten());
+ DCHECK_NOT_NULL(new_expression);
+ expr_ = new_expression;
+ is_rewritten_ = true;
+ }
+
+ static int num_ids() { return parent_num_ids(); }
+
+ protected:
+ RewritableAssignmentExpression(Zone* zone, Expression* expression)
+ : Expression(zone, expression->position()),
+ is_rewritten_(false),
+ expr_(expression) {}
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ bool is_rewritten_;
+ Expression* expr_;
+};
+
+
+class Yield final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(Yield)
+
+ enum Kind {
+ kInitial, // The initial yield that returns the unboxed generator object.
+ kSuspend, // A normal yield: { value: EXPRESSION, done: false }
+ kDelegating, // A yield*.
+ kFinal // A return: { value: EXPRESSION, done: true }
+ };
+
+ Expression* generator_object() const { return generator_object_; }
+ Expression* expression() const { return expression_; }
+ Kind yield_kind() const { return yield_kind_; }
+
+ void set_generator_object(Expression* e) { generator_object_ = e; }
+ void set_expression(Expression* e) { expression_ = e; }
+
+ // Type feedback information.
+ bool HasFeedbackSlots() const { return yield_kind() == kDelegating; }
+ void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
+ FeedbackVectorSlotCache* cache) override {
+ if (HasFeedbackSlots()) {
+ yield_first_feedback_slot_ = spec->AddKeyedLoadICSlot();
+ keyed_load_feedback_slot_ = spec->AddLoadICSlot();
+ done_feedback_slot_ = spec->AddLoadICSlot();
+ }
+ }
+
+ FeedbackVectorSlot KeyedLoadFeedbackSlot() {
+ DCHECK(!HasFeedbackSlots() || !yield_first_feedback_slot_.IsInvalid());
+ return yield_first_feedback_slot_;
+ }
+
+ FeedbackVectorSlot DoneFeedbackSlot() { return keyed_load_feedback_slot_; }
+
+ FeedbackVectorSlot ValueFeedbackSlot() { return done_feedback_slot_; }
+
+ protected:
+ Yield(Zone* zone, Expression* generator_object, Expression* expression,
+ Kind yield_kind, int pos)
+ : Expression(zone, pos),
+ generator_object_(generator_object),
+ expression_(expression),
+ yield_kind_(yield_kind) {}
+
+ private:
+ Expression* generator_object_;
+ Expression* expression_;
+ Kind yield_kind_;
+ FeedbackVectorSlot yield_first_feedback_slot_;
+ FeedbackVectorSlot keyed_load_feedback_slot_;
+ FeedbackVectorSlot done_feedback_slot_;
+};
+
+
+class Throw final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(Throw)
+
+ Expression* exception() const { return exception_; }
+ void set_exception(Expression* e) { exception_ = e; }
+
+ protected:
+ Throw(Zone* zone, Expression* exception, int pos)
+ : Expression(zone, pos), exception_(exception) {}
+
+ private:
+ Expression* exception_;
+};
+
+
+class FunctionLiteral final : public Expression {
+ public:
+ enum FunctionType {
+ kAnonymousExpression,
+ kNamedExpression,
+ kDeclaration,
+ kGlobalOrEval
+ };
+
+ enum ParameterFlag { kNoDuplicateParameters, kHasDuplicateParameters };
+
+ enum EagerCompileHint { kShouldEagerCompile, kShouldLazyCompile };
+
+ enum ArityRestriction { kNormalArity, kGetterArity, kSetterArity };
+
+ DECLARE_NODE_TYPE(FunctionLiteral)
+
+ Handle<String> name() const { return raw_name_->string(); }
+ const AstString* raw_name() const { return raw_name_; }
+ void set_raw_name(const AstString* name) { raw_name_ = name; }
+ Scope* scope() const { return scope_; }
+ ZoneList<Statement*>* body() const { return body_; }
+ void set_function_token_position(int pos) { function_token_position_ = pos; }
+ int function_token_position() const { return function_token_position_; }
+ int start_position() const;
+ int end_position() const;
+ int SourceSize() const { return end_position() - start_position(); }
+ bool is_expression() const { return IsExpression::decode(bitfield_); }
+ bool is_anonymous() const { return IsAnonymous::decode(bitfield_); }
+ LanguageMode language_mode() const;
+
+ 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_; }
+
+ bool AllowsLazyCompilation();
+ bool AllowsLazyCompilationWithoutContext();
+
+ Handle<String> debug_name() const {
+ if (raw_name_ != NULL && !raw_name_->IsEmpty()) {
+ return raw_name_->string();
+ }
+ return inferred_name();
+ }
+
+ Handle<String> inferred_name() const {
+ if (!inferred_name_.is_null()) {
+ DCHECK(raw_inferred_name_ == NULL);
+ return inferred_name_;
+ }
+ if (raw_inferred_name_ != NULL) {
+ return raw_inferred_name_->string();
+ }
+ UNREACHABLE();
+ return Handle<String>();
+ }
+
+ // Only one of {set_inferred_name, set_raw_inferred_name} should be called.
+ void set_inferred_name(Handle<String> inferred_name) {
+ DCHECK(!inferred_name.is_null());
+ inferred_name_ = inferred_name;
+ DCHECK(raw_inferred_name_== NULL || raw_inferred_name_->IsEmpty());
+ raw_inferred_name_ = NULL;
+ }
+
+ void set_raw_inferred_name(const AstString* raw_inferred_name) {
+ DCHECK(raw_inferred_name != NULL);
+ raw_inferred_name_ = raw_inferred_name;
+ DCHECK(inferred_name_.is_null());
+ inferred_name_ = Handle<String>();
+ }
+
+ bool pretenure() const { return Pretenure::decode(bitfield_); }
+ void set_pretenure() { bitfield_ = Pretenure::update(bitfield_, true); }
+
+ bool has_duplicate_parameters() const {
+ return HasDuplicateParameters::decode(bitfield_);
+ }
+
+ bool is_function() const { return IsFunction::decode(bitfield_); }
+
+ // 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:
+ // - (function() { ... })();
+ // - var x = function() { ... }();
+ bool should_eager_compile() const {
+ return ShouldEagerCompile::decode(bitfield_);
+ }
+ void set_should_eager_compile() {
+ bitfield_ = ShouldEagerCompile::update(bitfield_, true);
+ }
+
+ // A hint that we expect this function to be called (exactly) once,
+ // i.e. we suspect it's an initialization function.
+ bool should_be_used_once_hint() const {
+ return ShouldBeUsedOnceHint::decode(bitfield_);
+ }
+ void set_should_be_used_once_hint() {
+ bitfield_ = ShouldBeUsedOnceHint::update(bitfield_, true);
+ }
+
+ FunctionKind kind() const { return FunctionKindBits::decode(bitfield_); }
+
+ int ast_node_count() { return ast_properties_.node_count(); }
+ AstProperties::Flags flags() const { return ast_properties_.flags(); }
+ void set_ast_properties(AstProperties* ast_properties) {
+ ast_properties_ = *ast_properties;
+ }
+ const FeedbackVectorSpec* feedback_vector_spec() const {
+ return ast_properties_.get_spec();
+ }
+ bool dont_optimize() { return dont_optimize_reason_ != kNoReason; }
+ BailoutReason dont_optimize_reason() { return dont_optimize_reason_; }
+ void set_dont_optimize_reason(BailoutReason reason) {
+ dont_optimize_reason_ = reason;
+ }
+
+ protected:
+ FunctionLiteral(Zone* zone, const AstString* name,
+ AstValueFactory* ast_value_factory, Scope* scope,
+ ZoneList<Statement*>* body, int materialized_literal_count,
+ int expected_property_count, int parameter_count,
+ FunctionType function_type,
+ ParameterFlag has_duplicate_parameters,
+ EagerCompileHint eager_compile_hint, FunctionKind kind,
+ int position)
+ : Expression(zone, position),
+ raw_name_(name),
+ scope_(scope),
+ body_(body),
+ raw_inferred_name_(ast_value_factory->empty_string()),
+ ast_properties_(zone),
+ dont_optimize_reason_(kNoReason),
+ materialized_literal_count_(materialized_literal_count),
+ expected_property_count_(expected_property_count),
+ parameter_count_(parameter_count),
+ function_token_position_(RelocInfo::kNoPosition) {
+ bitfield_ =
+ IsExpression::encode(function_type != kDeclaration) |
+ IsAnonymous::encode(function_type == kAnonymousExpression) |
+ Pretenure::encode(false) |
+ HasDuplicateParameters::encode(has_duplicate_parameters ==
+ kHasDuplicateParameters) |
+ IsFunction::encode(function_type != kGlobalOrEval) |
+ ShouldEagerCompile::encode(eager_compile_hint == kShouldEagerCompile) |
+ FunctionKindBits::encode(kind) | ShouldBeUsedOnceHint::encode(false);
+ DCHECK(IsValidFunctionKind(kind));
+ }
+
+ private:
+ class IsExpression : public BitField16<bool, 0, 1> {};
+ class IsAnonymous : public BitField16<bool, 1, 1> {};
+ class Pretenure : public BitField16<bool, 2, 1> {};
+ class HasDuplicateParameters : public BitField16<bool, 3, 1> {};
+ class IsFunction : public BitField16<bool, 4, 1> {};
+ class ShouldEagerCompile : public BitField16<bool, 5, 1> {};
+ class FunctionKindBits : public BitField16<FunctionKind, 6, 8> {};
+ class ShouldBeUsedOnceHint : public BitField16<bool, 15, 1> {};
+
+ // Start with 16-bit field, which should get packed together
+ // with Expression's trailing 16-bit field.
+ uint16_t bitfield_;
+
+ const AstString* raw_name_;
+ Scope* scope_;
+ ZoneList<Statement*>* body_;
+ const AstString* raw_inferred_name_;
+ Handle<String> inferred_name_;
+ AstProperties ast_properties_;
+ BailoutReason dont_optimize_reason_;
+
+ int materialized_literal_count_;
+ int expected_property_count_;
+ int parameter_count_;
+ int function_token_position_;
+};
+
+
+class ClassLiteral final : public Expression {
+ public:
+ typedef ObjectLiteralProperty Property;
+
+ DECLARE_NODE_TYPE(ClassLiteral)
+
+ Handle<String> name() const { return raw_name_->string(); }
+ const AstRawString* raw_name() const { return raw_name_; }
+ void set_raw_name(const AstRawString* name) {
+ DCHECK_NULL(raw_name_);
+ raw_name_ = name;
+ }
+
+ Scope* scope() const { return scope_; }
+ VariableProxy* class_variable_proxy() const { return class_variable_proxy_; }
+ Expression* extends() const { return extends_; }
+ void set_extends(Expression* e) { extends_ = e; }
+ FunctionLiteral* constructor() const { return constructor_; }
+ void set_constructor(FunctionLiteral* f) { constructor_ = f; }
+ ZoneList<Property*>* properties() const { return properties_; }
+ int start_position() const { return position(); }
+ int end_position() const { return end_position_; }
+
+ BailoutId EntryId() const { return BailoutId(local_id(0)); }
+ BailoutId DeclsId() const { return BailoutId(local_id(1)); }
+ BailoutId ExitId() { return BailoutId(local_id(2)); }
+ BailoutId CreateLiteralId() const { return BailoutId(local_id(3)); }
+
+ // Return an AST id for a property that is used in simulate instructions.
+ BailoutId GetIdForProperty(int i) { return BailoutId(local_id(i + 4)); }
+
+ // 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() + 4 + 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) override;
+
+ bool NeedsProxySlot() const {
+ return class_variable_proxy() != nullptr &&
+ class_variable_proxy()->var()->IsUnallocated();
+ }
+
+ FeedbackVectorSlot ProxySlot() const { return slot_; }
+
+ protected:
+ ClassLiteral(Zone* zone, const AstRawString* name, Scope* scope,
+ VariableProxy* class_variable_proxy, Expression* extends,
+ FunctionLiteral* constructor, ZoneList<Property*>* properties,
+ int start_position, int end_position)
+ : Expression(zone, start_position),
+ raw_name_(name),
+ scope_(scope),
+ class_variable_proxy_(class_variable_proxy),
+ extends_(extends),
+ constructor_(constructor),
+ properties_(properties),
+ end_position_(end_position) {}
+
+ static int parent_num_ids() { return Expression::num_ids(); }
+
+ private:
+ int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+
+ const AstRawString* raw_name_;
+ Scope* scope_;
+ VariableProxy* class_variable_proxy_;
+ Expression* extends_;
+ FunctionLiteral* constructor_;
+ ZoneList<Property*>* properties_;
+ int end_position_;
+ FeedbackVectorSlot slot_;
+};
+
+
+class NativeFunctionLiteral final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(NativeFunctionLiteral)
+
+ Handle<String> name() const { return name_->string(); }
+ v8::Extension* extension() const { return extension_; }
+
+ protected:
+ NativeFunctionLiteral(Zone* zone, const AstRawString* name,
+ v8::Extension* extension, int pos)
+ : Expression(zone, pos), name_(name), extension_(extension) {}
+
+ private:
+ const AstRawString* name_;
+ v8::Extension* extension_;
+};
+
+
+class ThisFunction final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(ThisFunction)
+
+ protected:
+ ThisFunction(Zone* zone, int pos) : Expression(zone, pos) {}
+};
+
+
+class SuperPropertyReference final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(SuperPropertyReference)
+
+ VariableProxy* this_var() const { return this_var_; }
+ void set_this_var(VariableProxy* v) { this_var_ = v; }
+ Expression* home_object() const { return home_object_; }
+ void set_home_object(Expression* e) { home_object_ = e; }
+
+ protected:
+ SuperPropertyReference(Zone* zone, VariableProxy* this_var,
+ Expression* home_object, int pos)
+ : Expression(zone, pos), this_var_(this_var), home_object_(home_object) {
+ DCHECK(this_var->is_this());
+ DCHECK(home_object->IsProperty());
+ }
+
+ private:
+ VariableProxy* this_var_;
+ Expression* home_object_;
+};
+
+
+class SuperCallReference final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(SuperCallReference)
+
+ VariableProxy* this_var() const { return this_var_; }
+ void set_this_var(VariableProxy* v) { this_var_ = v; }
+ VariableProxy* new_target_var() const { return new_target_var_; }
+ void set_new_target_var(VariableProxy* v) { new_target_var_ = v; }
+ VariableProxy* this_function_var() const { return this_function_var_; }
+ void set_this_function_var(VariableProxy* v) { this_function_var_ = v; }
+
+ protected:
+ SuperCallReference(Zone* zone, VariableProxy* this_var,
+ VariableProxy* new_target_var,
+ VariableProxy* this_function_var, int pos)
+ : Expression(zone, pos),
+ this_var_(this_var),
+ new_target_var_(new_target_var),
+ this_function_var_(this_function_var) {
+ DCHECK(this_var->is_this());
+ DCHECK(new_target_var->raw_name()->IsOneByteEqualTo(".new.target"));
+ DCHECK(this_function_var->raw_name()->IsOneByteEqualTo(".this_function"));
+ }
+
+ private:
+ VariableProxy* this_var_;
+ VariableProxy* new_target_var_;
+ VariableProxy* this_function_var_;
+};
+
+
+// This class is produced when parsing the () in arrow functions without any
+// arguments and is not actually a valid expression.
+class EmptyParentheses final : public Expression {
+ public:
+ DECLARE_NODE_TYPE(EmptyParentheses)
+
+ private:
+ EmptyParentheses(Zone* zone, int pos) : Expression(zone, pos) {}
+};
+
+
+#undef DECLARE_NODE_TYPE
+
+
+// ----------------------------------------------------------------------------
+// Basic visitor
+// - leaf node visitors are abstract.
+
+class AstVisitor BASE_EMBEDDED {
+ public:
+ AstVisitor() {}
+ virtual ~AstVisitor() {}
+
+ // Stack overflow check and dynamic dispatch.
+ virtual void Visit(AstNode* node) = 0;
+
+ // Iteration left-to-right.
+ virtual void VisitDeclarations(ZoneList<Declaration*>* declarations);
+ virtual void VisitStatements(ZoneList<Statement*>* statements);
+ virtual void VisitExpressions(ZoneList<Expression*>* expressions);
+
+ // Individual AST nodes.
+#define DEF_VISIT(type) \
+ virtual void Visit##type(type* node) = 0;
+ AST_NODE_LIST(DEF_VISIT)
+#undef DEF_VISIT
+};
+
+#define DEFINE_AST_VISITOR_SUBCLASS_MEMBERS() \
+ public: \
+ void Visit(AstNode* node) final { \
+ if (!CheckStackOverflow()) node->Accept(this); \
+ } \
+ \
+ void SetStackOverflow() { stack_overflow_ = true; } \
+ void ClearStackOverflow() { stack_overflow_ = false; } \
+ bool HasStackOverflow() const { return stack_overflow_; } \
+ \
+ bool CheckStackOverflow() { \
+ if (stack_overflow_) return true; \
+ if (GetCurrentStackPosition() < stack_limit_) { \
+ stack_overflow_ = true; \
+ return true; \
+ } \
+ return false; \
+ } \
+ \
+ private: \
+ void InitializeAstVisitor(Isolate* isolate) { \
+ stack_limit_ = isolate->stack_guard()->real_climit(); \
+ stack_overflow_ = false; \
+ } \
+ \
+ void InitializeAstVisitor(uintptr_t stack_limit) { \
+ stack_limit_ = stack_limit; \
+ stack_overflow_ = false; \
+ } \
+ \
+ uintptr_t stack_limit_; \
+ bool stack_overflow_
+
+#define DEFINE_AST_REWRITER_SUBCLASS_MEMBERS() \
+ public: \
+ AstNode* Rewrite(AstNode* node) { \
+ DCHECK_NULL(replacement_); \
+ DCHECK_NOT_NULL(node); \
+ Visit(node); \
+ if (HasStackOverflow()) return node; \
+ if (replacement_ == nullptr) return node; \
+ AstNode* result = replacement_; \
+ replacement_ = nullptr; \
+ return result; \
+ } \
+ \
+ private: \
+ void InitializeAstRewriter(Isolate* isolate) { \
+ InitializeAstVisitor(isolate); \
+ replacement_ = nullptr; \
+ } \
+ \
+ void InitializeAstRewriter(uintptr_t stack_limit) { \
+ InitializeAstVisitor(stack_limit); \
+ replacement_ = nullptr; \
+ } \
+ \
+ DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); \
+ \
+ protected: \
+ AstNode* replacement_
+
+// Generic macro for rewriting things; `GET` is the expression to be
+// rewritten; `SET` is a command that should do the rewriting, i.e.
+// something sensible with the variable called `replacement`.
+#define AST_REWRITE(Type, GET, SET) \
+ do { \
+ DCHECK(!HasStackOverflow()); \
+ DCHECK_NULL(replacement_); \
+ Visit(GET); \
+ if (HasStackOverflow()) return; \
+ if (replacement_ == nullptr) break; \
+ Type* replacement = reinterpret_cast<Type*>(replacement_); \
+ do { \
+ SET; \
+ } while (false); \
+ replacement_ = nullptr; \
+ } while (false)
+
+// Macro for rewriting object properties; it assumes that `object` has
+// `property` with a public getter and setter.
+#define AST_REWRITE_PROPERTY(Type, object, property) \
+ do { \
+ auto _obj = (object); \
+ AST_REWRITE(Type, _obj->property(), _obj->set_##property(replacement)); \
+ } while (false)
+
+// Macro for rewriting list elements; it assumes that `list` has methods
+// `at` and `Set`.
+#define AST_REWRITE_LIST_ELEMENT(Type, list, index) \
+ do { \
+ auto _list = (list); \
+ auto _index = (index); \
+ AST_REWRITE(Type, _list->at(_index), _list->Set(_index, replacement)); \
+ } while (false)
+
+
+// ----------------------------------------------------------------------------
+// AstNode factory
+
+class AstNodeFactory final BASE_EMBEDDED {
+ public:
+ explicit AstNodeFactory(AstValueFactory* ast_value_factory)
+ : local_zone_(ast_value_factory->zone()),
+ parser_zone_(ast_value_factory->zone()),
+ ast_value_factory_(ast_value_factory) {}
+
+ AstValueFactory* ast_value_factory() const { return ast_value_factory_; }
+
+ VariableDeclaration* NewVariableDeclaration(
+ VariableProxy* proxy, VariableMode mode, Scope* scope, int pos,
+ bool is_class_declaration = false, int declaration_group_start = -1) {
+ return new (parser_zone_)
+ VariableDeclaration(parser_zone_, proxy, mode, scope, pos,
+ is_class_declaration, declaration_group_start);
+ }
+
+ FunctionDeclaration* NewFunctionDeclaration(VariableProxy* proxy,
+ VariableMode mode,
+ FunctionLiteral* fun,
+ Scope* scope,
+ int pos) {
+ return new (parser_zone_)
+ FunctionDeclaration(parser_zone_, proxy, mode, fun, scope, pos);
+ }
+
+ ImportDeclaration* NewImportDeclaration(VariableProxy* proxy,
+ const AstRawString* import_name,
+ const AstRawString* module_specifier,
+ Scope* scope, int pos) {
+ return new (parser_zone_) ImportDeclaration(
+ parser_zone_, proxy, import_name, module_specifier, scope, pos);
+ }
+
+ ExportDeclaration* NewExportDeclaration(VariableProxy* proxy,
+ Scope* scope,
+ int pos) {
+ return new (parser_zone_)
+ ExportDeclaration(parser_zone_, proxy, scope, pos);
+ }
+
+ Block* NewBlock(ZoneList<const AstRawString*>* labels, int capacity,
+ bool ignore_completion_value, int pos) {
+ return new (local_zone_)
+ Block(local_zone_, labels, capacity, ignore_completion_value, pos);
+ }
+
+#define STATEMENT_WITH_LABELS(NodeType) \
+ NodeType* New##NodeType(ZoneList<const AstRawString*>* labels, int pos) { \
+ return new (local_zone_) NodeType(local_zone_, labels, pos); \
+ }
+ STATEMENT_WITH_LABELS(DoWhileStatement)
+ STATEMENT_WITH_LABELS(WhileStatement)
+ STATEMENT_WITH_LABELS(ForStatement)
+ STATEMENT_WITH_LABELS(SwitchStatement)
+#undef STATEMENT_WITH_LABELS
+
+ ForEachStatement* NewForEachStatement(ForEachStatement::VisitMode visit_mode,
+ ZoneList<const AstRawString*>* labels,
+ int pos) {
+ switch (visit_mode) {
+ case ForEachStatement::ENUMERATE: {
+ return new (local_zone_) ForInStatement(local_zone_, labels, pos);
+ }
+ case ForEachStatement::ITERATE: {
+ return new (local_zone_) ForOfStatement(local_zone_, labels, pos);
+ }
+ }
+ UNREACHABLE();
+ return NULL;
+ }
+
+ ExpressionStatement* NewExpressionStatement(Expression* expression, int pos) {
+ return new (local_zone_) ExpressionStatement(local_zone_, expression, pos);
+ }
+
+ ContinueStatement* NewContinueStatement(IterationStatement* target, int pos) {
+ return new (local_zone_) ContinueStatement(local_zone_, target, pos);
+ }
+
+ BreakStatement* NewBreakStatement(BreakableStatement* target, int pos) {
+ return new (local_zone_) BreakStatement(local_zone_, target, pos);
+ }
+
+ ReturnStatement* NewReturnStatement(Expression* expression, int pos) {
+ return new (local_zone_) ReturnStatement(local_zone_, expression, pos);
+ }
+
+ WithStatement* NewWithStatement(Scope* scope,
+ Expression* expression,
+ Statement* statement,
+ int pos) {
+ return new (local_zone_)
+ WithStatement(local_zone_, scope, expression, statement, pos);
+ }
+
+ IfStatement* NewIfStatement(Expression* condition,
+ Statement* then_statement,
+ Statement* else_statement,
+ int pos) {
+ return new (local_zone_) IfStatement(local_zone_, condition, then_statement,
+ else_statement, pos);
+ }
+
+ TryCatchStatement* NewTryCatchStatement(Block* try_block, Scope* scope,
+ Variable* variable,
+ Block* catch_block, int pos) {
+ return new (local_zone_) TryCatchStatement(local_zone_, try_block, scope,
+ variable, catch_block, pos);
+ }
+
+ TryFinallyStatement* NewTryFinallyStatement(Block* try_block,
+ Block* finally_block, int pos) {
+ return new (local_zone_)
+ TryFinallyStatement(local_zone_, try_block, finally_block, pos);
+ }
+
+ DebuggerStatement* NewDebuggerStatement(int pos) {
+ return new (local_zone_) DebuggerStatement(local_zone_, pos);
+ }
+
+ EmptyStatement* NewEmptyStatement(int pos) {
+ return new (local_zone_) EmptyStatement(local_zone_, pos);
+ }
+
+ SloppyBlockFunctionStatement* NewSloppyBlockFunctionStatement(
+ Statement* statement, Scope* scope) {
+ return new (parser_zone_)
+ SloppyBlockFunctionStatement(parser_zone_, statement, scope);
+ }
+
+ CaseClause* NewCaseClause(
+ Expression* label, ZoneList<Statement*>* statements, int pos) {
+ return new (local_zone_) CaseClause(local_zone_, label, statements, pos);
+ }
+
+ Literal* NewStringLiteral(const AstRawString* string, int pos) {
+ return new (local_zone_)
+ Literal(local_zone_, ast_value_factory_->NewString(string), pos);
+ }
+
+ // A JavaScript symbol (ECMA-262 edition 6).
+ Literal* NewSymbolLiteral(const char* name, int pos) {
+ return new (local_zone_)
+ Literal(local_zone_, ast_value_factory_->NewSymbol(name), pos);
+ }
+
+ Literal* NewNumberLiteral(double number, int pos, bool with_dot = false) {
+ return new (local_zone_) Literal(
+ local_zone_, ast_value_factory_->NewNumber(number, with_dot), pos);
+ }
+
+ Literal* NewSmiLiteral(int number, int pos) {
+ return new (local_zone_)
+ Literal(local_zone_, ast_value_factory_->NewSmi(number), pos);
+ }
+
+ Literal* NewBooleanLiteral(bool b, int pos) {
+ return new (local_zone_)
+ Literal(local_zone_, ast_value_factory_->NewBoolean(b), pos);
+ }
+
+ Literal* NewNullLiteral(int pos) {
+ return new (local_zone_)
+ Literal(local_zone_, ast_value_factory_->NewNull(), pos);
+ }
+
+ Literal* NewUndefinedLiteral(int pos) {
+ return new (local_zone_)
+ Literal(local_zone_, ast_value_factory_->NewUndefined(), pos);
+ }
+
+ Literal* NewTheHoleLiteral(int pos) {
+ return new (local_zone_)
+ Literal(local_zone_, ast_value_factory_->NewTheHole(), pos);
+ }
+
+ ObjectLiteral* NewObjectLiteral(
+ ZoneList<ObjectLiteral::Property*>* properties,
+ int literal_index,
+ int boilerplate_properties,
+ bool has_function,
+ bool is_strong,
+ int pos) {
+ return new (local_zone_)
+ ObjectLiteral(local_zone_, properties, literal_index,
+ boilerplate_properties, has_function, is_strong, pos);
+ }
+
+ ObjectLiteral::Property* NewObjectLiteralProperty(
+ Expression* key, Expression* value, ObjectLiteralProperty::Kind kind,
+ bool is_static, bool is_computed_name) {
+ return new (local_zone_)
+ ObjectLiteral::Property(key, value, kind, is_static, is_computed_name);
+ }
+
+ ObjectLiteral::Property* NewObjectLiteralProperty(Expression* key,
+ Expression* value,
+ bool is_static,
+ bool is_computed_name) {
+ return new (local_zone_) ObjectLiteral::Property(
+ ast_value_factory_, key, value, is_static, is_computed_name);
+ }
+
+ RegExpLiteral* NewRegExpLiteral(const AstRawString* pattern, int flags,
+ int literal_index, bool is_strong, int pos) {
+ return new (local_zone_) RegExpLiteral(local_zone_, pattern, flags,
+ literal_index, is_strong, pos);
+ }
+
+ ArrayLiteral* NewArrayLiteral(ZoneList<Expression*>* values,
+ int literal_index,
+ bool is_strong,
+ int pos) {
+ return new (local_zone_)
+ ArrayLiteral(local_zone_, values, -1, literal_index, is_strong, pos);
+ }
+
+ ArrayLiteral* NewArrayLiteral(ZoneList<Expression*>* values,
+ int first_spread_index, int literal_index,
+ bool is_strong, int pos) {
+ return new (local_zone_) ArrayLiteral(
+ local_zone_, values, first_spread_index, literal_index, is_strong, pos);
+ }
+
+ VariableProxy* NewVariableProxy(Variable* var,
+ int start_position = RelocInfo::kNoPosition,
+ int end_position = RelocInfo::kNoPosition) {
+ return new (parser_zone_)
+ VariableProxy(parser_zone_, var, start_position, end_position);
+ }
+
+ VariableProxy* NewVariableProxy(const AstRawString* name,
+ Variable::Kind variable_kind,
+ int start_position = RelocInfo::kNoPosition,
+ int end_position = RelocInfo::kNoPosition) {
+ DCHECK_NOT_NULL(name);
+ return new (parser_zone_) VariableProxy(parser_zone_, name, variable_kind,
+ start_position, end_position);
+ }
+
+ Property* NewProperty(Expression* obj, Expression* key, int pos) {
+ return new (local_zone_) Property(local_zone_, obj, key, pos);
+ }
+
+ Call* NewCall(Expression* expression,
+ ZoneList<Expression*>* arguments,
+ int pos) {
+ return new (local_zone_) Call(local_zone_, expression, arguments, pos);
+ }
+
+ CallNew* NewCallNew(Expression* expression,
+ ZoneList<Expression*>* arguments,
+ int pos) {
+ return new (local_zone_) CallNew(local_zone_, expression, arguments, pos);
+ }
+
+ CallRuntime* NewCallRuntime(Runtime::FunctionId id,
+ ZoneList<Expression*>* arguments, int pos) {
+ return new (local_zone_)
+ CallRuntime(local_zone_, Runtime::FunctionForId(id), arguments, pos);
+ }
+
+ CallRuntime* NewCallRuntime(const Runtime::Function* function,
+ ZoneList<Expression*>* arguments, int pos) {
+ return new (local_zone_) CallRuntime(local_zone_, function, arguments, pos);
+ }
+
+ CallRuntime* NewCallRuntime(int context_index,
+ ZoneList<Expression*>* arguments, int pos) {
+ return new (local_zone_)
+ CallRuntime(local_zone_, context_index, arguments, pos);
+ }
+
+ UnaryOperation* NewUnaryOperation(Token::Value op,
+ Expression* expression,
+ int pos) {
+ return new (local_zone_) UnaryOperation(local_zone_, op, expression, pos);
+ }
+
+ BinaryOperation* NewBinaryOperation(Token::Value op,
+ Expression* left,
+ Expression* right,
+ int pos) {
+ return new (local_zone_) BinaryOperation(local_zone_, op, left, right, pos);
+ }
+
+ CountOperation* NewCountOperation(Token::Value op,
+ bool is_prefix,
+ Expression* expr,
+ int pos) {
+ return new (local_zone_)
+ CountOperation(local_zone_, op, is_prefix, expr, pos);
+ }
+
+ CompareOperation* NewCompareOperation(Token::Value op,
+ Expression* left,
+ Expression* right,
+ int pos) {
+ return new (local_zone_)
+ CompareOperation(local_zone_, op, left, right, pos);
+ }
+
+ Spread* NewSpread(Expression* expression, int pos) {
+ return new (local_zone_) Spread(local_zone_, expression, pos);
+ }
+
+ Conditional* NewConditional(Expression* condition,
+ Expression* then_expression,
+ Expression* else_expression,
+ int position) {
+ return new (local_zone_) Conditional(
+ local_zone_, condition, then_expression, else_expression, position);
+ }
+
+ RewritableAssignmentExpression* NewRewritableAssignmentExpression(
+ Expression* expression) {
+ DCHECK_NOT_NULL(expression);
+ DCHECK(expression->IsAssignment());
+ return new (local_zone_)
+ RewritableAssignmentExpression(local_zone_, expression);
+ }
+
+ Assignment* NewAssignment(Token::Value op,
+ Expression* target,
+ Expression* value,
+ int pos) {
+ DCHECK(Token::IsAssignmentOp(op));
+ Assignment* assign =
+ new (local_zone_) Assignment(local_zone_, op, target, value, pos);
+ if (assign->is_compound()) {
+ DCHECK(Token::IsAssignmentOp(op));
+ assign->binary_operation_ =
+ NewBinaryOperation(assign->binary_op(), target, value, pos + 1);
+ }
+ return assign;
+ }
+
+ Yield* NewYield(Expression *generator_object,
+ Expression* expression,
+ Yield::Kind yield_kind,
+ int pos) {
+ if (!expression) expression = NewUndefinedLiteral(pos);
+ return new (local_zone_)
+ Yield(local_zone_, generator_object, expression, yield_kind, pos);
+ }
+
+ Throw* NewThrow(Expression* exception, int pos) {
+ return new (local_zone_) Throw(local_zone_, exception, pos);
+ }
+
+ FunctionLiteral* NewFunctionLiteral(
+ const AstRawString* name, Scope* scope, ZoneList<Statement*>* body,
+ int materialized_literal_count, int expected_property_count,
+ int parameter_count,
+ FunctionLiteral::ParameterFlag has_duplicate_parameters,
+ FunctionLiteral::FunctionType function_type,
+ FunctionLiteral::EagerCompileHint eager_compile_hint, FunctionKind kind,
+ int position) {
+ return new (parser_zone_) FunctionLiteral(
+ parser_zone_, name, ast_value_factory_, scope, body,
+ materialized_literal_count, expected_property_count, parameter_count,
+ function_type, has_duplicate_parameters, eager_compile_hint, kind,
+ position);
+ }
+
+ ClassLiteral* NewClassLiteral(const AstRawString* name, Scope* scope,
+ VariableProxy* proxy, Expression* extends,
+ FunctionLiteral* constructor,
+ ZoneList<ObjectLiteral::Property*>* properties,
+ int start_position, int end_position) {
+ return new (parser_zone_)
+ ClassLiteral(parser_zone_, name, scope, proxy, extends, constructor,
+ properties, start_position, end_position);
+ }
+
+ NativeFunctionLiteral* NewNativeFunctionLiteral(const AstRawString* name,
+ v8::Extension* extension,
+ int pos) {
+ return new (parser_zone_)
+ NativeFunctionLiteral(parser_zone_, name, extension, pos);
+ }
+
+ DoExpression* NewDoExpression(Block* block, Variable* result_var, int pos) {
+ VariableProxy* result = NewVariableProxy(result_var, pos);
+ return new (parser_zone_) DoExpression(parser_zone_, block, result, pos);
+ }
+
+ ThisFunction* NewThisFunction(int pos) {
+ return new (local_zone_) ThisFunction(local_zone_, pos);
+ }
+
+ SuperPropertyReference* NewSuperPropertyReference(VariableProxy* this_var,
+ Expression* home_object,
+ int pos) {
+ return new (parser_zone_)
+ SuperPropertyReference(parser_zone_, this_var, home_object, pos);
+ }
+
+ SuperCallReference* NewSuperCallReference(VariableProxy* this_var,
+ VariableProxy* new_target_var,
+ VariableProxy* this_function_var,
+ int pos) {
+ return new (parser_zone_) SuperCallReference(
+ parser_zone_, this_var, new_target_var, this_function_var, pos);
+ }
+
+ EmptyParentheses* NewEmptyParentheses(int pos) {
+ return new (local_zone_) EmptyParentheses(local_zone_, pos);
+ }
+
+ Zone* zone() const { return local_zone_; }
+
+ // Handles use of temporary zones when parsing inner function bodies.
+ class BodyScope {
+ public:
+ BodyScope(AstNodeFactory* factory, Zone* temp_zone, bool use_temp_zone)
+ : factory_(factory), prev_zone_(factory->local_zone_) {
+ if (use_temp_zone) {
+ factory->local_zone_ = temp_zone;
+ }
+ }
+
+ ~BodyScope() { factory_->local_zone_ = prev_zone_; }
+
+ private:
+ AstNodeFactory* factory_;
+ Zone* prev_zone_;
+ };
+
+ private:
+ // This zone may be deallocated upon returning from parsing a function body
+ // which we can guarantee is not going to be compiled or have its AST
+ // inspected.
+ // See ParseFunctionLiteral in parser.cc for preconditions.
+ Zone* local_zone_;
+ // ZoneObjects which need to persist until scope analysis must be allocated in
+ // the parser-level zone.
+ Zone* parser_zone_;
+ AstValueFactory* ast_value_factory_;
+};
+
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_AST_AST_H_
diff --git a/deps/v8/src/ast/modules.cc b/deps/v8/src/ast/modules.cc
new file mode 100644
index 0000000000..225cd8d62c
--- /dev/null
+++ b/deps/v8/src/ast/modules.cc
@@ -0,0 +1,59 @@
+// Copyright 2012 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/modules.h"
+
+#include "src/ast/ast-value-factory.h"
+
+namespace v8 {
+namespace internal {
+
+
+void ModuleDescriptor::AddLocalExport(const AstRawString* export_name,
+ const AstRawString* local_name,
+ Zone* zone, bool* ok) {
+ DCHECK(!IsFrozen());
+ void* key = const_cast<AstRawString*>(export_name);
+
+ ZoneAllocationPolicy allocator(zone);
+
+ if (exports_ == nullptr) {
+ exports_ = new (zone->New(sizeof(ZoneHashMap)))
+ ZoneHashMap(ZoneHashMap::PointersMatch,
+ ZoneHashMap::kDefaultHashMapCapacity, allocator);
+ }
+
+ ZoneHashMap::Entry* p =
+ exports_->LookupOrInsert(key, export_name->hash(), allocator);
+ DCHECK_NOT_NULL(p);
+ if (p->value != nullptr) {
+ // Duplicate export.
+ *ok = false;
+ return;
+ }
+
+ p->value = const_cast<AstRawString*>(local_name);
+}
+
+
+void ModuleDescriptor::AddModuleRequest(const AstRawString* module_specifier,
+ Zone* zone) {
+ // TODO(adamk): Avoid this O(N) operation on each insert by storing
+ // a HashMap, or by de-duping after parsing.
+ if (requested_modules_.Contains(module_specifier)) return;
+ requested_modules_.Add(module_specifier, zone);
+}
+
+
+const AstRawString* ModuleDescriptor::LookupLocalExport(
+ const AstRawString* export_name, Zone* zone) {
+ if (exports_ == nullptr) return nullptr;
+ ZoneHashMap::Entry* entry = exports_->Lookup(
+ const_cast<AstRawString*>(export_name), export_name->hash());
+ if (entry == nullptr) return nullptr;
+ DCHECK_NOT_NULL(entry->value);
+ return static_cast<const AstRawString*>(entry->value);
+}
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/ast/modules.h b/deps/v8/src/ast/modules.h
new file mode 100644
index 0000000000..e3c66dce94
--- /dev/null
+++ b/deps/v8/src/ast/modules.h
@@ -0,0 +1,121 @@
+// Copyright 2012 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_MODULES_H_
+#define V8_AST_MODULES_H_
+
+#include "src/zone.h"
+
+namespace v8 {
+namespace internal {
+
+
+class AstRawString;
+
+
+class ModuleDescriptor : public ZoneObject {
+ public:
+ // ---------------------------------------------------------------------------
+ // Factory methods.
+
+ static ModuleDescriptor* New(Zone* zone) {
+ return new (zone) ModuleDescriptor(zone);
+ }
+
+ // ---------------------------------------------------------------------------
+ // Mutators.
+
+ // Add a name to the list of exports. If it already exists, or this descriptor
+ // is frozen, that's an error.
+ void AddLocalExport(const AstRawString* export_name,
+ const AstRawString* local_name, Zone* zone, bool* ok);
+
+ // Add module_specifier to the list of requested modules,
+ // if not already present.
+ void AddModuleRequest(const AstRawString* module_specifier, Zone* zone);
+
+ // Do not allow any further refinements, directly or through unification.
+ void Freeze() { frozen_ = true; }
+
+ // Assign an index.
+ void Allocate(int index) {
+ DCHECK(IsFrozen() && index_ == -1);
+ index_ = index;
+ }
+
+ // ---------------------------------------------------------------------------
+ // Accessors.
+
+ // Check whether this is closed (i.e. fully determined).
+ bool IsFrozen() { return frozen_; }
+
+ int Length() {
+ DCHECK(IsFrozen());
+ ZoneHashMap* exports = exports_;
+ return exports ? exports->occupancy() : 0;
+ }
+
+ // The context slot in the hosting script context pointing to this module.
+ int Index() {
+ DCHECK(IsFrozen());
+ return index_;
+ }
+
+ const AstRawString* LookupLocalExport(const AstRawString* export_name,
+ Zone* zone);
+
+ const ZoneList<const AstRawString*>& requested_modules() const {
+ return requested_modules_;
+ }
+
+ // ---------------------------------------------------------------------------
+ // Iterators.
+
+ // Use like:
+ // for (auto it = descriptor->iterator(); !it.done(); it.Advance()) {
+ // ... it.name() ...
+ // }
+ class Iterator {
+ public:
+ bool done() const { return entry_ == NULL; }
+ const AstRawString* export_name() const {
+ DCHECK(!done());
+ return static_cast<const AstRawString*>(entry_->key);
+ }
+ const AstRawString* local_name() const {
+ DCHECK(!done());
+ return static_cast<const AstRawString*>(entry_->value);
+ }
+ void Advance() { entry_ = exports_->Next(entry_); }
+
+ private:
+ friend class ModuleDescriptor;
+ explicit Iterator(const ZoneHashMap* exports)
+ : exports_(exports), entry_(exports ? exports->Start() : NULL) {}
+
+ const ZoneHashMap* exports_;
+ ZoneHashMap::Entry* entry_;
+ };
+
+ Iterator iterator() const { return Iterator(this->exports_); }
+
+ // ---------------------------------------------------------------------------
+ // Implementation.
+ private:
+ explicit ModuleDescriptor(Zone* zone)
+ : frozen_(false),
+ exports_(NULL),
+ requested_modules_(1, zone),
+ index_(-1) {}
+
+ bool frozen_;
+ ZoneHashMap* exports_; // Module exports and their types (allocated lazily)
+ ZoneList<const AstRawString*> requested_modules_;
+ int index_;
+};
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_AST_MODULES_H_
diff --git a/deps/v8/src/ast/prettyprinter.cc b/deps/v8/src/ast/prettyprinter.cc
new file mode 100644
index 0000000000..1f6b8c31de
--- /dev/null
+++ b/deps/v8/src/ast/prettyprinter.cc
@@ -0,0 +1,1698 @@
+// Copyright 2012 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/prettyprinter.h"
+
+#include <stdarg.h>
+
+#include "src/ast/ast-value-factory.h"
+#include "src/ast/scopes.h"
+#include "src/base/platform/platform.h"
+
+namespace v8 {
+namespace internal {
+
+CallPrinter::CallPrinter(Isolate* isolate, bool is_builtin) {
+ output_ = NULL;
+ size_ = 0;
+ pos_ = 0;
+ position_ = 0;
+ found_ = false;
+ done_ = false;
+ is_builtin_ = is_builtin;
+ InitializeAstVisitor(isolate);
+}
+
+
+CallPrinter::~CallPrinter() { DeleteArray(output_); }
+
+
+const char* CallPrinter::Print(FunctionLiteral* program, int position) {
+ Init();
+ position_ = position;
+ Find(program);
+ return output_;
+}
+
+
+void CallPrinter::Find(AstNode* node, bool print) {
+ if (done_) return;
+ if (found_) {
+ if (print) {
+ int start = pos_;
+ Visit(node);
+ if (start != pos_) return;
+ }
+ Print("(intermediate value)");
+ } else {
+ Visit(node);
+ }
+}
+
+
+void CallPrinter::Init() {
+ if (size_ == 0) {
+ DCHECK(output_ == NULL);
+ const int initial_size = 256;
+ output_ = NewArray<char>(initial_size);
+ size_ = initial_size;
+ }
+ output_[0] = '\0';
+ pos_ = 0;
+}
+
+
+void CallPrinter::Print(const char* format, ...) {
+ if (!found_ || done_) return;
+ for (;;) {
+ va_list arguments;
+ va_start(arguments, format);
+ int n = VSNPrintF(Vector<char>(output_, size_) + pos_, format, arguments);
+ va_end(arguments);
+
+ if (n >= 0) {
+ // there was enough space - we are done
+ pos_ += n;
+ return;
+ } else {
+ // there was not enough space - allocate more and try again
+ const int slack = 32;
+ int new_size = size_ + (size_ >> 1) + slack;
+ char* new_output = NewArray<char>(new_size);
+ MemCopy(new_output, output_, pos_);
+ DeleteArray(output_);
+ output_ = new_output;
+ size_ = new_size;
+ }
+ }
+}
+
+
+void CallPrinter::VisitBlock(Block* node) {
+ FindStatements(node->statements());
+}
+
+
+void CallPrinter::VisitVariableDeclaration(VariableDeclaration* node) {}
+
+
+void CallPrinter::VisitFunctionDeclaration(FunctionDeclaration* node) {}
+
+
+void CallPrinter::VisitImportDeclaration(ImportDeclaration* node) {
+}
+
+
+void CallPrinter::VisitExportDeclaration(ExportDeclaration* node) {}
+
+
+void CallPrinter::VisitExpressionStatement(ExpressionStatement* node) {
+ Find(node->expression());
+}
+
+
+void CallPrinter::VisitEmptyStatement(EmptyStatement* node) {}
+
+
+void CallPrinter::VisitSloppyBlockFunctionStatement(
+ SloppyBlockFunctionStatement* node) {
+ Find(node->statement());
+}
+
+
+void CallPrinter::VisitIfStatement(IfStatement* node) {
+ Find(node->condition());
+ Find(node->then_statement());
+ if (node->HasElseStatement()) {
+ Find(node->else_statement());
+ }
+}
+
+
+void CallPrinter::VisitContinueStatement(ContinueStatement* node) {}
+
+
+void CallPrinter::VisitBreakStatement(BreakStatement* node) {}
+
+
+void CallPrinter::VisitReturnStatement(ReturnStatement* node) {
+ Find(node->expression());
+}
+
+
+void CallPrinter::VisitWithStatement(WithStatement* node) {
+ Find(node->expression());
+ Find(node->statement());
+}
+
+
+void CallPrinter::VisitSwitchStatement(SwitchStatement* node) {
+ Find(node->tag());
+ ZoneList<CaseClause*>* cases = node->cases();
+ for (int i = 0; i < cases->length(); i++) Find(cases->at(i));
+}
+
+
+void CallPrinter::VisitCaseClause(CaseClause* clause) {
+ if (!clause->is_default()) {
+ Find(clause->label());
+ }
+ FindStatements(clause->statements());
+}
+
+
+void CallPrinter::VisitDoWhileStatement(DoWhileStatement* node) {
+ Find(node->body());
+ Find(node->cond());
+}
+
+
+void CallPrinter::VisitWhileStatement(WhileStatement* node) {
+ Find(node->cond());
+ Find(node->body());
+}
+
+
+void CallPrinter::VisitForStatement(ForStatement* node) {
+ if (node->init() != NULL) {
+ Find(node->init());
+ }
+ if (node->cond() != NULL) Find(node->cond());
+ if (node->next() != NULL) Find(node->next());
+ Find(node->body());
+}
+
+
+void CallPrinter::VisitForInStatement(ForInStatement* node) {
+ Find(node->each());
+ Find(node->enumerable());
+ Find(node->body());
+}
+
+
+void CallPrinter::VisitForOfStatement(ForOfStatement* node) {
+ Find(node->each());
+ Find(node->assign_iterator());
+ Find(node->body());
+ Find(node->next_result());
+}
+
+
+void CallPrinter::VisitTryCatchStatement(TryCatchStatement* node) {
+ Find(node->try_block());
+ Find(node->catch_block());
+}
+
+
+void CallPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) {
+ Find(node->try_block());
+ Find(node->finally_block());
+}
+
+
+void CallPrinter::VisitDebuggerStatement(DebuggerStatement* node) {}
+
+
+void CallPrinter::VisitFunctionLiteral(FunctionLiteral* node) {
+ FindStatements(node->body());
+}
+
+
+void CallPrinter::VisitClassLiteral(ClassLiteral* node) {
+ if (node->extends()) Find(node->extends());
+ for (int i = 0; i < node->properties()->length(); i++) {
+ Find(node->properties()->at(i)->value());
+ }
+}
+
+
+void CallPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) {}
+
+
+void CallPrinter::VisitDoExpression(DoExpression* node) { Find(node->block()); }
+
+
+void CallPrinter::VisitConditional(Conditional* node) {
+ Find(node->condition());
+ Find(node->then_expression());
+ Find(node->else_expression());
+}
+
+
+void CallPrinter::VisitLiteral(Literal* node) {
+ PrintLiteral(*node->value(), true);
+}
+
+
+void CallPrinter::VisitRegExpLiteral(RegExpLiteral* node) {
+ Print("/");
+ PrintLiteral(*node->pattern(), false);
+ Print("/");
+ if (node->flags() & RegExp::kGlobal) Print("g");
+ if (node->flags() & RegExp::kIgnoreCase) Print("i");
+ if (node->flags() & RegExp::kMultiline) Print("m");
+ if (node->flags() & RegExp::kUnicode) Print("u");
+ if (node->flags() & RegExp::kSticky) Print("y");
+}
+
+
+void CallPrinter::VisitObjectLiteral(ObjectLiteral* node) {
+ for (int i = 0; i < node->properties()->length(); i++) {
+ Find(node->properties()->at(i)->value());
+ }
+}
+
+
+void CallPrinter::VisitArrayLiteral(ArrayLiteral* node) {
+ Print("[");
+ for (int i = 0; i < node->values()->length(); i++) {
+ if (i != 0) Print(",");
+ Find(node->values()->at(i), true);
+ }
+ Print("]");
+}
+
+
+void CallPrinter::VisitVariableProxy(VariableProxy* node) {
+ if (is_builtin_) {
+ // Variable names of builtins are meaningless due to minification.
+ Print("(var)");
+ } else {
+ PrintLiteral(*node->name(), false);
+ }
+}
+
+
+void CallPrinter::VisitAssignment(Assignment* node) {
+ Find(node->target());
+ Find(node->value());
+}
+
+
+void CallPrinter::VisitYield(Yield* node) { Find(node->expression()); }
+
+
+void CallPrinter::VisitThrow(Throw* node) { Find(node->exception()); }
+
+
+void CallPrinter::VisitProperty(Property* node) {
+ Expression* key = node->key();
+ Literal* literal = key->AsLiteral();
+ if (literal != NULL && literal->value()->IsInternalizedString()) {
+ Find(node->obj(), true);
+ Print(".");
+ PrintLiteral(*literal->value(), false);
+ } else {
+ Find(node->obj(), true);
+ Print("[");
+ Find(key, true);
+ Print("]");
+ }
+}
+
+
+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()) {
+ done_ = true;
+ return;
+ }
+ found_ = true;
+ }
+ Find(node->expression(), true);
+ if (!was_found) Print("(...)");
+ FindArguments(node->arguments());
+ if (was_found) done_ = true;
+}
+
+
+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()) {
+ done_ = true;
+ return;
+ }
+ found_ = true;
+ }
+ Find(node->expression(), was_found);
+ FindArguments(node->arguments());
+ if (was_found) done_ = true;
+}
+
+
+void CallPrinter::VisitCallRuntime(CallRuntime* node) {
+ FindArguments(node->arguments());
+}
+
+
+void CallPrinter::VisitUnaryOperation(UnaryOperation* node) {
+ Token::Value op = node->op();
+ bool needsSpace =
+ op == Token::DELETE || op == Token::TYPEOF || op == Token::VOID;
+ Print("(%s%s", Token::String(op), needsSpace ? " " : "");
+ Find(node->expression(), true);
+ Print(")");
+}
+
+
+void CallPrinter::VisitCountOperation(CountOperation* node) {
+ Print("(");
+ if (node->is_prefix()) Print("%s", Token::String(node->op()));
+ Find(node->expression(), true);
+ if (node->is_postfix()) Print("%s", Token::String(node->op()));
+ Print(")");
+}
+
+
+void CallPrinter::VisitBinaryOperation(BinaryOperation* node) {
+ Print("(");
+ Find(node->left(), true);
+ Print(" %s ", Token::String(node->op()));
+ Find(node->right(), true);
+ Print(")");
+}
+
+
+void CallPrinter::VisitCompareOperation(CompareOperation* node) {
+ Print("(");
+ Find(node->left(), true);
+ Print(" %s ", Token::String(node->op()));
+ Find(node->right(), true);
+ Print(")");
+}
+
+
+void CallPrinter::VisitSpread(Spread* node) {
+ Print("(...");
+ Find(node->expression(), true);
+ Print(")");
+}
+
+
+void CallPrinter::VisitEmptyParentheses(EmptyParentheses* node) {
+ UNREACHABLE();
+}
+
+
+void CallPrinter::VisitThisFunction(ThisFunction* node) {}
+
+
+void CallPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) {}
+
+
+void CallPrinter::VisitSuperCallReference(SuperCallReference* node) {
+ Print("super");
+}
+
+
+void CallPrinter::VisitRewritableAssignmentExpression(
+ RewritableAssignmentExpression* node) {
+ Find(node->expression());
+}
+
+
+void CallPrinter::FindStatements(ZoneList<Statement*>* statements) {
+ if (statements == NULL) return;
+ for (int i = 0; i < statements->length(); i++) {
+ Find(statements->at(i));
+ }
+}
+
+
+void CallPrinter::FindArguments(ZoneList<Expression*>* arguments) {
+ if (found_) return;
+ for (int i = 0; i < arguments->length(); i++) {
+ Find(arguments->at(i));
+ }
+}
+
+
+void CallPrinter::PrintLiteral(Object* value, bool quote) {
+ Object* object = value;
+ if (object->IsString()) {
+ if (quote) Print("\"");
+ Print("%s", String::cast(object)->ToCString().get());
+ if (quote) Print("\"");
+ } else if (object->IsNull()) {
+ Print("null");
+ } else if (object->IsTrue()) {
+ Print("true");
+ } else if (object->IsFalse()) {
+ Print("false");
+ } else if (object->IsUndefined()) {
+ Print("undefined");
+ } else if (object->IsNumber()) {
+ Print("%g", object->Number());
+ } else if (object->IsSymbol()) {
+ // Symbols can only occur as literals if they were inserted by the parser.
+ PrintLiteral(Symbol::cast(object)->name(), false);
+ }
+}
+
+
+void CallPrinter::PrintLiteral(const AstRawString* value, bool quote) {
+ PrintLiteral(*value->string(), quote);
+}
+
+
+//-----------------------------------------------------------------------------
+
+
+#ifdef DEBUG
+
+// A helper for ast nodes that use FeedbackVectorSlots.
+static int FormatSlotNode(Vector<char>* buf, Expression* node,
+ const char* node_name, FeedbackVectorSlot slot) {
+ int pos = SNPrintF(*buf, "%s", node_name);
+ if (!slot.IsInvalid()) {
+ pos = SNPrintF(*buf + pos, " Slot(%d)", slot.ToInt());
+ }
+ return pos;
+}
+
+
+PrettyPrinter::PrettyPrinter(Isolate* isolate) {
+ output_ = NULL;
+ size_ = 0;
+ pos_ = 0;
+ InitializeAstVisitor(isolate);
+}
+
+
+PrettyPrinter::~PrettyPrinter() {
+ DeleteArray(output_);
+}
+
+
+void PrettyPrinter::VisitBlock(Block* node) {
+ if (!node->ignore_completion_value()) Print("{ ");
+ PrintStatements(node->statements());
+ if (node->statements()->length() > 0) Print(" ");
+ if (!node->ignore_completion_value()) Print("}");
+}
+
+
+void PrettyPrinter::VisitVariableDeclaration(VariableDeclaration* node) {
+ Print("var ");
+ PrintLiteral(node->proxy()->name(), false);
+ Print(";");
+}
+
+
+void PrettyPrinter::VisitFunctionDeclaration(FunctionDeclaration* node) {
+ Print("function ");
+ PrintLiteral(node->proxy()->name(), false);
+ Print(" = ");
+ PrintFunctionLiteral(node->fun());
+ Print(";");
+}
+
+
+void PrettyPrinter::VisitImportDeclaration(ImportDeclaration* node) {
+ Print("import ");
+ PrintLiteral(node->proxy()->name(), false);
+ Print(" from ");
+ PrintLiteral(node->module_specifier()->string(), true);
+ Print(";");
+}
+
+
+void PrettyPrinter::VisitExportDeclaration(ExportDeclaration* node) {
+ Print("export ");
+ PrintLiteral(node->proxy()->name(), false);
+ Print(";");
+}
+
+
+void PrettyPrinter::VisitExpressionStatement(ExpressionStatement* node) {
+ Visit(node->expression());
+ Print(";");
+}
+
+
+void PrettyPrinter::VisitEmptyStatement(EmptyStatement* node) {
+ Print(";");
+}
+
+
+void PrettyPrinter::VisitSloppyBlockFunctionStatement(
+ SloppyBlockFunctionStatement* node) {
+ Visit(node->statement());
+}
+
+
+void PrettyPrinter::VisitIfStatement(IfStatement* node) {
+ Print("if (");
+ Visit(node->condition());
+ Print(") ");
+ Visit(node->then_statement());
+ if (node->HasElseStatement()) {
+ Print(" else ");
+ Visit(node->else_statement());
+ }
+}
+
+
+void PrettyPrinter::VisitContinueStatement(ContinueStatement* node) {
+ Print("continue");
+ ZoneList<const AstRawString*>* labels = node->target()->labels();
+ if (labels != NULL) {
+ Print(" ");
+ DCHECK(labels->length() > 0); // guaranteed to have at least one entry
+ PrintLiteral(labels->at(0), false); // any label from the list is fine
+ }
+ Print(";");
+}
+
+
+void PrettyPrinter::VisitBreakStatement(BreakStatement* node) {
+ Print("break");
+ ZoneList<const AstRawString*>* labels = node->target()->labels();
+ if (labels != NULL) {
+ Print(" ");
+ DCHECK(labels->length() > 0); // guaranteed to have at least one entry
+ PrintLiteral(labels->at(0), false); // any label from the list is fine
+ }
+ Print(";");
+}
+
+
+void PrettyPrinter::VisitReturnStatement(ReturnStatement* node) {
+ Print("return ");
+ Visit(node->expression());
+ Print(";");
+}
+
+
+void PrettyPrinter::VisitWithStatement(WithStatement* node) {
+ Print("with (");
+ Visit(node->expression());
+ Print(") ");
+ Visit(node->statement());
+}
+
+
+void PrettyPrinter::VisitSwitchStatement(SwitchStatement* node) {
+ PrintLabels(node->labels());
+ Print("switch (");
+ Visit(node->tag());
+ Print(") { ");
+ ZoneList<CaseClause*>* cases = node->cases();
+ for (int i = 0; i < cases->length(); i++)
+ Visit(cases->at(i));
+ Print("}");
+}
+
+
+void PrettyPrinter::VisitCaseClause(CaseClause* clause) {
+ if (clause->is_default()) {
+ Print("default");
+ } else {
+ Print("case ");
+ Visit(clause->label());
+ }
+ Print(": ");
+ PrintStatements(clause->statements());
+ if (clause->statements()->length() > 0)
+ Print(" ");
+}
+
+
+void PrettyPrinter::VisitDoWhileStatement(DoWhileStatement* node) {
+ PrintLabels(node->labels());
+ Print("do ");
+ Visit(node->body());
+ Print(" while (");
+ Visit(node->cond());
+ Print(");");
+}
+
+
+void PrettyPrinter::VisitWhileStatement(WhileStatement* node) {
+ PrintLabels(node->labels());
+ Print("while (");
+ Visit(node->cond());
+ Print(") ");
+ Visit(node->body());
+}
+
+
+void PrettyPrinter::VisitForStatement(ForStatement* node) {
+ PrintLabels(node->labels());
+ Print("for (");
+ if (node->init() != NULL) {
+ Visit(node->init());
+ Print(" ");
+ } else {
+ Print("; ");
+ }
+ if (node->cond() != NULL) Visit(node->cond());
+ Print("; ");
+ if (node->next() != NULL) {
+ Visit(node->next()); // prints extra ';', unfortunately
+ // to fix: should use Expression for next
+ }
+ Print(") ");
+ Visit(node->body());
+}
+
+
+void PrettyPrinter::VisitForInStatement(ForInStatement* node) {
+ PrintLabels(node->labels());
+ Print("for (");
+ Visit(node->each());
+ Print(" in ");
+ Visit(node->enumerable());
+ Print(") ");
+ Visit(node->body());
+}
+
+
+void PrettyPrinter::VisitForOfStatement(ForOfStatement* node) {
+ PrintLabels(node->labels());
+ Print("for (");
+ Visit(node->each());
+ Print(" of ");
+ Visit(node->iterable());
+ Print(") ");
+ Visit(node->body());
+}
+
+
+void PrettyPrinter::VisitTryCatchStatement(TryCatchStatement* node) {
+ Print("try ");
+ Visit(node->try_block());
+ Print(" catch (");
+ const bool quote = false;
+ PrintLiteral(node->variable()->name(), quote);
+ Print(") ");
+ Visit(node->catch_block());
+}
+
+
+void PrettyPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) {
+ Print("try ");
+ Visit(node->try_block());
+ Print(" finally ");
+ Visit(node->finally_block());
+}
+
+
+void PrettyPrinter::VisitDebuggerStatement(DebuggerStatement* node) {
+ Print("debugger ");
+}
+
+
+void PrettyPrinter::VisitFunctionLiteral(FunctionLiteral* node) {
+ Print("(");
+ PrintFunctionLiteral(node);
+ Print(")");
+}
+
+
+void PrettyPrinter::VisitClassLiteral(ClassLiteral* node) {
+ Print("(class ");
+ PrintLiteral(node->name(), false);
+ if (node->extends()) {
+ Print(" extends ");
+ Visit(node->extends());
+ }
+ Print(" { ");
+ for (int i = 0; i < node->properties()->length(); i++) {
+ PrintObjectLiteralProperty(node->properties()->at(i));
+ }
+ Print(" })");
+}
+
+
+void PrettyPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) {
+ Print("(");
+ PrintLiteral(node->name(), false);
+ Print(")");
+}
+
+
+void PrettyPrinter::VisitDoExpression(DoExpression* node) {
+ Print("(do {");
+ PrintStatements(node->block()->statements());
+ Print("})");
+}
+
+
+void PrettyPrinter::VisitConditional(Conditional* node) {
+ Visit(node->condition());
+ Print(" ? ");
+ Visit(node->then_expression());
+ Print(" : ");
+ Visit(node->else_expression());
+}
+
+
+void PrettyPrinter::VisitLiteral(Literal* node) {
+ PrintLiteral(node->value(), true);
+}
+
+
+void PrettyPrinter::VisitRegExpLiteral(RegExpLiteral* node) {
+ Print(" RegExp(");
+ PrintLiteral(node->pattern(), false);
+ Print(",");
+ if (node->flags() & RegExp::kGlobal) Print("g");
+ if (node->flags() & RegExp::kIgnoreCase) Print("i");
+ if (node->flags() & RegExp::kMultiline) Print("m");
+ if (node->flags() & RegExp::kUnicode) Print("u");
+ if (node->flags() & RegExp::kSticky) Print("y");
+ Print(") ");
+}
+
+
+void PrettyPrinter::VisitObjectLiteral(ObjectLiteral* node) {
+ Print("{ ");
+ for (int i = 0; i < node->properties()->length(); i++) {
+ if (i != 0) Print(",");
+ PrintObjectLiteralProperty(node->properties()->at(i));
+ }
+ Print(" }");
+}
+
+
+void PrettyPrinter::PrintObjectLiteralProperty(
+ ObjectLiteralProperty* property) {
+ // TODO(arv): Better printing of methods etc.
+ Print(" ");
+ Visit(property->key());
+ Print(": ");
+ Visit(property->value());
+}
+
+
+void PrettyPrinter::VisitArrayLiteral(ArrayLiteral* node) {
+ Print("[ ");
+ Print(" literal_index = %d", node->literal_index());
+ for (int i = 0; i < node->values()->length(); i++) {
+ if (i != 0) Print(",");
+ Visit(node->values()->at(i));
+ }
+ Print(" ]");
+}
+
+
+void PrettyPrinter::VisitVariableProxy(VariableProxy* node) {
+ PrintLiteral(node->name(), false);
+}
+
+
+void PrettyPrinter::VisitAssignment(Assignment* node) {
+ Visit(node->target());
+ Print(" %s ", Token::String(node->op()));
+ Visit(node->value());
+}
+
+
+void PrettyPrinter::VisitYield(Yield* node) {
+ Print("yield ");
+ Visit(node->expression());
+}
+
+
+void PrettyPrinter::VisitThrow(Throw* node) {
+ Print("throw ");
+ Visit(node->exception());
+}
+
+
+void PrettyPrinter::VisitProperty(Property* node) {
+ Expression* key = node->key();
+ Literal* literal = key->AsLiteral();
+ if (literal != NULL && literal->value()->IsInternalizedString()) {
+ Print("(");
+ Visit(node->obj());
+ Print(").");
+ PrintLiteral(literal->value(), false);
+ } else {
+ Visit(node->obj());
+ Print("[");
+ Visit(key);
+ Print("]");
+ }
+}
+
+
+void PrettyPrinter::VisitCall(Call* node) {
+ Visit(node->expression());
+ PrintArguments(node->arguments());
+}
+
+
+void PrettyPrinter::VisitCallNew(CallNew* node) {
+ Print("new (");
+ Visit(node->expression());
+ Print(")");
+ PrintArguments(node->arguments());
+}
+
+
+void PrettyPrinter::VisitCallRuntime(CallRuntime* node) {
+ Print("%%%s\n", node->debug_name());
+ PrintArguments(node->arguments());
+}
+
+
+void PrettyPrinter::VisitUnaryOperation(UnaryOperation* node) {
+ Token::Value op = node->op();
+ bool needsSpace =
+ op == Token::DELETE || op == Token::TYPEOF || op == Token::VOID;
+ Print("(%s%s", Token::String(op), needsSpace ? " " : "");
+ Visit(node->expression());
+ Print(")");
+}
+
+
+void PrettyPrinter::VisitCountOperation(CountOperation* node) {
+ Print("(");
+ if (node->is_prefix()) Print("%s", Token::String(node->op()));
+ Visit(node->expression());
+ if (node->is_postfix()) Print("%s", Token::String(node->op()));
+ Print(")");
+}
+
+
+void PrettyPrinter::VisitBinaryOperation(BinaryOperation* node) {
+ Print("(");
+ Visit(node->left());
+ Print(" %s ", Token::String(node->op()));
+ Visit(node->right());
+ Print(")");
+}
+
+
+void PrettyPrinter::VisitCompareOperation(CompareOperation* node) {
+ Print("(");
+ Visit(node->left());
+ Print(" %s ", Token::String(node->op()));
+ Visit(node->right());
+ Print(")");
+}
+
+
+void PrettyPrinter::VisitSpread(Spread* node) {
+ Print("(...");
+ Visit(node->expression());
+ Print(")");
+}
+
+
+void PrettyPrinter::VisitEmptyParentheses(EmptyParentheses* node) {
+ Print("()");
+}
+
+
+void PrettyPrinter::VisitThisFunction(ThisFunction* node) {
+ Print("<this-function>");
+}
+
+
+void PrettyPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) {
+ Print("<super-property-reference>");
+}
+
+
+void PrettyPrinter::VisitSuperCallReference(SuperCallReference* node) {
+ Print("<super-call-reference>");
+}
+
+
+void PrettyPrinter::VisitRewritableAssignmentExpression(
+ RewritableAssignmentExpression* node) {
+ Visit(node->expression());
+}
+
+
+const char* PrettyPrinter::Print(AstNode* node) {
+ Init();
+ Visit(node);
+ return output_;
+}
+
+
+const char* PrettyPrinter::PrintExpression(FunctionLiteral* program) {
+ Init();
+ ExpressionStatement* statement =
+ program->body()->at(0)->AsExpressionStatement();
+ Visit(statement->expression());
+ return output_;
+}
+
+
+const char* PrettyPrinter::PrintProgram(FunctionLiteral* program) {
+ Init();
+ PrintStatements(program->body());
+ Print("\n");
+ return output_;
+}
+
+
+void PrettyPrinter::PrintOut(Isolate* isolate, AstNode* node) {
+ PrettyPrinter printer(isolate);
+ PrintF("%s\n", printer.Print(node));
+}
+
+
+void PrettyPrinter::Init() {
+ if (size_ == 0) {
+ DCHECK(output_ == NULL);
+ const int initial_size = 256;
+ output_ = NewArray<char>(initial_size);
+ size_ = initial_size;
+ }
+ output_[0] = '\0';
+ pos_ = 0;
+}
+
+
+void PrettyPrinter::Print(const char* format, ...) {
+ for (;;) {
+ va_list arguments;
+ va_start(arguments, format);
+ int n = VSNPrintF(Vector<char>(output_, size_) + pos_,
+ format,
+ arguments);
+ va_end(arguments);
+
+ if (n >= 0) {
+ // there was enough space - we are done
+ pos_ += n;
+ return;
+ } else {
+ // there was not enough space - allocate more and try again
+ const int slack = 32;
+ int new_size = size_ + (size_ >> 1) + slack;
+ char* new_output = NewArray<char>(new_size);
+ MemCopy(new_output, output_, pos_);
+ DeleteArray(output_);
+ output_ = new_output;
+ size_ = new_size;
+ }
+ }
+}
+
+
+void PrettyPrinter::PrintStatements(ZoneList<Statement*>* statements) {
+ if (statements == NULL) return;
+ for (int i = 0; i < statements->length(); i++) {
+ if (i != 0) Print(" ");
+ Visit(statements->at(i));
+ }
+}
+
+
+void PrettyPrinter::PrintLabels(ZoneList<const AstRawString*>* labels) {
+ if (labels != NULL) {
+ for (int i = 0; i < labels->length(); i++) {
+ PrintLiteral(labels->at(i), false);
+ Print(": ");
+ }
+ }
+}
+
+
+void PrettyPrinter::PrintArguments(ZoneList<Expression*>* arguments) {
+ Print("(");
+ for (int i = 0; i < arguments->length(); i++) {
+ if (i != 0) Print(", ");
+ Visit(arguments->at(i));
+ }
+ Print(")");
+}
+
+
+void PrettyPrinter::PrintLiteral(Handle<Object> value, bool quote) {
+ Object* object = *value;
+ if (object->IsString()) {
+ String* string = String::cast(object);
+ if (quote) Print("\"");
+ for (int i = 0; i < string->length(); i++) {
+ Print("%c", string->Get(i));
+ }
+ if (quote) Print("\"");
+ } else if (object->IsNull()) {
+ Print("null");
+ } else if (object->IsTrue()) {
+ Print("true");
+ } else if (object->IsFalse()) {
+ Print("false");
+ } else if (object->IsUndefined()) {
+ Print("undefined");
+ } else if (object->IsNumber()) {
+ Print("%g", object->Number());
+ } else if (object->IsJSObject()) {
+ // regular expression
+ if (object->IsJSFunction()) {
+ Print("JS-Function");
+ } else if (object->IsJSArray()) {
+ Print("JS-array[%u]", JSArray::cast(object)->length());
+ } else if (object->IsJSObject()) {
+ Print("JS-Object");
+ } else {
+ Print("?UNKNOWN?");
+ }
+ } else if (object->IsFixedArray()) {
+ Print("FixedArray");
+ } else {
+ Print("<unknown literal %p>", object);
+ }
+}
+
+
+void PrettyPrinter::PrintLiteral(const AstRawString* value, bool quote) {
+ PrintLiteral(value->string(), quote);
+}
+
+
+void PrettyPrinter::PrintParameters(Scope* scope) {
+ Print("(");
+ for (int i = 0; i < scope->num_parameters(); i++) {
+ if (i > 0) Print(", ");
+ PrintLiteral(scope->parameter(i)->name(), false);
+ }
+ Print(")");
+}
+
+
+void PrettyPrinter::PrintDeclarations(ZoneList<Declaration*>* declarations) {
+ for (int i = 0; i < declarations->length(); i++) {
+ if (i > 0) Print(" ");
+ Visit(declarations->at(i));
+ }
+}
+
+
+void PrettyPrinter::PrintFunctionLiteral(FunctionLiteral* function) {
+ Print("function ");
+ PrintLiteral(function->name(), false);
+ PrintParameters(function->scope());
+ Print(" { ");
+ PrintDeclarations(function->scope()->declarations());
+ PrintStatements(function->body());
+ Print(" }");
+}
+
+
+//-----------------------------------------------------------------------------
+
+class IndentedScope BASE_EMBEDDED {
+ public:
+ IndentedScope(AstPrinter* printer, const char* txt)
+ : ast_printer_(printer) {
+ ast_printer_->PrintIndented(txt);
+ ast_printer_->Print("\n");
+ ast_printer_->inc_indent();
+ }
+
+ IndentedScope(AstPrinter* printer, const char* txt, int pos)
+ : ast_printer_(printer) {
+ ast_printer_->PrintIndented(txt);
+ ast_printer_->Print(" at %d\n", pos);
+ ast_printer_->inc_indent();
+ }
+
+ virtual ~IndentedScope() {
+ ast_printer_->dec_indent();
+ }
+
+ private:
+ AstPrinter* ast_printer_;
+};
+
+
+//-----------------------------------------------------------------------------
+
+
+AstPrinter::AstPrinter(Isolate* isolate) : PrettyPrinter(isolate), indent_(0) {}
+
+
+AstPrinter::~AstPrinter() {
+ DCHECK(indent_ == 0);
+}
+
+
+void AstPrinter::PrintIndented(const char* txt) {
+ for (int i = 0; i < indent_; i++) {
+ Print(". ");
+ }
+ Print(txt);
+}
+
+
+void AstPrinter::PrintLiteralIndented(const char* info,
+ Handle<Object> value,
+ bool quote) {
+ PrintIndented(info);
+ Print(" ");
+ PrintLiteral(value, quote);
+ Print("\n");
+}
+
+
+void AstPrinter::PrintLiteralWithModeIndented(const char* info,
+ Variable* var,
+ Handle<Object> value) {
+ if (var == NULL) {
+ PrintLiteralIndented(info, value, true);
+ } else {
+ EmbeddedVector<char, 256> buf;
+ int pos = SNPrintF(buf, "%s (mode = %s", info,
+ Variable::Mode2String(var->mode()));
+ SNPrintF(buf + pos, ")");
+ PrintLiteralIndented(buf.start(), value, true);
+ }
+}
+
+
+void AstPrinter::PrintLabelsIndented(ZoneList<const AstRawString*>* labels) {
+ if (labels == NULL || labels->length() == 0) return;
+ PrintIndented("LABELS ");
+ PrintLabels(labels);
+ Print("\n");
+}
+
+
+void AstPrinter::PrintIndentedVisit(const char* s, AstNode* node) {
+ IndentedScope indent(this, s, node->position());
+ Visit(node);
+}
+
+
+const char* AstPrinter::PrintProgram(FunctionLiteral* program) {
+ Init();
+ { IndentedScope indent(this, "FUNC", program->position());
+ PrintLiteralIndented("NAME", program->name(), true);
+ PrintLiteralIndented("INFERRED NAME", program->inferred_name(), true);
+ PrintParameters(program->scope());
+ PrintDeclarations(program->scope()->declarations());
+ PrintStatements(program->body());
+ }
+ return Output();
+}
+
+
+void AstPrinter::PrintDeclarations(ZoneList<Declaration*>* declarations) {
+ if (declarations->length() > 0) {
+ IndentedScope indent(this, "DECLS");
+ for (int i = 0; i < declarations->length(); i++) {
+ Visit(declarations->at(i));
+ }
+ }
+}
+
+
+void AstPrinter::PrintParameters(Scope* scope) {
+ if (scope->num_parameters() > 0) {
+ IndentedScope indent(this, "PARAMS");
+ for (int i = 0; i < scope->num_parameters(); i++) {
+ PrintLiteralWithModeIndented("VAR", scope->parameter(i),
+ scope->parameter(i)->name());
+ }
+ }
+}
+
+
+void AstPrinter::PrintStatements(ZoneList<Statement*>* statements) {
+ for (int i = 0; i < statements->length(); i++) {
+ Visit(statements->at(i));
+ }
+}
+
+
+void AstPrinter::PrintArguments(ZoneList<Expression*>* arguments) {
+ for (int i = 0; i < arguments->length(); i++) {
+ Visit(arguments->at(i));
+ }
+}
+
+
+void AstPrinter::VisitBlock(Block* node) {
+ const char* block_txt =
+ node->ignore_completion_value() ? "BLOCK NOCOMPLETIONS" : "BLOCK";
+ IndentedScope indent(this, block_txt, node->position());
+ PrintStatements(node->statements());
+}
+
+
+// TODO(svenpanne) Start with IndentedScope.
+void AstPrinter::VisitVariableDeclaration(VariableDeclaration* node) {
+ PrintLiteralWithModeIndented(Variable::Mode2String(node->mode()),
+ node->proxy()->var(),
+ node->proxy()->name());
+}
+
+
+// TODO(svenpanne) Start with IndentedScope.
+void AstPrinter::VisitFunctionDeclaration(FunctionDeclaration* node) {
+ PrintIndented("FUNCTION ");
+ PrintLiteral(node->proxy()->name(), true);
+ Print(" = function ");
+ PrintLiteral(node->fun()->name(), false);
+ Print("\n");
+}
+
+
+void AstPrinter::VisitImportDeclaration(ImportDeclaration* node) {
+ IndentedScope indent(this, "IMPORT", node->position());
+ PrintLiteralIndented("NAME", node->proxy()->name(), true);
+ PrintLiteralIndented("FROM", node->module_specifier()->string(), true);
+}
+
+
+void AstPrinter::VisitExportDeclaration(ExportDeclaration* node) {
+ IndentedScope indent(this, "EXPORT", node->position());
+ PrintLiteral(node->proxy()->name(), true);
+}
+
+
+void AstPrinter::VisitExpressionStatement(ExpressionStatement* node) {
+ IndentedScope indent(this, "EXPRESSION STATEMENT", node->position());
+ Visit(node->expression());
+}
+
+
+void AstPrinter::VisitEmptyStatement(EmptyStatement* node) {
+ IndentedScope indent(this, "EMPTY", node->position());
+}
+
+
+void AstPrinter::VisitSloppyBlockFunctionStatement(
+ SloppyBlockFunctionStatement* node) {
+ Visit(node->statement());
+}
+
+
+void AstPrinter::VisitIfStatement(IfStatement* node) {
+ IndentedScope indent(this, "IF", node->position());
+ PrintIndentedVisit("CONDITION", node->condition());
+ PrintIndentedVisit("THEN", node->then_statement());
+ if (node->HasElseStatement()) {
+ PrintIndentedVisit("ELSE", node->else_statement());
+ }
+}
+
+
+void AstPrinter::VisitContinueStatement(ContinueStatement* node) {
+ IndentedScope indent(this, "CONTINUE", node->position());
+ PrintLabelsIndented(node->target()->labels());
+}
+
+
+void AstPrinter::VisitBreakStatement(BreakStatement* node) {
+ IndentedScope indent(this, "BREAK", node->position());
+ PrintLabelsIndented(node->target()->labels());
+}
+
+
+void AstPrinter::VisitReturnStatement(ReturnStatement* node) {
+ IndentedScope indent(this, "RETURN", node->position());
+ Visit(node->expression());
+}
+
+
+void AstPrinter::VisitWithStatement(WithStatement* node) {
+ IndentedScope indent(this, "WITH", node->position());
+ PrintIndentedVisit("OBJECT", node->expression());
+ PrintIndentedVisit("BODY", node->statement());
+}
+
+
+void AstPrinter::VisitSwitchStatement(SwitchStatement* node) {
+ IndentedScope indent(this, "SWITCH", node->position());
+ PrintLabelsIndented(node->labels());
+ PrintIndentedVisit("TAG", node->tag());
+ for (int i = 0; i < node->cases()->length(); i++) {
+ Visit(node->cases()->at(i));
+ }
+}
+
+
+void AstPrinter::VisitCaseClause(CaseClause* clause) {
+ if (clause->is_default()) {
+ IndentedScope indent(this, "DEFAULT", clause->position());
+ PrintStatements(clause->statements());
+ } else {
+ IndentedScope indent(this, "CASE", clause->position());
+ Visit(clause->label());
+ PrintStatements(clause->statements());
+ }
+}
+
+
+void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) {
+ IndentedScope indent(this, "DO", node->position());
+ PrintLabelsIndented(node->labels());
+ PrintIndentedVisit("BODY", node->body());
+ PrintIndentedVisit("COND", node->cond());
+}
+
+
+void AstPrinter::VisitWhileStatement(WhileStatement* node) {
+ IndentedScope indent(this, "WHILE", node->position());
+ PrintLabelsIndented(node->labels());
+ PrintIndentedVisit("COND", node->cond());
+ PrintIndentedVisit("BODY", node->body());
+}
+
+
+void AstPrinter::VisitForStatement(ForStatement* node) {
+ IndentedScope indent(this, "FOR", node->position());
+ PrintLabelsIndented(node->labels());
+ if (node->init()) PrintIndentedVisit("INIT", node->init());
+ if (node->cond()) PrintIndentedVisit("COND", node->cond());
+ PrintIndentedVisit("BODY", node->body());
+ if (node->next()) PrintIndentedVisit("NEXT", node->next());
+}
+
+
+void AstPrinter::VisitForInStatement(ForInStatement* node) {
+ IndentedScope indent(this, "FOR IN", node->position());
+ PrintIndentedVisit("FOR", node->each());
+ PrintIndentedVisit("IN", node->enumerable());
+ PrintIndentedVisit("BODY", node->body());
+}
+
+
+void AstPrinter::VisitForOfStatement(ForOfStatement* node) {
+ IndentedScope indent(this, "FOR OF", node->position());
+ PrintIndentedVisit("FOR", node->each());
+ PrintIndentedVisit("OF", node->iterable());
+ PrintIndentedVisit("BODY", node->body());
+}
+
+
+void AstPrinter::VisitTryCatchStatement(TryCatchStatement* node) {
+ IndentedScope indent(this, "TRY CATCH", node->position());
+ PrintIndentedVisit("TRY", node->try_block());
+ PrintLiteralWithModeIndented("CATCHVAR",
+ node->variable(),
+ node->variable()->name());
+ PrintIndentedVisit("CATCH", node->catch_block());
+}
+
+
+void AstPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) {
+ IndentedScope indent(this, "TRY FINALLY", node->position());
+ PrintIndentedVisit("TRY", node->try_block());
+ PrintIndentedVisit("FINALLY", node->finally_block());
+}
+
+
+void AstPrinter::VisitDebuggerStatement(DebuggerStatement* node) {
+ IndentedScope indent(this, "DEBUGGER", node->position());
+}
+
+
+void AstPrinter::VisitFunctionLiteral(FunctionLiteral* node) {
+ IndentedScope indent(this, "FUNC LITERAL", node->position());
+ PrintLiteralIndented("NAME", node->name(), false);
+ PrintLiteralIndented("INFERRED NAME", node->inferred_name(), false);
+ PrintParameters(node->scope());
+ // We don't want to see the function literal in this case: it
+ // will be printed via PrintProgram when the code for it is
+ // generated.
+ // PrintStatements(node->body());
+}
+
+
+void AstPrinter::VisitClassLiteral(ClassLiteral* node) {
+ IndentedScope indent(this, "CLASS LITERAL", node->position());
+ if (node->raw_name() != nullptr) {
+ PrintLiteralIndented("NAME", node->name(), false);
+ }
+ if (node->extends() != nullptr) {
+ PrintIndentedVisit("EXTENDS", node->extends());
+ }
+ PrintProperties(node->properties());
+}
+
+
+void AstPrinter::PrintProperties(
+ ZoneList<ObjectLiteral::Property*>* properties) {
+ for (int i = 0; i < properties->length(); i++) {
+ ObjectLiteral::Property* property = properties->at(i);
+ const char* prop_kind = nullptr;
+ switch (property->kind()) {
+ case ObjectLiteral::Property::CONSTANT:
+ prop_kind = "CONSTANT";
+ break;
+ case ObjectLiteral::Property::COMPUTED:
+ prop_kind = "COMPUTED";
+ break;
+ case ObjectLiteral::Property::MATERIALIZED_LITERAL:
+ prop_kind = "MATERIALIZED_LITERAL";
+ break;
+ case ObjectLiteral::Property::PROTOTYPE:
+ prop_kind = "PROTOTYPE";
+ break;
+ case ObjectLiteral::Property::GETTER:
+ prop_kind = "GETTER";
+ break;
+ case ObjectLiteral::Property::SETTER:
+ prop_kind = "SETTER";
+ break;
+ }
+ EmbeddedVector<char, 128> buf;
+ SNPrintF(buf, "PROPERTY%s - %s", property->is_static() ? " - STATIC" : "",
+ prop_kind);
+ IndentedScope prop(this, buf.start());
+ PrintIndentedVisit("KEY", properties->at(i)->key());
+ PrintIndentedVisit("VALUE", properties->at(i)->value());
+ }
+}
+
+
+void AstPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) {
+ IndentedScope indent(this, "NATIVE FUNC LITERAL", node->position());
+ PrintLiteralIndented("NAME", node->name(), false);
+}
+
+
+void AstPrinter::VisitDoExpression(DoExpression* node) {
+ IndentedScope indent(this, "DO EXPRESSION", node->position());
+ PrintStatements(node->block()->statements());
+}
+
+
+void AstPrinter::VisitConditional(Conditional* node) {
+ IndentedScope indent(this, "CONDITIONAL", node->position());
+ PrintIndentedVisit("CONDITION", node->condition());
+ PrintIndentedVisit("THEN", node->then_expression());
+ PrintIndentedVisit("ELSE", node->else_expression());
+}
+
+
+// TODO(svenpanne) Start with IndentedScope.
+void AstPrinter::VisitLiteral(Literal* node) {
+ PrintLiteralIndented("LITERAL", node->value(), true);
+}
+
+
+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());
+ PrintIndented(buf.start());
+ PrintLiteralIndented("PATTERN", node->pattern(), false);
+ int i = 0;
+ if (node->flags() & RegExp::kGlobal) buf[i++] = 'g';
+ if (node->flags() & RegExp::kIgnoreCase) buf[i++] = 'i';
+ if (node->flags() & RegExp::kMultiline) buf[i++] = 'm';
+ if (node->flags() & RegExp::kUnicode) buf[i++] = 'u';
+ if (node->flags() & RegExp::kSticky) buf[i++] = 'y';
+ buf[i] = '\0';
+ PrintIndented("FLAGS ");
+ Print(buf.start());
+ Print("\n");
+}
+
+
+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());
+ PrintIndented(buf.start());
+ PrintProperties(node->properties());
+}
+
+
+void AstPrinter::VisitArrayLiteral(ArrayLiteral* node) {
+ IndentedScope indent(this, "ARRAY LITERAL", node->position());
+
+ EmbeddedVector<char, 128> buf;
+ SNPrintF(buf, "literal_index = %d\n", node->literal_index());
+ PrintIndented(buf.start());
+ if (node->values()->length() > 0) {
+ IndentedScope indent(this, "VALUES", node->position());
+ for (int i = 0; i < node->values()->length(); i++) {
+ Visit(node->values()->at(i));
+ }
+ }
+}
+
+
+void AstPrinter::VisitVariableProxy(VariableProxy* node) {
+ Variable* var = node->var();
+ EmbeddedVector<char, 128> buf;
+ int pos =
+ FormatSlotNode(&buf, node, "VAR PROXY", node->VariableFeedbackSlot());
+
+ switch (var->location()) {
+ case VariableLocation::UNALLOCATED:
+ break;
+ case VariableLocation::PARAMETER:
+ SNPrintF(buf + pos, " parameter[%d]", var->index());
+ break;
+ case VariableLocation::LOCAL:
+ SNPrintF(buf + pos, " local[%d]", var->index());
+ break;
+ case VariableLocation::CONTEXT:
+ SNPrintF(buf + pos, " context[%d]", var->index());
+ break;
+ case VariableLocation::GLOBAL:
+ SNPrintF(buf + pos, " global[%d]", var->index());
+ break;
+ case VariableLocation::LOOKUP:
+ SNPrintF(buf + pos, " lookup");
+ break;
+ }
+ PrintLiteralWithModeIndented(buf.start(), var, node->name());
+}
+
+
+void AstPrinter::VisitAssignment(Assignment* node) {
+ IndentedScope indent(this, Token::Name(node->op()), node->position());
+ Visit(node->target());
+ Visit(node->value());
+}
+
+
+void AstPrinter::VisitYield(Yield* node) {
+ IndentedScope indent(this, "YIELD", node->position());
+ Visit(node->expression());
+}
+
+
+void AstPrinter::VisitThrow(Throw* node) {
+ IndentedScope indent(this, "THROW", node->position());
+ Visit(node->exception());
+}
+
+
+void AstPrinter::VisitProperty(Property* node) {
+ EmbeddedVector<char, 128> buf;
+ FormatSlotNode(&buf, node, "PROPERTY", node->PropertyFeedbackSlot());
+ IndentedScope indent(this, buf.start(), node->position());
+
+ Visit(node->obj());
+ Literal* literal = node->key()->AsLiteral();
+ if (literal != NULL && literal->value()->IsInternalizedString()) {
+ PrintLiteralIndented("NAME", literal->value(), false);
+ } else {
+ PrintIndentedVisit("KEY", node->key());
+ }
+}
+
+
+void AstPrinter::VisitCall(Call* node) {
+ EmbeddedVector<char, 128> buf;
+ FormatSlotNode(&buf, node, "CALL", node->CallFeedbackICSlot());
+ IndentedScope indent(this, buf.start());
+
+ Visit(node->expression());
+ PrintArguments(node->arguments());
+}
+
+
+void AstPrinter::VisitCallNew(CallNew* node) {
+ IndentedScope indent(this, "CALL NEW", node->position());
+ Visit(node->expression());
+ PrintArguments(node->arguments());
+}
+
+
+void AstPrinter::VisitCallRuntime(CallRuntime* node) {
+ EmbeddedVector<char, 128> buf;
+ SNPrintF(buf, "CALL RUNTIME %s", node->debug_name());
+ IndentedScope indent(this, buf.start(), node->position());
+ PrintArguments(node->arguments());
+}
+
+
+void AstPrinter::VisitUnaryOperation(UnaryOperation* node) {
+ IndentedScope indent(this, Token::Name(node->op()), node->position());
+ Visit(node->expression());
+}
+
+
+void AstPrinter::VisitCountOperation(CountOperation* node) {
+ EmbeddedVector<char, 128> buf;
+ SNPrintF(buf, "%s %s", (node->is_prefix() ? "PRE" : "POST"),
+ Token::Name(node->op()));
+ IndentedScope indent(this, buf.start(), node->position());
+ Visit(node->expression());
+}
+
+
+void AstPrinter::VisitBinaryOperation(BinaryOperation* node) {
+ IndentedScope indent(this, Token::Name(node->op()), node->position());
+ Visit(node->left());
+ Visit(node->right());
+}
+
+
+void AstPrinter::VisitCompareOperation(CompareOperation* node) {
+ IndentedScope indent(this, Token::Name(node->op()), node->position());
+ Visit(node->left());
+ Visit(node->right());
+}
+
+
+void AstPrinter::VisitSpread(Spread* node) {
+ IndentedScope indent(this, "...", node->position());
+ Visit(node->expression());
+}
+
+
+void AstPrinter::VisitEmptyParentheses(EmptyParentheses* node) {
+ IndentedScope indent(this, "()", node->position());
+}
+
+
+void AstPrinter::VisitThisFunction(ThisFunction* node) {
+ IndentedScope indent(this, "THIS-FUNCTION", node->position());
+}
+
+
+void AstPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) {
+ IndentedScope indent(this, "SUPER-PROPERTY-REFERENCE", node->position());
+}
+
+
+void AstPrinter::VisitSuperCallReference(SuperCallReference* node) {
+ IndentedScope indent(this, "SUPER-CALL-REFERENCE", node->position());
+}
+
+
+void AstPrinter::VisitRewritableAssignmentExpression(
+ RewritableAssignmentExpression* node) {
+ Visit(node->expression());
+}
+
+
+#endif // DEBUG
+
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/ast/prettyprinter.h b/deps/v8/src/ast/prettyprinter.h
new file mode 100644
index 0000000000..7e4dcdc804
--- /dev/null
+++ b/deps/v8/src/ast/prettyprinter.h
@@ -0,0 +1,140 @@
+// Copyright 2012 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_PRETTYPRINTER_H_
+#define V8_AST_PRETTYPRINTER_H_
+
+#include "src/allocation.h"
+#include "src/ast/ast.h"
+
+namespace v8 {
+namespace internal {
+
+class CallPrinter : public AstVisitor {
+ public:
+ explicit CallPrinter(Isolate* isolate, bool is_builtin);
+ virtual ~CallPrinter();
+
+ // The following routine prints the node with position |position| into a
+ // string. The result string is alive as long as the CallPrinter is alive.
+ const char* Print(FunctionLiteral* program, int position);
+
+ void Print(const char* format, ...);
+
+ void Find(AstNode* node, bool print = false);
+
+// Individual nodes
+#define DECLARE_VISIT(type) void Visit##type(type* node) override;
+ AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+ private:
+ void Init();
+ char* output_; // output string buffer
+ int size_; // output_ size
+ int pos_; // current printing position
+ int position_; // position of ast node to print
+ bool found_;
+ bool done_;
+ bool is_builtin_;
+
+ DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
+
+ protected:
+ void PrintLiteral(Object* value, bool quote);
+ void PrintLiteral(const AstRawString* value, bool quote);
+ void FindStatements(ZoneList<Statement*>* statements);
+ void FindArguments(ZoneList<Expression*>* arguments);
+};
+
+
+#ifdef DEBUG
+
+class PrettyPrinter: public AstVisitor {
+ public:
+ explicit PrettyPrinter(Isolate* isolate);
+ virtual ~PrettyPrinter();
+
+ // The following routines print a node into a string.
+ // The result string is alive as long as the PrettyPrinter is alive.
+ const char* Print(AstNode* node);
+ const char* PrintExpression(FunctionLiteral* program);
+ const char* PrintProgram(FunctionLiteral* program);
+
+ void Print(const char* format, ...);
+
+ // Print a node to stdout.
+ static void PrintOut(Isolate* isolate, AstNode* node);
+
+ // Individual nodes
+#define DECLARE_VISIT(type) void Visit##type(type* node) override;
+ AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+ private:
+ char* output_; // output string buffer
+ int size_; // output_ size
+ int pos_; // current printing position
+
+ protected:
+ void Init();
+ const char* Output() const { return output_; }
+
+ virtual void PrintStatements(ZoneList<Statement*>* statements);
+ void PrintLabels(ZoneList<const AstRawString*>* labels);
+ virtual void PrintArguments(ZoneList<Expression*>* arguments);
+ void PrintLiteral(Handle<Object> value, bool quote);
+ void PrintLiteral(const AstRawString* value, bool quote);
+ void PrintParameters(Scope* scope);
+ void PrintDeclarations(ZoneList<Declaration*>* declarations);
+ void PrintFunctionLiteral(FunctionLiteral* function);
+ void PrintCaseClause(CaseClause* clause);
+ void PrintObjectLiteralProperty(ObjectLiteralProperty* property);
+
+ DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
+};
+
+
+// Prints the AST structure
+class AstPrinter: public PrettyPrinter {
+ public:
+ explicit AstPrinter(Isolate* isolate);
+ virtual ~AstPrinter();
+
+ const char* PrintProgram(FunctionLiteral* program);
+
+ // Individual nodes
+#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
+ AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+ private:
+ friend class IndentedScope;
+ void PrintIndented(const char* txt);
+ void PrintIndentedVisit(const char* s, AstNode* node);
+
+ void PrintStatements(ZoneList<Statement*>* statements);
+ void PrintDeclarations(ZoneList<Declaration*>* declarations);
+ void PrintParameters(Scope* scope);
+ void PrintArguments(ZoneList<Expression*>* arguments);
+ void PrintCaseClause(CaseClause* clause);
+ void PrintLiteralIndented(const char* info, Handle<Object> value, bool quote);
+ void PrintLiteralWithModeIndented(const char* info,
+ Variable* var,
+ Handle<Object> value);
+ void PrintLabelsIndented(ZoneList<const AstRawString*>* labels);
+ void PrintProperties(ZoneList<ObjectLiteral::Property*>* properties);
+
+ void inc_indent() { indent_++; }
+ void dec_indent() { indent_--; }
+
+ int indent_;
+};
+
+#endif // DEBUG
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_AST_PRETTYPRINTER_H_
diff --git a/deps/v8/src/ast/scopeinfo.cc b/deps/v8/src/ast/scopeinfo.cc
new file mode 100644
index 0000000000..668879fe51
--- /dev/null
+++ b/deps/v8/src/ast/scopeinfo.cc
@@ -0,0 +1,858 @@
+// 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 "src/ast/scopeinfo.h"
+
+#include <stdlib.h>
+
+#include "src/ast/scopes.h"
+#include "src/bootstrapper.h"
+
+namespace v8 {
+namespace internal {
+
+
+Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone,
+ Scope* scope) {
+ // Collect stack and context locals.
+ ZoneList<Variable*> stack_locals(scope->StackLocalCount(), zone);
+ ZoneList<Variable*> context_locals(scope->ContextLocalCount(), zone);
+ ZoneList<Variable*> context_globals(scope->ContextGlobalCount(), zone);
+ ZoneList<Variable*> strong_mode_free_variables(0, zone);
+
+ scope->CollectStackAndContextLocals(&stack_locals, &context_locals,
+ &context_globals,
+ &strong_mode_free_variables);
+ const int stack_local_count = stack_locals.length();
+ const int context_local_count = context_locals.length();
+ const int context_global_count = context_globals.length();
+ const int strong_mode_free_variable_count =
+ strong_mode_free_variables.length();
+ // Make sure we allocate the correct amount.
+ DCHECK_EQ(scope->ContextLocalCount(), context_local_count);
+ DCHECK_EQ(scope->ContextGlobalCount(), context_global_count);
+
+ // Determine use and location of the "this" binding if it is present.
+ VariableAllocationInfo receiver_info;
+ if (scope->has_this_declaration()) {
+ Variable* var = scope->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->new_target_var() != nullptr;
+
+ // Determine use and location of the function variable if it is present.
+ VariableAllocationInfo function_name_info;
+ VariableMode function_variable_mode;
+ if (scope->is_function_scope() && scope->function() != NULL) {
+ Variable* var = scope->function()->proxy()->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;
+ }
+ function_variable_mode = var->mode();
+ } else {
+ function_name_info = NONE;
+ function_variable_mode = VAR;
+ }
+ DCHECK(context_global_count == 0 || scope->scope_type() == SCRIPT_SCOPE);
+
+ 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 int length = kVariablePartIndex + parameter_count +
+ (1 + stack_local_count) + 2 * context_local_count +
+ 2 * context_global_count +
+ 3 * strong_mode_free_variable_count +
+ (has_receiver ? 1 : 0) + (has_function_name ? 2 : 0);
+
+ Factory* factory = isolate->factory();
+ Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
+
+ bool has_simple_parameters =
+ scope->is_function_scope() && scope->has_simple_parameters();
+
+ // 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) |
+ FunctionVariableMode::encode(function_variable_mode) |
+ AsmModuleField::encode(scope->asm_module()) |
+ AsmFunctionField::encode(scope->asm_function()) |
+ HasSimpleParametersField::encode(has_simple_parameters) |
+ FunctionKindField::encode(scope->function_kind());
+ scope_info->SetFlags(flags);
+ scope_info->SetParameterCount(parameter_count);
+ scope_info->SetStackLocalCount(stack_local_count);
+ scope_info->SetContextLocalCount(context_local_count);
+ scope_info->SetContextGlobalCount(context_global_count);
+ scope_info->SetStrongModeFreeVariableCount(strong_mode_free_variable_count);
+
+ int index = kVariablePartIndex;
+ // Add parameters.
+ DCHECK(index == scope_info->ParameterEntriesIndex());
+ for (int i = 0; i < parameter_count; ++i) {
+ scope_info->set(index++, *scope->parameter(i)->name());
+ }
+
+ // Add stack locals' names. We are assuming that the stack locals'
+ // slots are allocated in increasing order, so we can simply add
+ // them to the ScopeInfo object.
+ int first_slot_index;
+ if (stack_local_count > 0) {
+ first_slot_index = stack_locals[0]->index();
+ } else {
+ first_slot_index = 0;
+ }
+ DCHECK(index == scope_info->StackLocalFirstSlotIndex());
+ scope_info->set(index++, Smi::FromInt(first_slot_index));
+ DCHECK(index == scope_info->StackLocalEntriesIndex());
+ for (int i = 0; i < stack_local_count; ++i) {
+ DCHECK(stack_locals[i]->index() == first_slot_index + i);
+ scope_info->set(index++, *stack_locals[i]->name());
+ }
+
+ // Due to usage analysis, context-allocated locals are not necessarily in
+ // increasing order: Some of them may be parameters which are allocated before
+ // the non-parameter locals. When the non-parameter locals are sorted
+ // according to usage, the allocated slot indices may not be in increasing
+ // order with the variable list anymore. Thus, we first need to sort them by
+ // context slot index before adding them to the ScopeInfo object.
+ context_locals.Sort(&Variable::CompareIndex);
+
+ // Add context locals' names.
+ DCHECK(index == scope_info->ContextLocalNameEntriesIndex());
+ for (int i = 0; i < context_local_count; ++i) {
+ scope_info->set(index++, *context_locals[i]->name());
+ }
+
+ // Add context globals' names.
+ DCHECK(index == scope_info->ContextGlobalNameEntriesIndex());
+ for (int i = 0; i < context_global_count; ++i) {
+ scope_info->set(index++, *context_globals[i]->name());
+ }
+
+ // Add context locals' info.
+ DCHECK(index == scope_info->ContextLocalInfoEntriesIndex());
+ for (int i = 0; i < context_local_count; ++i) {
+ Variable* var = context_locals[i];
+ uint32_t value =
+ ContextLocalMode::encode(var->mode()) |
+ ContextLocalInitFlag::encode(var->initialization_flag()) |
+ ContextLocalMaybeAssignedFlag::encode(var->maybe_assigned());
+ scope_info->set(index++, Smi::FromInt(value));
+ }
+
+ // Add context globals' info.
+ DCHECK(index == scope_info->ContextGlobalInfoEntriesIndex());
+ for (int i = 0; i < context_global_count; ++i) {
+ Variable* var = context_globals[i];
+ // TODO(ishell): do we need this kind of info for globals here?
+ uint32_t value =
+ ContextLocalMode::encode(var->mode()) |
+ ContextLocalInitFlag::encode(var->initialization_flag()) |
+ ContextLocalMaybeAssignedFlag::encode(var->maybe_assigned());
+ scope_info->set(index++, Smi::FromInt(value));
+ }
+
+ DCHECK(index == scope_info->StrongModeFreeVariableNameEntriesIndex());
+ for (int i = 0; i < strong_mode_free_variable_count; ++i) {
+ scope_info->set(index++, *strong_mode_free_variables[i]->name());
+ }
+
+ DCHECK(index == scope_info->StrongModeFreeVariablePositionEntriesIndex());
+ for (int i = 0; i < strong_mode_free_variable_count; ++i) {
+ // Unfortunately, the source code positions are stored as int even though
+ // int32_t would be enough (given the maximum source code length).
+ Handle<Object> start_position = factory->NewNumberFromInt(
+ static_cast<int32_t>(strong_mode_free_variables[i]
+ ->strong_mode_reference_start_position()));
+ scope_info->set(index++, *start_position);
+ Handle<Object> end_position = factory->NewNumberFromInt(
+ static_cast<int32_t>(strong_mode_free_variables[i]
+ ->strong_mode_reference_end_position()));
+ scope_info->set(index++, *end_position);
+ }
+
+ // If the receiver is allocated, add its index.
+ DCHECK(index == scope_info->ReceiverEntryIndex());
+ if (has_receiver) {
+ int var_index = scope->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(index == scope_info->FunctionNameEntryIndex());
+ if (has_function_name) {
+ int var_index = scope->function()->proxy()->var()->index();
+ scope_info->set(index++, *scope->function()->proxy()->name());
+ scope_info->set(index++, Smi::FromInt(var_index));
+ DCHECK(function_name_info != CONTEXT ||
+ var_index == scope_info->ContextLength() - 1);
+ }
+
+ DCHECK(index == scope_info->length());
+ DCHECK(scope->num_parameters() == scope_info->ParameterCount());
+ DCHECK(scope->num_heap_slots() == scope_info->ContextLength() ||
+ (scope->num_heap_slots() == kVariablePartIndex &&
+ scope_info->ContextLength() == 0));
+ 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 int context_global_count = 0;
+ const int strong_mode_free_variable_count = 0;
+ const bool has_simple_parameters = true;
+ const VariableAllocationInfo receiver_info = CONTEXT;
+ const VariableAllocationInfo function_name_info = NONE;
+ const VariableMode function_variable_mode = VAR;
+ const bool has_function_name = false;
+ const bool has_receiver = true;
+ const int parameter_count = 0;
+ const int length = kVariablePartIndex + parameter_count +
+ (1 + stack_local_count) + 2 * context_local_count +
+ 2 * context_global_count +
+ 3 * strong_mode_free_variable_count +
+ (has_receiver ? 1 : 0) + (has_function_name ? 2 : 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) |
+ FunctionVariableMode::encode(function_variable_mode) |
+ AsmModuleField::encode(false) | AsmFunctionField::encode(false) |
+ HasSimpleParametersField::encode(has_simple_parameters) |
+ FunctionKindField::encode(FunctionKind::kNormalFunction);
+ scope_info->SetFlags(flags);
+ scope_info->SetParameterCount(parameter_count);
+ scope_info->SetStackLocalCount(stack_local_count);
+ scope_info->SetContextLocalCount(context_local_count);
+ scope_info->SetContextGlobalCount(context_global_count);
+ scope_info->SetStrongModeFreeVariableCount(strong_mode_free_variable_count);
+
+ int index = kVariablePartIndex;
+ const int first_slot_index = 0;
+ DCHECK(index == scope_info->StackLocalFirstSlotIndex());
+ scope_info->set(index++, Smi::FromInt(first_slot_index));
+ DCHECK(index == scope_info->StackLocalEntriesIndex());
+
+ // Here we add info for context-allocated "this".
+ DCHECK(index == scope_info->ContextLocalNameEntriesIndex());
+ scope_info->set(index++, *isolate->factory()->this_string());
+ DCHECK(index == scope_info->ContextLocalInfoEntriesIndex());
+ const uint32_t value = ContextLocalMode::encode(CONST) |
+ ContextLocalInitFlag::encode(kCreatedInitialized) |
+ ContextLocalMaybeAssignedFlag::encode(kNotAssigned);
+ scope_info->set(index++, Smi::FromInt(value));
+
+ DCHECK(index == scope_info->StrongModeFreeVariableNameEntriesIndex());
+ DCHECK(index == scope_info->StrongModeFreeVariablePositionEntriesIndex());
+
+ // And here we record that this scopeinfo binds a receiver.
+ DCHECK(index == scope_info->ReceiverEntryIndex());
+ const int receiver_index = Context::MIN_CONTEXT_SLOTS + 0;
+ scope_info->set(index++, Smi::FromInt(receiver_index));
+
+ DCHECK(index == scope_info->FunctionNameEntryIndex());
+
+ 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 reinterpret_cast<ScopeInfo*>(isolate->heap()->empty_fixed_array());
+}
+
+
+ScopeType ScopeInfo::scope_type() {
+ DCHECK(length() > 0);
+ 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();
+ int context_globals = ContextGlobalCount();
+ bool function_name_context_slot =
+ FunctionVariableField::decode(Flags()) == CONTEXT;
+ bool has_context = context_locals > 0 || context_globals > 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 + context_globals +
+ (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::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(FunctionNameEntryIndex()));
+}
+
+
+String* ScopeInfo::ParameterName(int var) {
+ DCHECK(0 <= var && var < ParameterCount());
+ int info_index = ParameterEntriesIndex() + var;
+ return String::cast(get(info_index));
+}
+
+
+String* ScopeInfo::LocalName(int var) {
+ DCHECK(0 <= var && var < LocalCount());
+ DCHECK(StackLocalEntriesIndex() + StackLocalCount() ==
+ ContextLocalNameEntriesIndex());
+ int info_index = StackLocalEntriesIndex() + var;
+ return String::cast(get(info_index));
+}
+
+
+String* ScopeInfo::StackLocalName(int var) {
+ DCHECK(0 <= var && var < StackLocalCount());
+ int info_index = StackLocalEntriesIndex() + var;
+ return String::cast(get(info_index));
+}
+
+
+int ScopeInfo::StackLocalIndex(int var) {
+ DCHECK(0 <= var && var < StackLocalCount());
+ int first_slot_index = Smi::cast(get(StackLocalFirstSlotIndex()))->value();
+ return first_slot_index + var;
+}
+
+
+String* ScopeInfo::ContextLocalName(int var) {
+ DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount());
+ int info_index = ContextLocalNameEntriesIndex() + var;
+ return String::cast(get(info_index));
+}
+
+
+VariableMode ScopeInfo::ContextLocalMode(int var) {
+ DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount());
+ int info_index = ContextLocalInfoEntriesIndex() + var;
+ int value = Smi::cast(get(info_index))->value();
+ return ContextLocalMode::decode(value);
+}
+
+
+InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) {
+ DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount());
+ int info_index = ContextLocalInfoEntriesIndex() + var;
+ int value = Smi::cast(get(info_index))->value();
+ return ContextLocalInitFlag::decode(value);
+}
+
+
+MaybeAssignedFlag ScopeInfo::ContextLocalMaybeAssignedFlag(int var) {
+ DCHECK(0 <= var && var < ContextLocalCount() + ContextGlobalCount());
+ int info_index = ContextLocalInfoEntriesIndex() + var;
+ int value = Smi::cast(get(info_index))->value();
+ return ContextLocalMaybeAssignedFlag::decode(value);
+}
+
+
+bool ScopeInfo::LocalIsSynthetic(int var) {
+ DCHECK(0 <= var && var < LocalCount());
+ // 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!
+ Handle<String> name(LocalName(var));
+ return (name->length() > 0 && name->Get(0) == '.') ||
+ name->Equals(*GetIsolate()->factory()->this_string());
+}
+
+
+String* ScopeInfo::StrongModeFreeVariableName(int var) {
+ DCHECK(0 <= var && var < StrongModeFreeVariableCount());
+ int info_index = StrongModeFreeVariableNameEntriesIndex() + var;
+ return String::cast(get(info_index));
+}
+
+
+int ScopeInfo::StrongModeFreeVariableStartPosition(int var) {
+ DCHECK(0 <= var && var < StrongModeFreeVariableCount());
+ int info_index = StrongModeFreeVariablePositionEntriesIndex() + var * 2;
+ int32_t value = 0;
+ bool ok = get(info_index)->ToInt32(&value);
+ USE(ok);
+ DCHECK(ok);
+ return value;
+}
+
+
+int ScopeInfo::StrongModeFreeVariableEndPosition(int var) {
+ DCHECK(0 <= var && var < StrongModeFreeVariableCount());
+ int info_index = StrongModeFreeVariablePositionEntriesIndex() + var * 2 + 1;
+ int32_t value = 0;
+ bool ok = get(info_index)->ToInt32(&value);
+ USE(ok);
+ DCHECK(ok);
+ return value;
+}
+
+
+int ScopeInfo::StackSlotIndex(String* name) {
+ DCHECK(name->IsInternalizedString());
+ if (length() > 0) {
+ int first_slot_index = Smi::cast(get(StackLocalFirstSlotIndex()))->value();
+ int start = StackLocalEntriesIndex();
+ int end = StackLocalEntriesIndex() + StackLocalCount();
+ for (int i = start; i < end; ++i) {
+ if (name == get(i)) {
+ return i - start + first_slot_index;
+ }
+ }
+ }
+ return -1;
+}
+
+
+int ScopeInfo::ContextSlotIndex(Handle<ScopeInfo> scope_info,
+ Handle<String> name, VariableMode* mode,
+ InitializationFlag* init_flag,
+ MaybeAssignedFlag* maybe_assigned_flag) {
+ DCHECK(name->IsInternalizedString());
+ DCHECK(mode != NULL);
+ DCHECK(init_flag != NULL);
+ 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(result < scope_info->ContextLength());
+ return result;
+ }
+
+ int start = scope_info->ContextLocalNameEntriesIndex();
+ int end = scope_info->ContextLocalNameEntriesIndex() +
+ 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(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;
+}
+
+
+int ScopeInfo::ContextGlobalSlotIndex(Handle<ScopeInfo> scope_info,
+ Handle<String> name, VariableMode* mode,
+ InitializationFlag* init_flag,
+ MaybeAssignedFlag* maybe_assigned_flag) {
+ DCHECK(name->IsInternalizedString());
+ DCHECK(mode != NULL);
+ DCHECK(init_flag != NULL);
+ if (scope_info->length() > 0) {
+ // This is to ensure that ContextLocalMode() and co. queries would work.
+ DCHECK_EQ(scope_info->ContextGlobalNameEntriesIndex(),
+ scope_info->ContextLocalNameEntriesIndex() +
+ scope_info->ContextLocalCount());
+ int base = scope_info->ContextLocalNameEntriesIndex();
+ int start = scope_info->ContextGlobalNameEntriesIndex();
+ int end = scope_info->ContextGlobalNameEntriesIndex() +
+ scope_info->ContextGlobalCount();
+ for (int i = start; i < end; ++i) {
+ if (*name == scope_info->get(i)) {
+ int var = i - base;
+ *mode = scope_info->ContextLocalMode(var);
+ *init_flag = scope_info->ContextLocalInitFlag(var);
+ *maybe_assigned_flag = scope_info->ContextLocalMaybeAssignedFlag(var);
+ int result = Context::MIN_CONTEXT_SLOTS + var;
+ DCHECK(result < scope_info->ContextLength());
+ return result;
+ }
+ }
+ }
+ 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() + ContextGlobalCount());
+ 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 = ParameterEntriesIndex();
+ int end = ParameterEntriesIndex() + 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(ReceiverEntryIndex()))->value();
+ return -1;
+}
+
+
+int ScopeInfo::FunctionContextSlotIndex(String* name, VariableMode* mode) {
+ DCHECK(name->IsInternalizedString());
+ DCHECK(mode != NULL);
+ if (length() > 0) {
+ if (FunctionVariableField::decode(Flags()) == CONTEXT &&
+ FunctionName() == name) {
+ *mode = FunctionVariableMode::decode(Flags());
+ return Smi::cast(get(FunctionNameEntryIndex() + 1))->value();
+ }
+ }
+ return -1;
+}
+
+
+FunctionKind ScopeInfo::function_kind() {
+ return FunctionKindField::decode(Flags());
+}
+
+
+int ScopeInfo::ParameterEntriesIndex() {
+ DCHECK(length() > 0);
+ return kVariablePartIndex;
+}
+
+
+int ScopeInfo::StackLocalFirstSlotIndex() {
+ return ParameterEntriesIndex() + ParameterCount();
+}
+
+
+int ScopeInfo::StackLocalEntriesIndex() {
+ return StackLocalFirstSlotIndex() + 1;
+}
+
+
+int ScopeInfo::ContextLocalNameEntriesIndex() {
+ return StackLocalEntriesIndex() + StackLocalCount();
+}
+
+
+int ScopeInfo::ContextGlobalNameEntriesIndex() {
+ return ContextLocalNameEntriesIndex() + ContextLocalCount();
+}
+
+
+int ScopeInfo::ContextLocalInfoEntriesIndex() {
+ return ContextGlobalNameEntriesIndex() + ContextGlobalCount();
+}
+
+
+int ScopeInfo::ContextGlobalInfoEntriesIndex() {
+ return ContextLocalInfoEntriesIndex() + ContextLocalCount();
+}
+
+
+int ScopeInfo::StrongModeFreeVariableNameEntriesIndex() {
+ return ContextGlobalInfoEntriesIndex() + ContextGlobalCount();
+}
+
+
+int ScopeInfo::StrongModeFreeVariablePositionEntriesIndex() {
+ return StrongModeFreeVariableNameEntriesIndex() +
+ StrongModeFreeVariableCount();
+}
+
+
+int ScopeInfo::ReceiverEntryIndex() {
+ return StrongModeFreeVariablePositionEntriesIndex() +
+ 2 * StrongModeFreeVariableCount();
+}
+
+
+int ScopeInfo::FunctionNameEntryIndex() {
+ return ReceiverEntryIndex() + (HasAllocatedReceiver() ? 1 : 0);
+}
+
+
+int ContextSlotCache::Hash(Object* data, String* name) {
+ // Uses only lower 32 bits if pointers are larger.
+ uintptr_t addr_hash =
+ static_cast<uint32_t>(reinterpret_cast<uintptr_t>(data)) >> 2;
+ return static_cast<int>((addr_hash ^ name->Hash()) % kLength);
+}
+
+
+int ContextSlotCache::Lookup(Object* data, String* name, VariableMode* mode,
+ InitializationFlag* init_flag,
+ MaybeAssignedFlag* maybe_assigned_flag) {
+ int index = Hash(data, name);
+ Key& key = keys_[index];
+ if ((key.data == data) && key.name->Equals(name)) {
+ Value result(values_[index]);
+ if (mode != NULL) *mode = result.mode();
+ if (init_flag != NULL) *init_flag = result.initialization_flag();
+ if (maybe_assigned_flag != NULL)
+ *maybe_assigned_flag = result.maybe_assigned_flag();
+ return result.index() + kNotFound;
+ }
+ return kNotFound;
+}
+
+
+void ContextSlotCache::Update(Handle<Object> data, Handle<String> name,
+ VariableMode mode, InitializationFlag init_flag,
+ MaybeAssignedFlag maybe_assigned_flag,
+ int slot_index) {
+ DisallowHeapAllocation no_gc;
+ Handle<String> internalized_name;
+ DCHECK(slot_index > kNotFound);
+ if (StringTable::InternalizeStringIfExists(name->GetIsolate(), name).
+ ToHandle(&internalized_name)) {
+ int index = Hash(*data, *internalized_name);
+ Key& key = keys_[index];
+ key.data = *data;
+ key.name = *internalized_name;
+ // Please note value only takes a uint as index.
+ values_[index] = Value(mode, init_flag, maybe_assigned_flag,
+ slot_index - kNotFound).raw();
+#ifdef DEBUG
+ ValidateEntry(data, name, mode, init_flag, maybe_assigned_flag, slot_index);
+#endif
+ }
+}
+
+
+void ContextSlotCache::Clear() {
+ for (int index = 0; index < kLength; index++) keys_[index].data = NULL;
+}
+
+
+#ifdef DEBUG
+
+void ContextSlotCache::ValidateEntry(Handle<Object> data, Handle<String> name,
+ VariableMode mode,
+ InitializationFlag init_flag,
+ MaybeAssignedFlag maybe_assigned_flag,
+ int slot_index) {
+ DisallowHeapAllocation no_gc;
+ Handle<String> internalized_name;
+ if (StringTable::InternalizeStringIfExists(name->GetIsolate(), name).
+ ToHandle(&internalized_name)) {
+ int index = Hash(*data, *name);
+ Key& key = keys_[index];
+ DCHECK(key.data == *data);
+ DCHECK(key.name->Equals(*name));
+ Value result(values_[index]);
+ DCHECK(result.mode() == mode);
+ DCHECK(result.initialization_flag() == init_flag);
+ DCHECK(result.maybe_assigned_flag() == maybe_assigned_flag);
+ DCHECK(result.index() + kNotFound == slot_index);
+ }
+}
+
+
+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, ParameterEntriesIndex(),
+ ParameterEntriesIndex() + ParameterCount(), this);
+ PrintList("stack slots", 0, StackLocalEntriesIndex(),
+ StackLocalEntriesIndex() + StackLocalCount(), this);
+ PrintList("context slots", Context::MIN_CONTEXT_SLOTS,
+ ContextLocalNameEntriesIndex(),
+ ContextLocalNameEntriesIndex() + ContextLocalCount(), this);
+ }
+
+ PrintF("}\n");
+}
+#endif // DEBUG
+
+
+//---------------------------------------------------------------------------
+// ModuleInfo.
+
+Handle<ModuleInfo> ModuleInfo::Create(Isolate* isolate,
+ ModuleDescriptor* descriptor,
+ Scope* scope) {
+ Handle<ModuleInfo> info = Allocate(isolate, descriptor->Length());
+ info->set_host_index(descriptor->Index());
+ int i = 0;
+ for (ModuleDescriptor::Iterator it = descriptor->iterator(); !it.done();
+ it.Advance(), ++i) {
+ Variable* var = scope->LookupLocal(it.local_name());
+ info->set_name(i, *(it.export_name()->string()));
+ info->set_mode(i, var->mode());
+ DCHECK(var->index() >= 0);
+ info->set_index(i, var->index());
+ }
+ DCHECK(i == info->length());
+ return info;
+}
+
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/ast/scopeinfo.h b/deps/v8/src/ast/scopeinfo.h
new file mode 100644
index 0000000000..489a672ed8
--- /dev/null
+++ b/deps/v8/src/ast/scopeinfo.h
@@ -0,0 +1,175 @@
+// 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.
+
+#ifndef V8_AST_SCOPEINFO_H_
+#define V8_AST_SCOPEINFO_H_
+
+#include "src/allocation.h"
+#include "src/ast/modules.h"
+#include "src/ast/variables.h"
+
+namespace v8 {
+namespace internal {
+
+// Cache for mapping (data, property name) into context slot index.
+// The cache contains both positive and negative results.
+// Slot index equals -1 means the property is absent.
+// Cleared at startup and prior to mark sweep collection.
+class ContextSlotCache {
+ public:
+ // Lookup context slot index for (data, name).
+ // If absent, kNotFound is returned.
+ int Lookup(Object* data, String* name, VariableMode* mode,
+ InitializationFlag* init_flag,
+ MaybeAssignedFlag* maybe_assigned_flag);
+
+ // Update an element in the cache.
+ void Update(Handle<Object> data, Handle<String> name, VariableMode mode,
+ InitializationFlag init_flag,
+ MaybeAssignedFlag maybe_assigned_flag, int slot_index);
+
+ // Clear the cache.
+ void Clear();
+
+ static const int kNotFound = -2;
+
+ private:
+ ContextSlotCache() {
+ for (int i = 0; i < kLength; ++i) {
+ keys_[i].data = NULL;
+ keys_[i].name = NULL;
+ values_[i] = kNotFound;
+ }
+ }
+
+ inline static int Hash(Object* data, String* name);
+
+#ifdef DEBUG
+ void ValidateEntry(Handle<Object> data, Handle<String> name,
+ VariableMode mode, InitializationFlag init_flag,
+ MaybeAssignedFlag maybe_assigned_flag, int slot_index);
+#endif
+
+ static const int kLength = 256;
+ struct Key {
+ Object* data;
+ String* name;
+ };
+
+ struct Value {
+ Value(VariableMode mode, InitializationFlag init_flag,
+ MaybeAssignedFlag maybe_assigned_flag, int index) {
+ DCHECK(ModeField::is_valid(mode));
+ DCHECK(InitField::is_valid(init_flag));
+ DCHECK(MaybeAssignedField::is_valid(maybe_assigned_flag));
+ DCHECK(IndexField::is_valid(index));
+ value_ = ModeField::encode(mode) | IndexField::encode(index) |
+ InitField::encode(init_flag) |
+ MaybeAssignedField::encode(maybe_assigned_flag);
+ DCHECK(mode == this->mode());
+ DCHECK(init_flag == this->initialization_flag());
+ DCHECK(maybe_assigned_flag == this->maybe_assigned_flag());
+ DCHECK(index == this->index());
+ }
+
+ explicit inline Value(uint32_t value) : value_(value) {}
+
+ uint32_t raw() { return value_; }
+
+ VariableMode mode() { return ModeField::decode(value_); }
+
+ InitializationFlag initialization_flag() {
+ return InitField::decode(value_);
+ }
+
+ MaybeAssignedFlag maybe_assigned_flag() {
+ return MaybeAssignedField::decode(value_);
+ }
+
+ int index() { return IndexField::decode(value_); }
+
+ // Bit fields in value_ (type, shift, size). Must be public so the
+ // constants can be embedded in generated code.
+ class ModeField : public BitField<VariableMode, 0, 4> {};
+ class InitField : public BitField<InitializationFlag, 4, 1> {};
+ class MaybeAssignedField : public BitField<MaybeAssignedFlag, 5, 1> {};
+ class IndexField : public BitField<int, 6, 32 - 6> {};
+
+ private:
+ uint32_t value_;
+ };
+
+ Key keys_[kLength];
+ uint32_t values_[kLength];
+
+ friend class Isolate;
+ DISALLOW_COPY_AND_ASSIGN(ContextSlotCache);
+};
+
+
+
+
+//---------------------------------------------------------------------------
+// Auxiliary class used for the description of module instances.
+// Used by Runtime_DeclareModules.
+
+class ModuleInfo: public FixedArray {
+ public:
+ static ModuleInfo* cast(Object* description) {
+ return static_cast<ModuleInfo*>(FixedArray::cast(description));
+ }
+
+ static Handle<ModuleInfo> Create(Isolate* isolate,
+ ModuleDescriptor* descriptor, Scope* scope);
+
+ // Index of module's context in host context.
+ int host_index() { return Smi::cast(get(HOST_OFFSET))->value(); }
+
+ // Name, mode, and index of the i-th export, respectively.
+ // For value exports, the index is the slot of the value in the module
+ // context, for exported modules it is the slot index of the
+ // referred module's context in the host context.
+ // TODO(rossberg): This format cannot yet handle exports of modules declared
+ // in earlier scripts.
+ String* name(int i) { return String::cast(get(name_offset(i))); }
+ VariableMode mode(int i) {
+ return static_cast<VariableMode>(Smi::cast(get(mode_offset(i)))->value());
+ }
+ int index(int i) { return Smi::cast(get(index_offset(i)))->value(); }
+
+ int length() { return (FixedArray::length() - HEADER_SIZE) / ITEM_SIZE; }
+
+ private:
+ // The internal format is: Index, (Name, VariableMode, Index)*
+ enum {
+ HOST_OFFSET,
+ NAME_OFFSET,
+ MODE_OFFSET,
+ INDEX_OFFSET,
+ HEADER_SIZE = NAME_OFFSET,
+ ITEM_SIZE = INDEX_OFFSET - NAME_OFFSET + 1
+ };
+ inline int name_offset(int i) { return NAME_OFFSET + i * ITEM_SIZE; }
+ inline int mode_offset(int i) { return MODE_OFFSET + i * ITEM_SIZE; }
+ inline int index_offset(int i) { return INDEX_OFFSET + i * ITEM_SIZE; }
+
+ static Handle<ModuleInfo> Allocate(Isolate* isolate, int length) {
+ return Handle<ModuleInfo>::cast(
+ isolate->factory()->NewFixedArray(HEADER_SIZE + ITEM_SIZE * length));
+ }
+ void set_host_index(int index) { set(HOST_OFFSET, Smi::FromInt(index)); }
+ void set_name(int i, String* name) { set(name_offset(i), name); }
+ void set_mode(int i, VariableMode mode) {
+ set(mode_offset(i), Smi::FromInt(mode));
+ }
+ void set_index(int i, int index) {
+ set(index_offset(i), Smi::FromInt(index));
+ }
+};
+
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_AST_SCOPEINFO_H_
diff --git a/deps/v8/src/ast/scopes.cc b/deps/v8/src/ast/scopes.cc
new file mode 100644
index 0000000000..c2b05b7c04
--- /dev/null
+++ b/deps/v8/src/ast/scopes.cc
@@ -0,0 +1,1698 @@
+// Copyright 2012 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/scopes.h"
+
+#include "src/accessors.h"
+#include "src/ast/scopeinfo.h"
+#include "src/bootstrapper.h"
+#include "src/messages.h"
+#include "src/parsing/parser.h" // for ParseInfo
+
+namespace v8 {
+namespace internal {
+
+// ----------------------------------------------------------------------------
+// Implementation of LocalsMap
+//
+// Note: We are storing the handle locations as key values in the hash map.
+// When inserting a new variable via Declare(), we rely on the fact that
+// the handle location remains alive for the duration of that variable
+// use. Because a Variable holding a handle with the same location exists
+// this is ensured.
+
+VariableMap::VariableMap(Zone* zone)
+ : ZoneHashMap(ZoneHashMap::PointersMatch, 8, ZoneAllocationPolicy(zone)),
+ zone_(zone) {}
+VariableMap::~VariableMap() {}
+
+
+Variable* VariableMap::Declare(Scope* scope, const AstRawString* name,
+ VariableMode mode, Variable::Kind kind,
+ InitializationFlag initialization_flag,
+ MaybeAssignedFlag maybe_assigned_flag,
+ int declaration_group_start) {
+ // AstRawStrings are unambiguous, i.e., the same string is always represented
+ // by the same AstRawString*.
+ // FIXME(marja): fix the type of Lookup.
+ Entry* p =
+ ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->hash(),
+ ZoneAllocationPolicy(zone()));
+ if (p->value == NULL) {
+ // The variable has not been declared yet -> insert it.
+ DCHECK(p->key == name);
+ if (kind == Variable::CLASS) {
+ p->value = new (zone())
+ ClassVariable(scope, name, mode, initialization_flag,
+ maybe_assigned_flag, declaration_group_start);
+ } else {
+ p->value = new (zone()) Variable(
+ scope, name, mode, kind, initialization_flag, maybe_assigned_flag);
+ }
+ }
+ return reinterpret_cast<Variable*>(p->value);
+}
+
+
+Variable* VariableMap::Lookup(const AstRawString* name) {
+ Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash());
+ if (p != NULL) {
+ DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name);
+ DCHECK(p->value != NULL);
+ return reinterpret_cast<Variable*>(p->value);
+ }
+ return NULL;
+}
+
+
+SloppyBlockFunctionMap::SloppyBlockFunctionMap(Zone* zone)
+ : ZoneHashMap(ZoneHashMap::PointersMatch, 8, ZoneAllocationPolicy(zone)),
+ zone_(zone) {}
+SloppyBlockFunctionMap::~SloppyBlockFunctionMap() {}
+
+
+void SloppyBlockFunctionMap::Declare(const AstRawString* name,
+ SloppyBlockFunctionStatement* stmt) {
+ // 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_));
+ if (p->value == nullptr) {
+ p->value = new (zone_->New(sizeof(Vector))) Vector(zone_);
+ }
+ Vector* delegates = static_cast<Vector*>(p->value);
+ delegates->push_back(stmt);
+}
+
+
+// ----------------------------------------------------------------------------
+// Implementation of Scope
+
+Scope::Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type,
+ AstValueFactory* ast_value_factory, FunctionKind function_kind)
+ : inner_scopes_(4, zone),
+ variables_(zone),
+ temps_(4, zone),
+ params_(4, zone),
+ unresolved_(16, zone),
+ decls_(4, zone),
+ module_descriptor_(
+ scope_type == MODULE_SCOPE ? ModuleDescriptor::New(zone) : NULL),
+ sloppy_block_function_map_(zone),
+ already_resolved_(false),
+ ast_value_factory_(ast_value_factory),
+ zone_(zone),
+ class_declaration_group_start_(-1) {
+ SetDefaults(scope_type, outer_scope, Handle<ScopeInfo>::null(),
+ function_kind);
+ // The outermost scope must be a script scope.
+ DCHECK(scope_type == SCRIPT_SCOPE || outer_scope != NULL);
+ DCHECK(!HasIllegalRedeclaration());
+}
+
+
+Scope::Scope(Zone* zone, Scope* inner_scope, ScopeType scope_type,
+ Handle<ScopeInfo> scope_info, AstValueFactory* value_factory)
+ : inner_scopes_(4, zone),
+ variables_(zone),
+ temps_(4, zone),
+ params_(4, zone),
+ unresolved_(16, zone),
+ decls_(4, zone),
+ module_descriptor_(NULL),
+ sloppy_block_function_map_(zone),
+ already_resolved_(true),
+ ast_value_factory_(value_factory),
+ zone_(zone),
+ class_declaration_group_start_(-1) {
+ SetDefaults(scope_type, NULL, scope_info);
+ if (!scope_info.is_null()) {
+ num_heap_slots_ = scope_info_->ContextLength();
+ }
+ // Ensure at least MIN_CONTEXT_SLOTS to indicate a materialized context.
+ num_heap_slots_ = Max(num_heap_slots_,
+ static_cast<int>(Context::MIN_CONTEXT_SLOTS));
+ AddInnerScope(inner_scope);
+}
+
+
+Scope::Scope(Zone* zone, Scope* inner_scope,
+ const AstRawString* catch_variable_name,
+ AstValueFactory* value_factory)
+ : inner_scopes_(1, zone),
+ variables_(zone),
+ temps_(0, zone),
+ params_(0, zone),
+ unresolved_(0, zone),
+ decls_(0, zone),
+ module_descriptor_(NULL),
+ sloppy_block_function_map_(zone),
+ already_resolved_(true),
+ ast_value_factory_(value_factory),
+ zone_(zone),
+ class_declaration_group_start_(-1) {
+ SetDefaults(CATCH_SCOPE, NULL, Handle<ScopeInfo>::null());
+ AddInnerScope(inner_scope);
+ ++num_var_or_const_;
+ num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
+ Variable* variable = variables_.Declare(this,
+ catch_variable_name,
+ VAR,
+ Variable::NORMAL,
+ kCreatedInitialized);
+ AllocateHeapSlot(variable);
+}
+
+
+void Scope::SetDefaults(ScopeType scope_type, Scope* outer_scope,
+ Handle<ScopeInfo> scope_info,
+ FunctionKind function_kind) {
+ outer_scope_ = outer_scope;
+ scope_type_ = scope_type;
+ is_declaration_scope_ =
+ is_eval_scope() || is_function_scope() ||
+ is_module_scope() || is_script_scope();
+ function_kind_ = function_kind;
+ scope_name_ = ast_value_factory_->empty_string();
+ dynamics_ = nullptr;
+ receiver_ = nullptr;
+ new_target_ = nullptr;
+ function_ = nullptr;
+ arguments_ = nullptr;
+ this_function_ = nullptr;
+ illegal_redecl_ = nullptr;
+ scope_inside_with_ = false;
+ scope_contains_with_ = false;
+ scope_calls_eval_ = false;
+ scope_uses_arguments_ = false;
+ scope_uses_super_property_ = false;
+ asm_module_ = false;
+ asm_function_ = outer_scope != NULL && outer_scope->asm_module_;
+ // Inherit the language mode from the parent scope.
+ language_mode_ = outer_scope != NULL ? outer_scope->language_mode_ : SLOPPY;
+ outer_scope_calls_sloppy_eval_ = false;
+ inner_scope_calls_eval_ = false;
+ scope_nonlinear_ = false;
+ force_eager_compilation_ = false;
+ force_context_allocation_ = (outer_scope != NULL && !is_function_scope())
+ ? outer_scope->has_forced_context_allocation() : false;
+ num_var_or_const_ = 0;
+ num_stack_slots_ = 0;
+ num_heap_slots_ = 0;
+ num_global_slots_ = 0;
+ arity_ = 0;
+ has_simple_parameters_ = true;
+ rest_parameter_ = NULL;
+ rest_index_ = -1;
+ scope_info_ = scope_info;
+ start_position_ = RelocInfo::kNoPosition;
+ end_position_ = RelocInfo::kNoPosition;
+ if (!scope_info.is_null()) {
+ scope_calls_eval_ = scope_info->CallsEval();
+ language_mode_ = scope_info->language_mode();
+ is_declaration_scope_ = scope_info->is_declaration_scope();
+ function_kind_ = scope_info->function_kind();
+ }
+}
+
+
+Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone,
+ Context* context, Scope* script_scope) {
+ // Reconstruct the outer scope chain from a closure's context chain.
+ Scope* current_scope = NULL;
+ Scope* innermost_scope = NULL;
+ bool contains_with = false;
+ while (!context->IsNativeContext()) {
+ if (context->IsWithContext()) {
+ Scope* with_scope = new (zone)
+ Scope(zone, current_scope, WITH_SCOPE, Handle<ScopeInfo>::null(),
+ script_scope->ast_value_factory_);
+ current_scope = with_scope;
+ // All the inner scopes are inside a with.
+ contains_with = true;
+ for (Scope* s = innermost_scope; s != NULL; s = s->outer_scope()) {
+ s->scope_inside_with_ = true;
+ }
+ } else if (context->IsScriptContext()) {
+ ScopeInfo* scope_info = context->scope_info();
+ current_scope = new (zone) Scope(zone, current_scope, SCRIPT_SCOPE,
+ Handle<ScopeInfo>(scope_info),
+ script_scope->ast_value_factory_);
+ } else if (context->IsModuleContext()) {
+ ScopeInfo* scope_info = context->module()->scope_info();
+ current_scope = new (zone) Scope(zone, current_scope, MODULE_SCOPE,
+ Handle<ScopeInfo>(scope_info),
+ script_scope->ast_value_factory_);
+ } else if (context->IsFunctionContext()) {
+ ScopeInfo* scope_info = context->closure()->shared()->scope_info();
+ current_scope = new (zone) Scope(zone, current_scope, FUNCTION_SCOPE,
+ Handle<ScopeInfo>(scope_info),
+ script_scope->ast_value_factory_);
+ if (scope_info->IsAsmFunction()) current_scope->asm_function_ = true;
+ if (scope_info->IsAsmModule()) current_scope->asm_module_ = true;
+ } else if (context->IsBlockContext()) {
+ ScopeInfo* scope_info = context->scope_info();
+ current_scope = new (zone)
+ Scope(zone, current_scope, BLOCK_SCOPE, Handle<ScopeInfo>(scope_info),
+ script_scope->ast_value_factory_);
+ } else {
+ DCHECK(context->IsCatchContext());
+ String* name = context->catch_name();
+ current_scope = new (zone) Scope(
+ zone, current_scope,
+ script_scope->ast_value_factory_->GetString(Handle<String>(name)),
+ script_scope->ast_value_factory_);
+ }
+ if (contains_with) current_scope->RecordWithStatement();
+ if (innermost_scope == NULL) innermost_scope = current_scope;
+
+ // Forget about a with when we move to a context for a different function.
+ if (context->previous()->closure() != context->closure()) {
+ contains_with = false;
+ }
+ context = context->previous();
+ }
+
+ script_scope->AddInnerScope(current_scope);
+ script_scope->PropagateScopeInfo(false);
+ return (innermost_scope == NULL) ? script_scope : innermost_scope;
+}
+
+
+bool Scope::Analyze(ParseInfo* info) {
+ DCHECK(info->literal() != NULL);
+ DCHECK(info->scope() == NULL);
+ Scope* scope = info->literal()->scope();
+ Scope* top = scope;
+
+ // Traverse the scope tree up to the first unresolved scope or the global
+ // scope and start scope resolution and variable allocation from that scope.
+ while (!top->is_script_scope() &&
+ !top->outer_scope()->already_resolved()) {
+ top = top->outer_scope();
+ }
+
+ // Allocate the variables.
+ {
+ AstNodeFactory ast_node_factory(info->ast_value_factory());
+ if (!top->AllocateVariables(info, &ast_node_factory)) {
+ DCHECK(top->pending_error_handler_.has_pending_error());
+ top->pending_error_handler_.ThrowPendingError(info->isolate(),
+ info->script());
+ return false;
+ }
+ }
+
+#ifdef DEBUG
+ if (info->script_is_native() ? FLAG_print_builtin_scopes
+ : FLAG_print_scopes) {
+ scope->Print();
+ }
+#endif
+
+ info->set_scope(scope);
+ return true;
+}
+
+
+void Scope::Initialize() {
+ DCHECK(!already_resolved());
+
+ // Add this scope as a new inner scope of the outer scope.
+ if (outer_scope_ != NULL) {
+ outer_scope_->inner_scopes_.Add(this, zone());
+ scope_inside_with_ = outer_scope_->scope_inside_with_ || is_with_scope();
+ } else {
+ scope_inside_with_ = is_with_scope();
+ }
+
+ // Declare convenience variables and the receiver.
+ if (is_declaration_scope() && has_this_declaration()) {
+ bool subclass_constructor = IsSubclassConstructor(function_kind_);
+ Variable* var = variables_.Declare(
+ this, ast_value_factory_->this_string(),
+ subclass_constructor ? CONST : VAR, Variable::THIS,
+ subclass_constructor ? kNeedsInitialization : kCreatedInitialized);
+ receiver_ = var;
+ }
+
+ if (is_function_scope() && !is_arrow_scope()) {
+ // 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.
+ variables_.Declare(this, ast_value_factory_->arguments_string(), VAR,
+ Variable::ARGUMENTS, kCreatedInitialized);
+
+ variables_.Declare(this, ast_value_factory_->new_target_string(), CONST,
+ Variable::NORMAL, kCreatedInitialized);
+
+ if (IsConciseMethod(function_kind_) || IsClassConstructor(function_kind_) ||
+ IsAccessorFunction(function_kind_)) {
+ variables_.Declare(this, ast_value_factory_->this_function_string(),
+ CONST, Variable::NORMAL, kCreatedInitialized);
+ }
+ }
+}
+
+
+Scope* Scope::FinalizeBlockScope() {
+ DCHECK(is_block_scope());
+ DCHECK(temps_.is_empty());
+ DCHECK(params_.is_empty());
+
+ if (num_var_or_const() > 0 ||
+ (is_declaration_scope() && calls_sloppy_eval())) {
+ return this;
+ }
+
+ // Remove this scope from outer scope.
+ outer_scope()->RemoveInnerScope(this);
+
+ // Reparent inner scopes.
+ for (int i = 0; i < inner_scopes_.length(); i++) {
+ outer_scope()->AddInnerScope(inner_scopes_[i]);
+ }
+
+ // Move unresolved variables
+ for (int i = 0; i < unresolved_.length(); i++) {
+ outer_scope()->unresolved_.Add(unresolved_[i], zone());
+ }
+
+ PropagateUsageFlagsToScope(outer_scope_);
+
+ return NULL;
+}
+
+
+void Scope::ReplaceOuterScope(Scope* outer) {
+ DCHECK_NOT_NULL(outer);
+ DCHECK_NOT_NULL(outer_scope_);
+ DCHECK(!already_resolved());
+ DCHECK(!outer->already_resolved());
+ DCHECK(!outer_scope_->already_resolved());
+ outer_scope_->RemoveInnerScope(this);
+ outer->AddInnerScope(this);
+ outer_scope_ = outer;
+}
+
+
+void Scope::PropagateUsageFlagsToScope(Scope* other) {
+ DCHECK_NOT_NULL(other);
+ DCHECK(!already_resolved());
+ DCHECK(!other->already_resolved());
+ if (uses_arguments()) other->RecordArgumentsUsage();
+ if (uses_super_property()) other->RecordSuperPropertyUsage();
+ if (calls_eval()) other->RecordEvalCall();
+ if (scope_contains_with_) other->RecordWithStatement();
+}
+
+
+Variable* Scope::LookupLocal(const AstRawString* name) {
+ Variable* result = variables_.Lookup(name);
+ if (result != NULL || scope_info_.is_null()) {
+ return result;
+ }
+ Handle<String> name_handle = name->string();
+ // The Scope is backed up by ScopeInfo. This means it cannot operate in a
+ // heap-independent mode, and all strings must be internalized immediately. So
+ // it's ok to get the Handle<String> here.
+ // If we have a serialized scope info, we might find the variable there.
+ // There should be no local slot with the given name.
+ DCHECK(scope_info_->StackSlotIndex(*name_handle) < 0 || is_block_scope());
+
+ // Check context slot lookup.
+ VariableMode mode;
+ VariableLocation location = VariableLocation::CONTEXT;
+ InitializationFlag init_flag;
+ MaybeAssignedFlag maybe_assigned_flag;
+ int index = ScopeInfo::ContextSlotIndex(scope_info_, name_handle, &mode,
+ &init_flag, &maybe_assigned_flag);
+ if (index < 0) {
+ location = VariableLocation::GLOBAL;
+ index = ScopeInfo::ContextGlobalSlotIndex(scope_info_, name_handle, &mode,
+ &init_flag, &maybe_assigned_flag);
+ }
+ if (index < 0) {
+ // Check parameters.
+ index = scope_info_->ParameterIndex(*name_handle);
+ if (index < 0) return NULL;
+
+ mode = DYNAMIC;
+ location = VariableLocation::LOOKUP;
+ init_flag = kCreatedInitialized;
+ // Be conservative and flag parameters as maybe assigned. Better information
+ // would require ScopeInfo to serialize the maybe_assigned bit also for
+ // parameters.
+ maybe_assigned_flag = kMaybeAssigned;
+ } else {
+ DCHECK(location != VariableLocation::GLOBAL ||
+ (is_script_scope() && IsDeclaredVariableMode(mode) &&
+ !IsLexicalVariableMode(mode)));
+ }
+
+ Variable::Kind kind = Variable::NORMAL;
+ if (location == VariableLocation::CONTEXT &&
+ index == scope_info_->ReceiverContextSlotIndex()) {
+ kind = Variable::THIS;
+ }
+ // TODO(marja, rossberg): Correctly declare FUNCTION, CLASS, NEW_TARGET, and
+ // ARGUMENTS bindings as their corresponding Variable::Kind.
+
+ Variable* var = variables_.Declare(this, name, mode, kind, init_flag,
+ maybe_assigned_flag);
+ var->AllocateTo(location, index);
+ return var;
+}
+
+
+Variable* Scope::LookupFunctionVar(const AstRawString* name,
+ AstNodeFactory* factory) {
+ if (function_ != NULL && function_->proxy()->raw_name() == name) {
+ return function_->proxy()->var();
+ } else if (!scope_info_.is_null()) {
+ // If we are backed by a scope info, try to lookup the variable there.
+ VariableMode mode;
+ int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode);
+ if (index < 0) return NULL;
+ Variable* var = new (zone())
+ Variable(this, name, mode, Variable::NORMAL, kCreatedInitialized);
+ VariableProxy* proxy = factory->NewVariableProxy(var);
+ VariableDeclaration* declaration = factory->NewVariableDeclaration(
+ proxy, mode, this, RelocInfo::kNoPosition);
+ DeclareFunctionVar(declaration);
+ var->AllocateTo(VariableLocation::CONTEXT, index);
+ return var;
+ } else {
+ return NULL;
+ }
+}
+
+
+Variable* Scope::Lookup(const AstRawString* name) {
+ for (Scope* scope = this;
+ scope != NULL;
+ scope = scope->outer_scope()) {
+ Variable* var = scope->LookupLocal(name);
+ if (var != NULL) return var;
+ }
+ return NULL;
+}
+
+
+Variable* Scope::DeclareParameter(
+ const AstRawString* name, VariableMode mode,
+ bool is_optional, bool is_rest, bool* is_duplicate) {
+ DCHECK(!already_resolved());
+ DCHECK(is_function_scope());
+ DCHECK(!is_optional || !is_rest);
+ Variable* var;
+ if (mode == TEMPORARY) {
+ var = NewTemporary(name);
+ } else {
+ var = variables_.Declare(this, name, mode, Variable::NORMAL,
+ kCreatedInitialized);
+ // TODO(wingo): Avoid O(n^2) check.
+ *is_duplicate = IsDeclaredParameter(name);
+ }
+ if (!is_optional && !is_rest && arity_ == params_.length()) {
+ ++arity_;
+ }
+ if (is_rest) {
+ DCHECK_NULL(rest_parameter_);
+ rest_parameter_ = var;
+ rest_index_ = num_parameters();
+ }
+ params_.Add(var, zone());
+ return var;
+}
+
+
+Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode,
+ InitializationFlag init_flag, Variable::Kind kind,
+ MaybeAssignedFlag maybe_assigned_flag,
+ int declaration_group_start) {
+ DCHECK(!already_resolved());
+ // This function handles VAR, LET, and CONST modes. DYNAMIC variables are
+ // introduces during variable allocation, and TEMPORARY variables are
+ // allocated via NewTemporary().
+ DCHECK(IsDeclaredVariableMode(mode));
+ ++num_var_or_const_;
+ return variables_.Declare(this, name, mode, kind, init_flag,
+ maybe_assigned_flag, declaration_group_start);
+}
+
+
+Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) {
+ DCHECK(is_script_scope());
+ return variables_.Declare(this,
+ name,
+ DYNAMIC_GLOBAL,
+ Variable::NORMAL,
+ kCreatedInitialized);
+}
+
+
+bool Scope::RemoveUnresolved(VariableProxy* var) {
+ // Most likely (always?) any variable we want to remove
+ // was just added before, so we search backwards.
+ for (int i = unresolved_.length(); i-- > 0;) {
+ if (unresolved_[i] == var) {
+ unresolved_.Remove(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+Variable* Scope::NewTemporary(const AstRawString* name) {
+ DCHECK(!already_resolved());
+ Scope* scope = this->ClosureScope();
+ Variable* var = new(zone()) Variable(scope,
+ name,
+ TEMPORARY,
+ Variable::NORMAL,
+ kCreatedInitialized);
+ scope->AddTemporary(var);
+ return var;
+}
+
+
+bool Scope::RemoveTemporary(Variable* var) {
+ // Most likely (always?) any temporary variable we want to remove
+ // was just added before, so we search backwards.
+ for (int i = temps_.length(); i-- > 0;) {
+ if (temps_[i] == var) {
+ temps_.Remove(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void Scope::AddDeclaration(Declaration* declaration) {
+ decls_.Add(declaration, zone());
+}
+
+
+void Scope::SetIllegalRedeclaration(Expression* expression) {
+ // Record only the first illegal redeclaration.
+ if (!HasIllegalRedeclaration()) {
+ illegal_redecl_ = expression;
+ }
+ DCHECK(HasIllegalRedeclaration());
+}
+
+
+Expression* Scope::GetIllegalRedeclaration() {
+ DCHECK(HasIllegalRedeclaration());
+ return illegal_redecl_;
+}
+
+
+Declaration* Scope::CheckConflictingVarDeclarations() {
+ int length = decls_.length();
+ for (int i = 0; i < length; i++) {
+ Declaration* decl = decls_[i];
+ // We don't create a separate scope to hold the function name of a function
+ // expression, so we have to make sure not to consider it when checking for
+ // conflicts (since it's conceptually "outside" the declaration scope).
+ if (is_function_scope() && decl == function()) continue;
+ if (IsLexicalVariableMode(decl->mode()) && !is_block_scope()) continue;
+ const AstRawString* name = decl->proxy()->raw_name();
+
+ // Iterate through all scopes until and including the declaration scope.
+ Scope* previous = NULL;
+ Scope* current = decl->scope();
+ // Lexical vs lexical conflicts within the same scope have already been
+ // captured in Parser::Declare. The only conflicts we still need to check
+ // are lexical vs VAR, or any declarations within a declaration block scope
+ // vs lexical declarations in its surrounding (function) scope.
+ if (IsLexicalVariableMode(decl->mode())) current = current->outer_scope_;
+ do {
+ // There is a conflict if there exists a non-VAR binding.
+ Variable* other_var = current->variables_.Lookup(name);
+ if (other_var != NULL && IsLexicalVariableMode(other_var->mode())) {
+ return decl;
+ }
+ previous = current;
+ current = current->outer_scope_;
+ } while (!previous->is_declaration_scope());
+ }
+ return NULL;
+}
+
+
+class VarAndOrder {
+ public:
+ VarAndOrder(Variable* var, int order) : var_(var), order_(order) { }
+ Variable* var() const { return var_; }
+ int order() const { return order_; }
+ static int Compare(const VarAndOrder* a, const VarAndOrder* b) {
+ return a->order_ - b->order_;
+ }
+
+ private:
+ Variable* var_;
+ int order_;
+};
+
+
+void Scope::CollectStackAndContextLocals(
+ ZoneList<Variable*>* stack_locals, ZoneList<Variable*>* context_locals,
+ ZoneList<Variable*>* context_globals,
+ ZoneList<Variable*>* strong_mode_free_variables) {
+ DCHECK(stack_locals != NULL);
+ DCHECK(context_locals != NULL);
+ DCHECK(context_globals != NULL);
+
+ // Collect temporaries which are always allocated on the stack, unless the
+ // context as a whole has forced context allocation.
+ for (int i = 0; i < temps_.length(); i++) {
+ Variable* var = temps_[i];
+ if (var->is_used()) {
+ if (var->IsContextSlot()) {
+ DCHECK(has_forced_context_allocation());
+ context_locals->Add(var, zone());
+ } else if (var->IsStackLocal()) {
+ stack_locals->Add(var, zone());
+ } else {
+ DCHECK(var->IsParameter());
+ }
+ }
+ }
+
+ // Collect declared local variables.
+ ZoneList<VarAndOrder> vars(variables_.occupancy(), zone());
+ for (VariableMap::Entry* p = variables_.Start();
+ p != NULL;
+ p = variables_.Next(p)) {
+ Variable* var = reinterpret_cast<Variable*>(p->value);
+ if (strong_mode_free_variables && var->has_strong_mode_reference() &&
+ var->mode() == DYNAMIC_GLOBAL) {
+ strong_mode_free_variables->Add(var, zone());
+ }
+
+ if (var->is_used()) {
+ vars.Add(VarAndOrder(var, p->order), zone());
+ }
+ }
+ vars.Sort(VarAndOrder::Compare);
+ int var_count = vars.length();
+ for (int i = 0; i < var_count; i++) {
+ Variable* var = vars[i].var();
+ if (var->IsStackLocal()) {
+ stack_locals->Add(var, zone());
+ } else if (var->IsContextSlot()) {
+ context_locals->Add(var, zone());
+ } else if (var->IsGlobalSlot()) {
+ context_globals->Add(var, zone());
+ }
+ }
+}
+
+
+bool Scope::AllocateVariables(ParseInfo* info, AstNodeFactory* factory) {
+ // 1) Propagate scope information.
+ bool outer_scope_calls_sloppy_eval = false;
+ if (outer_scope_ != NULL) {
+ outer_scope_calls_sloppy_eval =
+ outer_scope_->outer_scope_calls_sloppy_eval() |
+ outer_scope_->calls_sloppy_eval();
+ }
+ PropagateScopeInfo(outer_scope_calls_sloppy_eval);
+
+ // 2) Resolve variables.
+ if (!ResolveVariablesRecursively(info, factory)) return false;
+
+ // 3) Allocate variables.
+ AllocateVariablesRecursively(info->isolate());
+
+ return true;
+}
+
+
+bool Scope::HasTrivialContext() const {
+ // A function scope has a trivial context if it always is the global
+ // context. We iteratively scan out the context chain to see if
+ // there is anything that makes this scope non-trivial; otherwise we
+ // return true.
+ for (const Scope* scope = this; scope != NULL; scope = scope->outer_scope_) {
+ if (scope->is_eval_scope()) return false;
+ if (scope->scope_inside_with_) return false;
+ if (scope->ContextLocalCount() > 0) return false;
+ if (scope->ContextGlobalCount() > 0) return false;
+ }
+ return true;
+}
+
+
+bool Scope::HasTrivialOuterContext() const {
+ Scope* outer = outer_scope_;
+ if (outer == NULL) return true;
+ // Note that the outer context may be trivial in general, but the current
+ // scope may be inside a 'with' statement in which case the outer context
+ // for this scope is not trivial.
+ return !scope_inside_with_ && outer->HasTrivialContext();
+}
+
+
+bool Scope::AllowsLazyParsing() const {
+ // If we are inside a block scope, we must parse eagerly to find out how
+ // to allocate variables on the block scope. At this point, declarations may
+ // not have yet been parsed.
+ for (const Scope* scope = this; scope != NULL; scope = scope->outer_scope_) {
+ if (scope->is_block_scope()) return false;
+ }
+ return AllowsLazyCompilation();
+}
+
+
+bool Scope::AllowsLazyCompilation() const { return !force_eager_compilation_; }
+
+
+bool Scope::AllowsLazyCompilationWithoutContext() const {
+ return !force_eager_compilation_ && HasTrivialOuterContext();
+}
+
+
+int Scope::ContextChainLength(Scope* scope) {
+ int n = 0;
+ for (Scope* s = this; s != scope; s = s->outer_scope_) {
+ DCHECK(s != NULL); // scope must be in the scope chain
+ if (s->NeedsContext()) n++;
+ }
+ return n;
+}
+
+
+int Scope::MaxNestedContextChainLength() {
+ int max_context_chain_length = 0;
+ for (int i = 0; i < inner_scopes_.length(); i++) {
+ Scope* scope = inner_scopes_[i];
+ max_context_chain_length = std::max(scope->MaxNestedContextChainLength(),
+ max_context_chain_length);
+ }
+ if (NeedsContext()) {
+ max_context_chain_length += 1;
+ }
+ return max_context_chain_length;
+}
+
+
+Scope* Scope::DeclarationScope() {
+ Scope* scope = this;
+ while (!scope->is_declaration_scope()) {
+ scope = scope->outer_scope();
+ }
+ return scope;
+}
+
+
+Scope* Scope::ClosureScope() {
+ Scope* scope = this;
+ while (!scope->is_declaration_scope() || scope->is_block_scope()) {
+ scope = scope->outer_scope();
+ }
+ return scope;
+}
+
+
+Scope* Scope::ReceiverScope() {
+ Scope* scope = this;
+ while (!scope->is_script_scope() &&
+ (!scope->is_function_scope() || scope->is_arrow_scope())) {
+ scope = scope->outer_scope();
+ }
+ return scope;
+}
+
+
+
+Handle<ScopeInfo> Scope::GetScopeInfo(Isolate* isolate) {
+ if (scope_info_.is_null()) {
+ scope_info_ = ScopeInfo::Create(isolate, zone(), this);
+ }
+ return scope_info_;
+}
+
+
+void Scope::GetNestedScopeChain(Isolate* isolate,
+ List<Handle<ScopeInfo> >* chain, int position) {
+ if (!is_eval_scope()) chain->Add(Handle<ScopeInfo>(GetScopeInfo(isolate)));
+
+ for (int i = 0; i < inner_scopes_.length(); i++) {
+ Scope* scope = inner_scopes_[i];
+ int beg_pos = scope->start_position();
+ int end_pos = scope->end_position();
+ DCHECK(beg_pos >= 0 && end_pos >= 0);
+ if (beg_pos <= position && position < end_pos) {
+ scope->GetNestedScopeChain(isolate, chain, position);
+ return;
+ }
+ }
+}
+
+
+void Scope::CollectNonLocals(HashMap* non_locals) {
+ // Collect non-local variables referenced in the scope.
+ // TODO(yangguo): store non-local variables explicitly if we can no longer
+ // rely on unresolved_ to find them.
+ for (int i = 0; i < unresolved_.length(); i++) {
+ VariableProxy* proxy = unresolved_[i];
+ if (proxy->is_resolved() && proxy->var()->IsStackAllocated()) continue;
+ Handle<String> name = proxy->name();
+ void* key = reinterpret_cast<void*>(name.location());
+ HashMap::Entry* entry = non_locals->LookupOrInsert(key, name->Hash());
+ entry->value = key;
+ }
+ for (int i = 0; i < inner_scopes_.length(); i++) {
+ inner_scopes_[i]->CollectNonLocals(non_locals);
+ }
+}
+
+
+void Scope::ReportMessage(int start_position, int end_position,
+ MessageTemplate::Template message,
+ const AstRawString* arg) {
+ // Propagate the error to the topmost scope targeted by this scope analysis
+ // phase.
+ Scope* top = this;
+ while (!top->is_script_scope() && !top->outer_scope()->already_resolved()) {
+ top = top->outer_scope();
+ }
+
+ top->pending_error_handler_.ReportMessageAt(start_position, end_position,
+ message, arg, kReferenceError);
+}
+
+
+#ifdef DEBUG
+static 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?
+ case FUNCTION_SCOPE:
+ return IsArrowFunction(function_kind) ? "arrow" : "function";
+ case MODULE_SCOPE: return "module";
+ case SCRIPT_SCOPE: return "global";
+ case CATCH_SCOPE: return "catch";
+ case BLOCK_SCOPE: return is_declaration_scope ? "varblock" : "block";
+ case WITH_SCOPE: return "with";
+ }
+ UNREACHABLE();
+ return NULL;
+}
+
+
+static void Indent(int n, const char* str) {
+ PrintF("%*s%s", n, "", str);
+}
+
+
+static void PrintName(const AstRawString* name) {
+ PrintF("%.*s", name->length(), name->raw_data());
+}
+
+
+static void PrintLocation(Variable* var) {
+ switch (var->location()) {
+ case VariableLocation::UNALLOCATED:
+ break;
+ case VariableLocation::PARAMETER:
+ PrintF("parameter[%d]", var->index());
+ break;
+ case VariableLocation::LOCAL:
+ PrintF("local[%d]", var->index());
+ break;
+ case VariableLocation::CONTEXT:
+ PrintF("context[%d]", var->index());
+ break;
+ case VariableLocation::GLOBAL:
+ PrintF("global[%d]", var->index());
+ break;
+ case VariableLocation::LOOKUP:
+ PrintF("lookup");
+ break;
+ }
+}
+
+
+static void PrintVar(int indent, Variable* var) {
+ if (var->is_used() || !var->IsUnallocated()) {
+ Indent(indent, Variable::Mode2String(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() == kMaybeAssigned) {
+ if (comma) PrintF(", ");
+ PrintF("maybe assigned");
+ }
+ PrintF("\n");
+ }
+}
+
+
+static void PrintMap(int indent, VariableMap* map) {
+ for (VariableMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
+ Variable* var = reinterpret_cast<Variable*>(p->value);
+ if (var == NULL) {
+ Indent(indent, "<?>\n");
+ } else {
+ PrintVar(indent, var);
+ }
+ }
+}
+
+
+void Scope::Print(int n) {
+ int n0 = (n > 0 ? n : 0);
+ int n1 = n0 + 2; // indentation
+
+ // Print header.
+ Indent(n0, Header(scope_type_, function_kind_, is_declaration_scope()));
+ if (scope_name_ != nullptr && !scope_name_->IsEmpty()) {
+ PrintF(" ");
+ PrintName(scope_name_);
+ }
+
+ // Print parameters, if any.
+ if (is_function_scope()) {
+ PrintF(" (");
+ for (int i = 0; i < params_.length(); i++) {
+ if (i > 0) PrintF(", ");
+ const AstRawString* name = params_[i]->raw_name();
+ if (name->IsEmpty())
+ PrintF(".%p", reinterpret_cast<void*>(params_[i]));
+ else
+ PrintName(name);
+ }
+ PrintF(")");
+ }
+
+ PrintF(" { // (%d, %d)\n", start_position(), end_position());
+
+ // Function name, if any (named function literals, only).
+ if (function_ != NULL) {
+ Indent(n1, "// (local) function name: ");
+ PrintName(function_->proxy()->raw_name());
+ PrintF("\n");
+ }
+
+ // Scope info.
+ if (HasTrivialOuterContext()) {
+ Indent(n1, "// scope has trivial outer context\n");
+ }
+ if (is_strong(language_mode())) {
+ Indent(n1, "// strong mode scope\n");
+ } else if (is_strict(language_mode())) {
+ Indent(n1, "// strict mode scope\n");
+ }
+ if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n");
+ if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n");
+ if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n");
+ if (scope_uses_arguments_) Indent(n1, "// scope uses 'arguments'\n");
+ if (scope_uses_super_property_)
+ Indent(n1, "// scope uses 'super' property\n");
+ if (outer_scope_calls_sloppy_eval_) {
+ Indent(n1, "// outer scope calls 'eval' in sloppy context\n");
+ }
+ if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
+ if (num_stack_slots_ > 0) {
+ Indent(n1, "// ");
+ PrintF("%d stack slots\n", num_stack_slots_);
+ }
+ if (num_heap_slots_ > 0) {
+ Indent(n1, "// ");
+ PrintF("%d heap slots (including %d global slots)\n", num_heap_slots_,
+ num_global_slots_);
+ }
+
+ // Print locals.
+ if (function_ != NULL) {
+ Indent(n1, "// function var:\n");
+ PrintVar(n1, function_->proxy()->var());
+ }
+
+ if (temps_.length() > 0) {
+ Indent(n1, "// temporary vars:\n");
+ for (int i = 0; i < temps_.length(); i++) {
+ PrintVar(n1, temps_[i]);
+ }
+ }
+
+ if (variables_.Start() != NULL) {
+ Indent(n1, "// local vars:\n");
+ PrintMap(n1, &variables_);
+ }
+
+ if (dynamics_ != NULL) {
+ Indent(n1, "// dynamic vars:\n");
+ PrintMap(n1, dynamics_->GetMap(DYNAMIC));
+ PrintMap(n1, dynamics_->GetMap(DYNAMIC_LOCAL));
+ PrintMap(n1, dynamics_->GetMap(DYNAMIC_GLOBAL));
+ }
+
+ // Print inner scopes (disable by providing negative n).
+ if (n >= 0) {
+ for (int i = 0; i < inner_scopes_.length(); i++) {
+ PrintF("\n");
+ inner_scopes_[i]->Print(n1);
+ }
+ }
+
+ Indent(n0, "}\n");
+}
+#endif // DEBUG
+
+
+Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) {
+ if (dynamics_ == NULL) dynamics_ = new (zone()) DynamicScopePart(zone());
+ VariableMap* map = dynamics_->GetMap(mode);
+ Variable* var = map->Lookup(name);
+ if (var == NULL) {
+ // Declare a new non-local.
+ InitializationFlag init_flag = (mode == VAR)
+ ? kCreatedInitialized : kNeedsInitialization;
+ var = map->Declare(NULL,
+ name,
+ mode,
+ Variable::NORMAL,
+ init_flag);
+ // Allocate it by giving it a dynamic lookup.
+ var->AllocateTo(VariableLocation::LOOKUP, -1);
+ }
+ return var;
+}
+
+
+Variable* Scope::LookupRecursive(VariableProxy* proxy,
+ BindingKind* binding_kind,
+ AstNodeFactory* factory) {
+ DCHECK(binding_kind != NULL);
+ if (already_resolved() && is_with_scope()) {
+ // Short-cut: if the scope is deserialized from a scope info, variable
+ // allocation is already fixed. We can simply return with dynamic lookup.
+ *binding_kind = DYNAMIC_LOOKUP;
+ return NULL;
+ }
+
+ // Try to find the variable in this scope.
+ Variable* var = LookupLocal(proxy->raw_name());
+
+ // We found a variable and we are done. (Even if there is an 'eval' in
+ // this scope which introduces the same variable again, the resulting
+ // variable remains the same.)
+ if (var != NULL) {
+ *binding_kind = BOUND;
+ return var;
+ }
+
+ // We did not find a variable locally. Check against the function variable,
+ // if any. We can do this for all scopes, since the function variable is
+ // only present - if at all - for function scopes.
+ *binding_kind = UNBOUND;
+ var = LookupFunctionVar(proxy->raw_name(), factory);
+ if (var != NULL) {
+ *binding_kind = BOUND;
+ } else if (outer_scope_ != NULL) {
+ var = outer_scope_->LookupRecursive(proxy, binding_kind, factory);
+ if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) {
+ var->ForceContextAllocation();
+ }
+ } else {
+ DCHECK(is_script_scope());
+ }
+
+ // "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes.
+ // TODO(wingo): There are other variables in this category; add them.
+ bool name_can_be_shadowed = var == nullptr || !var->is_this();
+
+ if (is_with_scope() && name_can_be_shadowed) {
+ DCHECK(!already_resolved());
+ // The current scope is a with scope, so the variable binding can not be
+ // statically resolved. However, note that it was necessary to do a lookup
+ // in the outer scope anyway, because if a binding exists in an outer scope,
+ // the associated variable has to be marked as potentially being accessed
+ // from inside of an inner with scope (the property may not be in the 'with'
+ // object).
+ if (var != NULL && proxy->is_assigned()) var->set_maybe_assigned();
+ *binding_kind = DYNAMIC_LOOKUP;
+ return NULL;
+ } else if (calls_sloppy_eval() && !is_script_scope() &&
+ name_can_be_shadowed) {
+ // A variable binding may have been found in an outer scope, but the current
+ // scope makes a sloppy 'eval' call, so the found variable may not be
+ // the correct one (the 'eval' may introduce a binding with the same name).
+ // In that case, change the lookup result to reflect this situation.
+ if (*binding_kind == BOUND) {
+ *binding_kind = BOUND_EVAL_SHADOWED;
+ } else if (*binding_kind == UNBOUND) {
+ *binding_kind = UNBOUND_EVAL_SHADOWED;
+ }
+ }
+ return var;
+}
+
+
+bool Scope::ResolveVariable(ParseInfo* info, VariableProxy* proxy,
+ AstNodeFactory* factory) {
+ DCHECK(info->script_scope()->is_script_scope());
+
+ // If the proxy is already resolved there's nothing to do
+ // (functions and consts may be resolved by the parser).
+ if (proxy->is_resolved()) return true;
+
+ // Otherwise, try to resolve the variable.
+ BindingKind binding_kind;
+ Variable* var = LookupRecursive(proxy, &binding_kind, factory);
+
+#ifdef DEBUG
+ if (info->script_is_native()) {
+ // To avoid polluting the global object in native scripts
+ // - Variables must not be allocated to the global scope.
+ CHECK_NOT_NULL(outer_scope());
+ // - Variables must be bound locally or unallocated.
+ if (BOUND != binding_kind) {
+ // The following variable name may be minified. If so, disable
+ // minification in js2c.py for better output.
+ Handle<String> name = proxy->raw_name()->string();
+ V8_Fatal(__FILE__, __LINE__, "Unbound variable: '%s' in native script.",
+ name->ToCString().get());
+ }
+ VariableLocation location = var->location();
+ CHECK(location == VariableLocation::LOCAL ||
+ location == VariableLocation::CONTEXT ||
+ location == VariableLocation::PARAMETER ||
+ location == VariableLocation::UNALLOCATED);
+ }
+#endif
+
+ switch (binding_kind) {
+ case BOUND:
+ // We found a variable binding.
+ if (is_strong(language_mode())) {
+ if (!CheckStrongModeDeclaration(proxy, var)) return false;
+ }
+ break;
+
+ case BOUND_EVAL_SHADOWED:
+ // We either found a variable binding that might be shadowed by eval or
+ // gave up on it (e.g. by encountering a local with the same in the outer
+ // scope which was not promoted to a context, this can happen if we use
+ // debugger to evaluate arbitrary expressions at a break point).
+ if (var->IsGlobalObjectProperty()) {
+ var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL);
+ } else if (var->is_dynamic()) {
+ var = NonLocal(proxy->raw_name(), DYNAMIC);
+ } else {
+ Variable* invalidated = var;
+ var = NonLocal(proxy->raw_name(), DYNAMIC_LOCAL);
+ var->set_local_if_not_shadowed(invalidated);
+ }
+ break;
+
+ case UNBOUND:
+ // No binding has been found. Declare a variable on the global object.
+ var = info->script_scope()->DeclareDynamicGlobal(proxy->raw_name());
+ break;
+
+ case UNBOUND_EVAL_SHADOWED:
+ // No binding has been found. But some scope makes a sloppy 'eval' call.
+ var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL);
+ break;
+
+ case DYNAMIC_LOOKUP:
+ // The variable could not be resolved statically.
+ var = NonLocal(proxy->raw_name(), DYNAMIC);
+ break;
+ }
+
+ DCHECK(var != NULL);
+ if (proxy->is_assigned()) var->set_maybe_assigned();
+
+ if (is_strong(language_mode())) {
+ // Record that the variable is referred to from strong mode. Also, record
+ // the position.
+ var->RecordStrongModeReference(proxy->position(), proxy->end_position());
+ }
+
+ proxy->BindTo(var);
+
+ return true;
+}
+
+
+bool Scope::CheckStrongModeDeclaration(VariableProxy* proxy, Variable* var) {
+ // Check for declaration-after use (for variables) in strong mode. Note that
+ // we can only do this in the case where we have seen the declaration. And we
+ // always allow referencing functions (for now).
+
+ // This might happen during lazy compilation; we don't keep track of
+ // initializer positions for variables stored in ScopeInfo, so we cannot check
+ // bindings against them. TODO(marja, rossberg): remove this hack.
+ if (var->initializer_position() == RelocInfo::kNoPosition) return true;
+
+ // Allow referencing the class name from methods of that class, even though
+ // the initializer position for class names is only after the body.
+ Scope* scope = this;
+ while (scope) {
+ if (scope->ClassVariableForMethod() == var) return true;
+ scope = scope->outer_scope();
+ }
+
+ // Allow references from methods to classes declared later, if we detect no
+ // problematic dependency cycles. Note that we can be inside multiple methods
+ // at the same time, and it's enough if we find one where the reference is
+ // allowed.
+ if (var->is_class() &&
+ var->AsClassVariable()->declaration_group_start() >= 0) {
+ for (scope = this; scope && scope != var->scope();
+ scope = scope->outer_scope()) {
+ ClassVariable* class_var = scope->ClassVariableForMethod();
+ // A method is referring to some other class, possibly declared
+ // later. Referring to a class declared earlier is always OK and covered
+ // by the code outside this if. Here we only need to allow special cases
+ // for referring to a class which is declared later.
+
+ // Referring to a class C declared later is OK under the following
+ // circumstances:
+
+ // 1. The class declarations are in a consecutive group with no other
+ // declarations or statements in between, and
+
+ // 2. There is no dependency cycle where the first edge is an
+ // initialization time dependency (computed property name or extends
+ // clause) from C to something that depends on this class directly or
+ // transitively.
+ if (class_var &&
+ class_var->declaration_group_start() ==
+ var->AsClassVariable()->declaration_group_start()) {
+ return true;
+ }
+
+ // TODO(marja,rossberg): implement the dependency cycle detection. Here we
+ // undershoot the target and allow referring to any class in the same
+ // consectuive declaration group.
+
+ // The cycle detection can work roughly like this: 1) detect init-time
+ // references here (they are free variables which are inside the class
+ // scope but not inside a method scope - no parser changes needed to
+ // detect them) 2) if we encounter an init-time reference here, allow it,
+ // but record it for a later dependency cycle check 3) also record
+ // non-init-time references here 4) after scope analysis is done, analyse
+ // the dependency cycles: an illegal cycle is one starting with an
+ // init-time reference and leading back to the starting point with either
+ // non-init-time and init-time references.
+ }
+ }
+
+ // If both the use and the declaration are inside an eval scope (possibly
+ // indirectly), or one of them is, we need to check whether they are inside
+ // the same eval scope or different ones.
+
+ // TODO(marja,rossberg): Detect errors across different evals (depends on the
+ // future of eval in strong mode).
+ const Scope* eval_for_use = NearestOuterEvalScope();
+ const Scope* eval_for_declaration = var->scope()->NearestOuterEvalScope();
+
+ if (proxy->position() != RelocInfo::kNoPosition &&
+ proxy->position() < var->initializer_position() && !var->is_function() &&
+ eval_for_use == eval_for_declaration) {
+ DCHECK(proxy->end_position() != RelocInfo::kNoPosition);
+ ReportMessage(proxy->position(), proxy->end_position(),
+ MessageTemplate::kStrongUseBeforeDeclaration,
+ proxy->raw_name());
+ return false;
+ }
+ return true;
+}
+
+
+ClassVariable* Scope::ClassVariableForMethod() const {
+ // TODO(marja, rossberg): This fails to find a class variable in the following
+ // cases:
+ // let A = class { ... }
+ // It needs to be investigated whether this causes any practical problems.
+ if (!is_function_scope()) return nullptr;
+ if (IsInObjectLiteral(function_kind_)) return nullptr;
+ if (!IsConciseMethod(function_kind_) && !IsClassConstructor(function_kind_) &&
+ !IsAccessorFunction(function_kind_)) {
+ return nullptr;
+ }
+ DCHECK_NOT_NULL(outer_scope_);
+ // The class scope contains at most one variable, the class name.
+ DCHECK(outer_scope_->variables_.occupancy() <= 1);
+ if (outer_scope_->variables_.occupancy() == 0) return nullptr;
+ VariableMap::Entry* p = outer_scope_->variables_.Start();
+ Variable* var = reinterpret_cast<Variable*>(p->value);
+ if (!var->is_class()) return nullptr;
+ return var->AsClassVariable();
+}
+
+
+bool Scope::ResolveVariablesRecursively(ParseInfo* info,
+ AstNodeFactory* factory) {
+ DCHECK(info->script_scope()->is_script_scope());
+
+ // Resolve unresolved variables for this scope.
+ for (int i = 0; i < unresolved_.length(); i++) {
+ if (!ResolveVariable(info, unresolved_[i], factory)) return false;
+ }
+
+ // Resolve unresolved variables for inner scopes.
+ for (int i = 0; i < inner_scopes_.length(); i++) {
+ if (!inner_scopes_[i]->ResolveVariablesRecursively(info, factory))
+ return false;
+ }
+
+ return true;
+}
+
+
+void Scope::PropagateScopeInfo(bool outer_scope_calls_sloppy_eval ) {
+ if (outer_scope_calls_sloppy_eval) {
+ outer_scope_calls_sloppy_eval_ = true;
+ }
+
+ bool calls_sloppy_eval =
+ this->calls_sloppy_eval() || outer_scope_calls_sloppy_eval_;
+ for (int i = 0; i < inner_scopes_.length(); i++) {
+ Scope* inner = inner_scopes_[i];
+ inner->PropagateScopeInfo(calls_sloppy_eval);
+ if (inner->scope_calls_eval_ || inner->inner_scope_calls_eval_) {
+ inner_scope_calls_eval_ = true;
+ }
+ if (inner->force_eager_compilation_) {
+ force_eager_compilation_ = true;
+ }
+ if (asm_module_ && inner->scope_type() == FUNCTION_SCOPE) {
+ inner->asm_function_ = true;
+ }
+ }
+}
+
+
+bool Scope::MustAllocate(Variable* var) {
+ // 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
+ // visible name.
+ if ((var->is_this() || !var->raw_name()->IsEmpty()) &&
+ (var->has_forced_context_allocation() || scope_calls_eval_ ||
+ inner_scope_calls_eval_ || scope_contains_with_ || is_catch_scope() ||
+ is_block_scope() || is_module_scope() || is_script_scope())) {
+ var->set_is_used();
+ if (scope_calls_eval_ || inner_scope_calls_eval_) var->set_maybe_assigned();
+ }
+ // Global variables do not need to be allocated.
+ return !var->IsGlobalObjectProperty() && var->is_used();
+}
+
+
+bool Scope::MustAllocateInContext(Variable* var) {
+ // If var is accessed from an inner scope, or if there is a possibility
+ // that it might be accessed from the current or an inner scope (through
+ // an eval() call or a runtime with lookup), it must be allocated in the
+ // context.
+ //
+ // Exceptions: If the scope as a whole has forced context allocation, all
+ // variables will have context allocation, even temporaries. Otherwise
+ // temporary variables are always stack-allocated. Catch-bound variables are
+ // always context-allocated.
+ if (has_forced_context_allocation()) return true;
+ if (var->mode() == TEMPORARY) return false;
+ if (is_catch_scope() || is_module_scope()) return true;
+ if (is_script_scope() && IsLexicalVariableMode(var->mode())) return true;
+ return var->has_forced_context_allocation() ||
+ scope_calls_eval_ ||
+ inner_scope_calls_eval_ ||
+ scope_contains_with_;
+}
+
+
+bool Scope::HasArgumentsParameter(Isolate* isolate) {
+ for (int i = 0; i < params_.length(); i++) {
+ if (params_[i]->name().is_identical_to(
+ isolate->factory()->arguments_string())) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void Scope::AllocateStackSlot(Variable* var) {
+ if (is_block_scope()) {
+ outer_scope()->DeclarationScope()->AllocateStackSlot(var);
+ } else {
+ var->AllocateTo(VariableLocation::LOCAL, num_stack_slots_++);
+ }
+}
+
+
+void Scope::AllocateHeapSlot(Variable* var) {
+ var->AllocateTo(VariableLocation::CONTEXT, num_heap_slots_++);
+}
+
+
+void Scope::AllocateParameterLocals(Isolate* isolate) {
+ DCHECK(is_function_scope());
+ Variable* arguments = LookupLocal(ast_value_factory_->arguments_string());
+ // Functions have 'arguments' declared implicitly in all non arrow functions.
+ DCHECK(arguments != nullptr || is_arrow_scope());
+
+ bool uses_sloppy_arguments = false;
+
+ if (arguments != nullptr && MustAllocate(arguments) &&
+ !HasArgumentsParameter(isolate)) {
+ // 'arguments' is used. Unless there is also a parameter called
+ // 'arguments', we must be conservative and allocate all parameters to
+ // the context assuming they will be captured by the arguments object.
+ // If we have a parameter named 'arguments', a (new) value is always
+ // assigned to it via the function invocation. Then 'arguments' denotes
+ // that specific parameter value and cannot be used to access the
+ // parameters, which is why we don't need to allocate an arguments
+ // object in that case.
+
+ // We are using 'arguments'. Tell the code generator that is needs to
+ // allocate the arguments object by setting 'arguments_'.
+ arguments_ = arguments;
+
+ // In strict mode 'arguments' does not alias formal parameters.
+ // Therefore in strict mode we allocate parameters as if 'arguments'
+ // were not used.
+ // If the parameter list is not simple, arguments isn't sloppy either.
+ uses_sloppy_arguments =
+ is_sloppy(language_mode()) && has_simple_parameters();
+ }
+
+ if (rest_parameter_ && !MustAllocate(rest_parameter_)) {
+ rest_parameter_ = NULL;
+ }
+
+ // The same parameter may occur multiple times in the parameters_ list.
+ // If it does, and if it is not copied into the context object, it must
+ // receive the highest parameter index for that parameter; thus iteration
+ // order is relevant!
+ for (int i = params_.length() - 1; i >= 0; --i) {
+ Variable* var = params_[i];
+ if (var == rest_parameter_) continue;
+
+ DCHECK(var->scope() == this);
+ if (uses_sloppy_arguments || has_forced_context_allocation()) {
+ // Force context allocation of the parameter.
+ var->ForceContextAllocation();
+ }
+ AllocateParameter(var, i);
+ }
+}
+
+
+void Scope::AllocateParameter(Variable* var, int index) {
+ if (MustAllocate(var)) {
+ if (MustAllocateInContext(var)) {
+ DCHECK(var->IsUnallocated() || var->IsContextSlot());
+ if (var->IsUnallocated()) {
+ AllocateHeapSlot(var);
+ }
+ } else {
+ DCHECK(var->IsUnallocated() || var->IsParameter());
+ if (var->IsUnallocated()) {
+ var->AllocateTo(VariableLocation::PARAMETER, index);
+ }
+ }
+ } else {
+ DCHECK(!var->IsGlobalSlot());
+ }
+}
+
+
+void Scope::AllocateReceiver() {
+ DCHECK_NOT_NULL(receiver());
+ DCHECK_EQ(receiver()->scope(), this);
+
+ if (has_forced_context_allocation()) {
+ // Force context allocation of the receiver.
+ receiver()->ForceContextAllocation();
+ }
+ AllocateParameter(receiver(), -1);
+}
+
+
+void Scope::AllocateNonParameterLocal(Isolate* isolate, Variable* var) {
+ DCHECK(var->scope() == this);
+ DCHECK(!var->IsVariable(isolate->factory()->dot_result_string()) ||
+ !var->IsStackLocal());
+ if (var->IsUnallocated() && MustAllocate(var)) {
+ if (MustAllocateInContext(var)) {
+ AllocateHeapSlot(var);
+ } else {
+ AllocateStackSlot(var);
+ }
+ }
+}
+
+
+void Scope::AllocateDeclaredGlobal(Isolate* isolate, Variable* var) {
+ DCHECK(var->scope() == this);
+ DCHECK(!var->IsVariable(isolate->factory()->dot_result_string()) ||
+ !var->IsStackLocal());
+ if (var->IsUnallocated()) {
+ if (var->IsStaticGlobalObjectProperty()) {
+ DCHECK_EQ(-1, var->index());
+ DCHECK(var->name()->IsString());
+ var->AllocateTo(VariableLocation::GLOBAL, num_heap_slots_++);
+ num_global_slots_++;
+ } else {
+ // There must be only DYNAMIC_GLOBAL in the script scope.
+ DCHECK(!is_script_scope() || DYNAMIC_GLOBAL == var->mode());
+ }
+ }
+}
+
+
+void Scope::AllocateNonParameterLocalsAndDeclaredGlobals(Isolate* isolate) {
+ // All variables that have no rewrite yet are non-parameter locals.
+ for (int i = 0; i < temps_.length(); i++) {
+ AllocateNonParameterLocal(isolate, temps_[i]);
+ }
+
+ ZoneList<VarAndOrder> vars(variables_.occupancy(), zone());
+ for (VariableMap::Entry* p = variables_.Start();
+ p != NULL;
+ p = variables_.Next(p)) {
+ Variable* var = reinterpret_cast<Variable*>(p->value);
+ vars.Add(VarAndOrder(var, p->order), zone());
+ }
+ vars.Sort(VarAndOrder::Compare);
+ int var_count = vars.length();
+ for (int i = 0; i < var_count; i++) {
+ AllocateNonParameterLocal(isolate, vars[i].var());
+ }
+
+ if (FLAG_global_var_shortcuts) {
+ for (int i = 0; i < var_count; i++) {
+ AllocateDeclaredGlobal(isolate, vars[i].var());
+ }
+ }
+
+ // For now, function_ must be allocated at the very end. If it gets
+ // allocated in the context, it must be the last slot in the context,
+ // because of the current ScopeInfo implementation (see
+ // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor).
+ if (function_ != nullptr) {
+ AllocateNonParameterLocal(isolate, function_->proxy()->var());
+ }
+
+ if (rest_parameter_ != nullptr) {
+ AllocateNonParameterLocal(isolate, rest_parameter_);
+ }
+
+ Variable* new_target_var =
+ LookupLocal(ast_value_factory_->new_target_string());
+ if (new_target_var != nullptr && MustAllocate(new_target_var)) {
+ new_target_ = new_target_var;
+ }
+
+ Variable* this_function_var =
+ LookupLocal(ast_value_factory_->this_function_string());
+ if (this_function_var != nullptr && MustAllocate(this_function_var)) {
+ this_function_ = this_function_var;
+ }
+}
+
+
+void Scope::AllocateVariablesRecursively(Isolate* isolate) {
+ if (!already_resolved()) {
+ num_stack_slots_ = 0;
+ }
+ // Allocate variables for inner scopes.
+ for (int i = 0; i < inner_scopes_.length(); i++) {
+ inner_scopes_[i]->AllocateVariablesRecursively(isolate);
+ }
+
+ // If scope is already resolved, we still need to allocate
+ // variables in inner scopes which might not had been resolved yet.
+ if (already_resolved()) return;
+ // The number of slots required for variables.
+ num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
+
+ // Allocate variables for this scope.
+ // Parameters must be allocated first, if any.
+ if (is_function_scope()) AllocateParameterLocals(isolate);
+ if (has_this_declaration()) AllocateReceiver();
+ AllocateNonParameterLocalsAndDeclaredGlobals(isolate);
+
+ // 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.
+ bool must_have_context =
+ is_with_scope() || is_module_scope() ||
+ (is_function_scope() && calls_sloppy_eval()) ||
+ (is_block_scope() && is_declaration_scope() && calls_sloppy_eval());
+
+ // If we didn't allocate any locals in the local context, then we only
+ // need the minimal number of slots if we must have a context.
+ if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS && !must_have_context) {
+ num_heap_slots_ = 0;
+ }
+
+ // Allocation done.
+ DCHECK(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS);
+}
+
+
+int Scope::StackLocalCount() const {
+ return num_stack_slots() -
+ (function_ != NULL && function_->proxy()->var()->IsStackLocal() ? 1 : 0);
+}
+
+
+int Scope::ContextLocalCount() const {
+ if (num_heap_slots() == 0) return 0;
+ bool is_function_var_in_context =
+ function_ != NULL && function_->proxy()->var()->IsContextSlot();
+ return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - num_global_slots() -
+ (is_function_var_in_context ? 1 : 0);
+}
+
+
+int Scope::ContextGlobalCount() const { return num_global_slots(); }
+
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/ast/scopes.h b/deps/v8/src/ast/scopes.h
new file mode 100644
index 0000000000..6c261f63c3
--- /dev/null
+++ b/deps/v8/src/ast/scopes.h
@@ -0,0 +1,849 @@
+// Copyright 2012 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_SCOPES_H_
+#define V8_AST_SCOPES_H_
+
+#include "src/ast/ast.h"
+#include "src/hashmap.h"
+#include "src/pending-compilation-error-handler.h"
+#include "src/zone.h"
+
+namespace v8 {
+namespace internal {
+
+class ParseInfo;
+
+// A hash map to support fast variable declaration and lookup.
+class VariableMap: public ZoneHashMap {
+ public:
+ explicit VariableMap(Zone* zone);
+
+ virtual ~VariableMap();
+
+ Variable* Declare(Scope* scope, const AstRawString* name, VariableMode mode,
+ Variable::Kind kind, InitializationFlag initialization_flag,
+ MaybeAssignedFlag maybe_assigned_flag = kNotAssigned,
+ int declaration_group_start = -1);
+
+ Variable* Lookup(const AstRawString* name);
+
+ Zone* zone() const { return zone_; }
+
+ private:
+ Zone* zone_;
+};
+
+
+// The dynamic scope part holds hash maps for the variables that will
+// be looked up dynamically from within eval and with scopes. The objects
+// are allocated on-demand from Scope::NonLocal to avoid wasting memory
+// and setup time for scopes that don't need them.
+class DynamicScopePart : public ZoneObject {
+ public:
+ explicit DynamicScopePart(Zone* zone) {
+ for (int i = 0; i < 3; i++)
+ maps_[i] = new(zone->New(sizeof(VariableMap))) VariableMap(zone);
+ }
+
+ VariableMap* GetMap(VariableMode mode) {
+ int index = mode - DYNAMIC;
+ DCHECK(index >= 0 && index < 3);
+ return maps_[index];
+ }
+
+ private:
+ VariableMap *maps_[3];
+};
+
+
+// Sloppy block-scoped function declarations to var-bind
+class SloppyBlockFunctionMap : public ZoneHashMap {
+ public:
+ explicit SloppyBlockFunctionMap(Zone* zone);
+
+ virtual ~SloppyBlockFunctionMap();
+
+ void Declare(const AstRawString* name,
+ SloppyBlockFunctionStatement* statement);
+
+ typedef ZoneVector<SloppyBlockFunctionStatement*> Vector;
+
+ private:
+ Zone* zone_;
+};
+
+
+// Global invariants after AST construction: Each reference (i.e. identifier)
+// to a JavaScript variable (including global properties) is represented by a
+// VariableProxy node. Immediately after AST construction and before variable
+// allocation, most VariableProxy nodes are "unresolved", i.e. not bound to a
+// corresponding variable (though some are bound during parse time). Variable
+// allocation binds each unresolved VariableProxy to one Variable and assigns
+// a location. Note that many VariableProxy nodes may refer to the same Java-
+// Script variable.
+
+class Scope: public ZoneObject {
+ public:
+ // ---------------------------------------------------------------------------
+ // Construction
+
+ Scope(Zone* zone, Scope* outer_scope, ScopeType scope_type,
+ AstValueFactory* value_factory,
+ FunctionKind function_kind = kNormalFunction);
+
+ // Compute top scope and allocate variables. For lazy compilation the top
+ // scope only contains the single lazily compiled function, so this
+ // doesn't re-allocate variables repeatedly.
+ static bool Analyze(ParseInfo* info);
+
+ static Scope* DeserializeScopeChain(Isolate* isolate, Zone* zone,
+ Context* context, Scope* script_scope);
+
+ // The scope name is only used for printing/debugging.
+ void SetScopeName(const AstRawString* scope_name) {
+ scope_name_ = scope_name;
+ }
+
+ void Initialize();
+
+ // Checks if the block scope is redundant, i.e. it does not contain any
+ // block scoped declarations. In that case it is removed from the scope
+ // tree and its children are reparented.
+ Scope* FinalizeBlockScope();
+
+ // Inserts outer_scope into this scope's scope chain (and removes this
+ // from the current outer_scope_'s inner_scopes_).
+ // Assumes outer_scope_ is non-null.
+ void ReplaceOuterScope(Scope* outer_scope);
+
+ // Propagates any eagerly-gathered scope usage flags (such as calls_eval())
+ // to the passed-in scope.
+ void PropagateUsageFlagsToScope(Scope* other);
+
+ Zone* zone() const { return zone_; }
+
+ // ---------------------------------------------------------------------------
+ // Declarations
+
+ // Lookup a variable in this scope. Returns the variable or NULL if not found.
+ Variable* LookupLocal(const AstRawString* name);
+
+ // This lookup corresponds to a lookup in the "intermediate" scope sitting
+ // between this scope and the outer scope. (ECMA-262, 3rd., requires that
+ // the name of named function literal is kept in an intermediate scope
+ // in between this scope and the next outer scope.)
+ Variable* LookupFunctionVar(const AstRawString* name,
+ AstNodeFactory* factory);
+
+ // Lookup a variable in this scope or outer scopes.
+ // Returns the variable or NULL if not found.
+ Variable* Lookup(const AstRawString* name);
+
+ // Declare the function variable for a function literal. This variable
+ // is in an intermediate scope between this function scope and the the
+ // outer scope. Only possible for function scopes; at most one variable.
+ void DeclareFunctionVar(VariableDeclaration* declaration) {
+ DCHECK(is_function_scope());
+ // Handle implicit declaration of the function name in named function
+ // expressions before other declarations.
+ decls_.InsertAt(0, declaration, zone());
+ function_ = declaration;
+ }
+
+ // Declare a parameter in this scope. When there are duplicated
+ // parameters the rightmost one 'wins'. However, the implementation
+ // expects all parameters to be declared and from left to right.
+ Variable* DeclareParameter(
+ const AstRawString* name, VariableMode mode,
+ bool is_optional, bool is_rest, bool* is_duplicate);
+
+ // 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, Variable::Kind kind,
+ MaybeAssignedFlag maybe_assigned_flag = kNotAssigned,
+ int declaration_group_start = -1);
+
+ // 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
+ // with statements or eval calls.
+ Variable* DeclareDynamicGlobal(const AstRawString* name);
+
+ // Create a new unresolved variable.
+ VariableProxy* NewUnresolved(AstNodeFactory* factory,
+ const AstRawString* name,
+ Variable::Kind kind = Variable::NORMAL,
+ int start_position = RelocInfo::kNoPosition,
+ int end_position = RelocInfo::kNoPosition) {
+ // Note that we must not share the unresolved variables with
+ // the same name because they may be removed selectively via
+ // RemoveUnresolved().
+ DCHECK(!already_resolved());
+ VariableProxy* proxy =
+ factory->NewVariableProxy(name, kind, start_position, end_position);
+ unresolved_.Add(proxy, zone_);
+ return proxy;
+ }
+
+ void AddUnresolved(VariableProxy* proxy) {
+ DCHECK(!already_resolved());
+ DCHECK(!proxy->is_resolved());
+ unresolved_.Add(proxy, zone_);
+ }
+
+ // Remove a unresolved variable. During parsing, an unresolved variable
+ // may have been added optimistically, but then only the variable name
+ // was used (typically for labels). If the variable was not declared, the
+ // addition introduced a new unresolved variable which may end up being
+ // 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);
+
+ // 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.
+ // In particular, the only way to get hold of the temporary is by keeping the
+ // Variable* around. The name should not clash with a legitimate variable
+ // names.
+ Variable* NewTemporary(const AstRawString* name);
+
+ // Remove a temporary variable. This is for adjusting the scope of
+ // temporaries used when desugaring parameter initializers.
+ bool RemoveTemporary(Variable* var);
+
+ // Adds a temporary variable in this scope's TemporaryScope. This is for
+ // adjusting the scope of temporaries used when desugaring parameter
+ // initializers.
+ void AddTemporary(Variable* var) { temps_.Add(var, zone()); }
+
+ // Adds the specific declaration node to the list of declarations in
+ // this scope. The declarations are processed as part of entering
+ // the scope; see codegen.cc:ProcessDeclarations.
+ void AddDeclaration(Declaration* declaration);
+
+ // ---------------------------------------------------------------------------
+ // Illegal redeclaration support.
+
+ // Set an expression node that will be executed when the scope is
+ // entered. We only keep track of one illegal redeclaration node per
+ // scope - the first one - so if you try to set it multiple times
+ // the additional requests will be silently ignored.
+ void SetIllegalRedeclaration(Expression* expression);
+
+ // Retrieve the illegal redeclaration expression. Do not call if the
+ // scope doesn't have an illegal redeclaration node.
+ Expression* GetIllegalRedeclaration();
+
+ // Check if the scope has (at least) one illegal redeclaration.
+ bool HasIllegalRedeclaration() const { return illegal_redecl_ != NULL; }
+
+ // For harmony block scoping mode: Check if the scope has conflicting var
+ // declarations, i.e. a var declaration that has been hoisted from a nested
+ // scope over a let binding of the same name.
+ Declaration* CheckConflictingVarDeclarations();
+
+ // ---------------------------------------------------------------------------
+ // Scope-specific info.
+
+ // Inform the scope that the corresponding code contains a with statement.
+ void RecordWithStatement() { scope_contains_with_ = true; }
+
+ // Inform the scope that the corresponding code contains an eval call.
+ void RecordEvalCall() { scope_calls_eval_ = true; }
+
+ // Inform the scope that the corresponding code uses "arguments".
+ void RecordArgumentsUsage() { scope_uses_arguments_ = true; }
+
+ // Inform the scope that the corresponding code uses "super".
+ void RecordSuperPropertyUsage() { scope_uses_super_property_ = true; }
+
+ // Set the language mode flag (unless disabled by a global flag).
+ void SetLanguageMode(LanguageMode language_mode) {
+ language_mode_ = language_mode;
+ }
+
+ // Set the ASM module flag.
+ void SetAsmModule() { asm_module_ = true; }
+
+ // Inform the scope that the scope may execute declarations nonlinearly.
+ // Currently, the only nonlinear scope is a switch statement. The name is
+ // more general in case something else comes up with similar control flow,
+ // for example the ability to break out of something which does not have
+ // its own lexical scope.
+ // The bit does not need to be stored on the ScopeInfo because none of
+ // the three compilers will perform hole check elimination on a variable
+ // located in VariableLocation::CONTEXT. So, direct eval and closures
+ // will not expose holes.
+ void SetNonlinear() { scope_nonlinear_ = true; }
+
+ // Position in the source where this scope begins and ends.
+ //
+ // * For the scope of a with statement
+ // with (obj) stmt
+ // start position: start position of first token of 'stmt'
+ // end position: end position of last token of 'stmt'
+ // * For the scope of a block
+ // { stmts }
+ // start position: start position of '{'
+ // end position: end position of '}'
+ // * For the scope of a function literal or decalaration
+ // function fun(a,b) { stmts }
+ // start position: start position of '('
+ // end position: end position of '}'
+ // * For the scope of a catch block
+ // try { stms } catch(e) { stmts }
+ // start position: start position of '('
+ // end position: end position of ')'
+ // * For the scope of a for-statement
+ // for (let x ...) stmt
+ // start position: start position of '('
+ // end position: end position of last token of 'stmt'
+ // * For the scope of a switch statement
+ // switch (tag) { cases }
+ // start position: start position of '{'
+ // end position: end position of '}'
+ int start_position() const { return start_position_; }
+ void set_start_position(int statement_pos) {
+ start_position_ = statement_pos;
+ }
+ int end_position() const { return end_position_; }
+ void set_end_position(int statement_pos) {
+ end_position_ = statement_pos;
+ }
+
+ // In some cases we want to force context allocation for a whole scope.
+ void ForceContextAllocation() {
+ DCHECK(!already_resolved());
+ force_context_allocation_ = true;
+ }
+ bool has_forced_context_allocation() const {
+ return force_context_allocation_;
+ }
+
+ // ---------------------------------------------------------------------------
+ // Predicates.
+
+ // Specific scope types.
+ bool is_eval_scope() const { return scope_type_ == EVAL_SCOPE; }
+ bool is_function_scope() const { return scope_type_ == FUNCTION_SCOPE; }
+ bool is_module_scope() const { return scope_type_ == MODULE_SCOPE; }
+ bool is_script_scope() const { return scope_type_ == SCRIPT_SCOPE; }
+ bool is_catch_scope() const { return scope_type_ == CATCH_SCOPE; }
+ bool is_block_scope() const { return scope_type_ == BLOCK_SCOPE; }
+ bool is_with_scope() const { return scope_type_ == WITH_SCOPE; }
+ bool is_arrow_scope() const {
+ return is_function_scope() && IsArrowFunction(function_kind_);
+ }
+ bool is_declaration_scope() const { return is_declaration_scope_; }
+
+ void set_is_declaration_scope() { is_declaration_scope_ = true; }
+
+ // Information about which scopes calls eval.
+ bool calls_eval() const { return scope_calls_eval_; }
+ bool calls_sloppy_eval() const {
+ return scope_calls_eval_ && is_sloppy(language_mode_);
+ }
+ bool outer_scope_calls_sloppy_eval() const {
+ return outer_scope_calls_sloppy_eval_;
+ }
+ bool asm_module() const { return asm_module_; }
+ bool asm_function() const { return asm_function_; }
+
+ // Is this scope inside a with statement.
+ bool inside_with() const { return scope_inside_with_; }
+
+ // Does this scope access "arguments".
+ bool uses_arguments() const { return scope_uses_arguments_; }
+ // Does this scope access "super" property (super.foo).
+ bool uses_super_property() const { return scope_uses_super_property_; }
+ // Does this scope have the potential to execute declarations non-linearly?
+ bool is_nonlinear() const { return scope_nonlinear_; }
+
+ // Whether this needs to be represented by a runtime context.
+ bool NeedsContext() const {
+ // Catch and module scopes always have heap slots.
+ DCHECK(!is_catch_scope() || num_heap_slots() > 0);
+ DCHECK(!is_module_scope() || num_heap_slots() > 0);
+ return is_with_scope() || num_heap_slots() > 0;
+ }
+
+ bool NeedsHomeObject() const {
+ return scope_uses_super_property_ ||
+ ((scope_calls_eval_ || inner_scope_calls_eval_) &&
+ (IsConciseMethod(function_kind()) ||
+ IsAccessorFunction(function_kind()) ||
+ IsClassConstructor(function_kind())));
+ }
+
+ const Scope* NearestOuterEvalScope() const {
+ if (is_eval_scope()) return this;
+ if (outer_scope() == nullptr) return nullptr;
+ return outer_scope()->NearestOuterEvalScope();
+ }
+
+ // ---------------------------------------------------------------------------
+ // Accessors.
+
+ // The type of this scope.
+ ScopeType scope_type() const { return scope_type_; }
+
+ FunctionKind function_kind() const { return function_kind_; }
+
+ // The language mode of this scope.
+ LanguageMode language_mode() const { return language_mode_; }
+
+ // The variable corresponding to the 'this' value.
+ Variable* receiver() {
+ DCHECK(has_this_declaration());
+ DCHECK_NOT_NULL(receiver_);
+ return receiver_;
+ }
+
+ // TODO(wingo): Add a GLOBAL_SCOPE scope type which will lexically allocate
+ // "this" (and no other variable) on the native context. Script scopes then
+ // will not have a "this" declaration.
+ bool has_this_declaration() const {
+ return (is_function_scope() && !is_arrow_scope()) || is_module_scope();
+ }
+
+ // The variable corresponding to the 'new.target' value.
+ Variable* new_target_var() { return new_target_; }
+
+ // The variable holding the function literal for named function
+ // literals, or NULL. Only valid for function scopes.
+ VariableDeclaration* function() const {
+ DCHECK(is_function_scope());
+ return function_;
+ }
+
+ // Parameters. The left-most parameter has index 0.
+ // Only valid for function scopes.
+ Variable* parameter(int index) const {
+ DCHECK(is_function_scope());
+ return params_[index];
+ }
+
+ // Returns the default function arity excluding default or rest parameters.
+ int default_function_length() const { return arity_; }
+
+ int num_parameters() const { return params_.length(); }
+
+ // A function can have at most one rest parameter. Returns Variable* or NULL.
+ Variable* rest_parameter(int* index) const {
+ *index = rest_index_;
+ if (rest_index_ < 0) return NULL;
+ return rest_parameter_;
+ }
+
+ bool has_rest_parameter() const { return rest_index_ >= 0; }
+
+ bool has_simple_parameters() const {
+ return has_simple_parameters_;
+ }
+
+ // TODO(caitp): manage this state in a better way. PreParser must be able to
+ // communicate that the scope is non-simple, without allocating any parameters
+ // as the Parser does. This is necessary to ensure that TC39's proposed early
+ // error can be reported consistently regardless of whether lazily parsed or
+ // not.
+ void SetHasNonSimpleParameters() {
+ DCHECK(is_function_scope());
+ has_simple_parameters_ = false;
+ }
+
+ // Retrieve `IsSimpleParameterList` of current or outer function.
+ bool HasSimpleParameters() {
+ Scope* scope = ClosureScope();
+ return !scope->is_function_scope() || scope->has_simple_parameters();
+ }
+
+ // The local variable 'arguments' if we need to allocate it; NULL otherwise.
+ Variable* arguments() const {
+ DCHECK(!is_arrow_scope() || arguments_ == nullptr);
+ return arguments_;
+ }
+
+ Variable* this_function_var() const {
+ // This is only used in derived constructors atm.
+ DCHECK(this_function_ == nullptr ||
+ (is_function_scope() && (IsClassConstructor(function_kind()) ||
+ IsConciseMethod(function_kind()) ||
+ IsAccessorFunction(function_kind()))));
+ return this_function_;
+ }
+
+ // Declarations list.
+ ZoneList<Declaration*>* declarations() { return &decls_; }
+
+ // Inner scope list.
+ ZoneList<Scope*>* inner_scopes() { return &inner_scopes_; }
+
+ // The scope immediately surrounding this scope, or NULL.
+ Scope* outer_scope() const { return outer_scope_; }
+
+ // The ModuleDescriptor for this scope; only for module scopes.
+ ModuleDescriptor* module() const { return module_descriptor_; }
+
+
+ void set_class_declaration_group_start(int position) {
+ class_declaration_group_start_ = position;
+ }
+
+ int class_declaration_group_start() const {
+ return class_declaration_group_start_;
+ }
+
+ // ---------------------------------------------------------------------------
+ // Variable allocation.
+
+ // Collect stack and context allocated local variables in this scope. Note
+ // that the function variable - if present - is not collected and should be
+ // handled separately.
+ void CollectStackAndContextLocals(
+ ZoneList<Variable*>* stack_locals, ZoneList<Variable*>* context_locals,
+ ZoneList<Variable*>* context_globals,
+ ZoneList<Variable*>* strong_mode_free_variables = nullptr);
+
+ // Current number of var or const locals.
+ int num_var_or_const() { return num_var_or_const_; }
+
+ // Result of variable allocation.
+ int num_stack_slots() const { return num_stack_slots_; }
+ int num_heap_slots() const { return num_heap_slots_; }
+ int num_global_slots() const { return num_global_slots_; }
+
+ int StackLocalCount() const;
+ int ContextLocalCount() const;
+ int ContextGlobalCount() const;
+
+ // Make sure this scope and all outer scopes are eagerly compiled.
+ void ForceEagerCompilation() { force_eager_compilation_ = true; }
+
+ // Determine if we can parse a function literal in this scope lazily.
+ bool AllowsLazyParsing() const;
+
+ // Determine if we can use lazy compilation for this scope.
+ bool AllowsLazyCompilation() const;
+
+ // Determine if we can use lazy compilation for this scope without a context.
+ bool AllowsLazyCompilationWithoutContext() const;
+
+ // True if the outer context of this scope is always the native context.
+ bool HasTrivialOuterContext() const;
+
+ // The number of contexts between this and scope; zero if this == scope.
+ int ContextChainLength(Scope* scope);
+
+ // The maximum number of nested contexts required for this scope and any inner
+ // scopes.
+ int MaxNestedContextChainLength();
+
+ // Find the first function, script, eval or (declaration) block scope. This is
+ // the scope where var declarations will be hoisted to in the implementation.
+ Scope* DeclarationScope();
+
+ // Find the first non-block declaration scope. This should be either a script,
+ // function, or eval scope. Same as DeclarationScope(), but skips
+ // declaration "block" scopes. Used for differentiating associated
+ // function objects (i.e., the scope for which a function prologue allocates
+ // a context) or declaring temporaries.
+ Scope* ClosureScope();
+
+ // Find the first (non-arrow) function or script scope. This is where
+ // 'this' is bound, and what determines the function kind.
+ Scope* ReceiverScope();
+
+ Handle<ScopeInfo> GetScopeInfo(Isolate* isolate);
+
+ // Get the chain of nested scopes within this scope for the source statement
+ // position. The scopes will be added to the list from the outermost scope to
+ // the innermost scope. Only nested block, catch or with scopes are tracked
+ // and will be returned, but no inner function scopes.
+ void GetNestedScopeChain(Isolate* isolate, List<Handle<ScopeInfo> >* chain,
+ int statement_position);
+
+ void CollectNonLocals(HashMap* non_locals);
+
+ // ---------------------------------------------------------------------------
+ // Strict mode support.
+ bool IsDeclared(const AstRawString* name) {
+ // During formal parameter list parsing the scope only contains
+ // two variables inserted at initialization: "this" and "arguments".
+ // "this" is an invalid parameter name and "arguments" is invalid parameter
+ // name in strict mode. Therefore looking up with the map which includes
+ // "this" and "arguments" in addition to all formal parameters is safe.
+ return variables_.Lookup(name) != NULL;
+ }
+
+ bool IsDeclaredParameter(const AstRawString* name) {
+ // If IsSimpleParameterList is false, duplicate parameters are not allowed,
+ // however `arguments` may be allowed if function is not strict code. Thus,
+ // the assumptions explained above do not hold.
+ return params_.Contains(variables_.Lookup(name));
+ }
+
+ SloppyBlockFunctionMap* sloppy_block_function_map() {
+ return &sloppy_block_function_map_;
+ }
+
+ // Error handling.
+ void ReportMessage(int start_position, int end_position,
+ MessageTemplate::Template message,
+ const AstRawString* arg);
+
+ // ---------------------------------------------------------------------------
+ // Debugging.
+
+#ifdef DEBUG
+ void Print(int n = 0); // n = indentation; n < 0 => don't print recursively
+#endif
+
+ // ---------------------------------------------------------------------------
+ // Implementation.
+ private:
+ // Scope tree.
+ Scope* outer_scope_; // the immediately enclosing outer scope, or NULL
+ ZoneList<Scope*> inner_scopes_; // the immediately enclosed inner scopes
+
+ // The scope type.
+ ScopeType scope_type_;
+ // If the scope is a function scope, this is the function kind.
+ FunctionKind function_kind_;
+
+ // Debugging support.
+ const AstRawString* scope_name_;
+
+ // The variables declared in this scope:
+ //
+ // All user-declared variables (incl. parameters). For script scopes
+ // variables may be implicitly 'declared' by being used (possibly in
+ // an inner scope) with no intervening with statements or eval calls.
+ VariableMap variables_;
+ // Compiler-allocated (user-invisible) temporaries.
+ ZoneList<Variable*> temps_;
+ // Parameter list in source order.
+ ZoneList<Variable*> params_;
+ // Variables that must be looked up dynamically.
+ DynamicScopePart* dynamics_;
+ // Unresolved variables referred to from this scope.
+ ZoneList<VariableProxy*> unresolved_;
+ // Declarations.
+ ZoneList<Declaration*> decls_;
+ // Convenience variable.
+ Variable* receiver_;
+ // Function variable, if any; function scopes only.
+ VariableDeclaration* function_;
+ // new.target variable, function scopes only.
+ Variable* new_target_;
+ // Convenience variable; function scopes only.
+ Variable* arguments_;
+ // Convenience variable; Subclass constructor only
+ Variable* this_function_;
+ // Module descriptor; module scopes only.
+ ModuleDescriptor* module_descriptor_;
+
+ // Map of function names to lists of functions defined in sloppy blocks
+ SloppyBlockFunctionMap sloppy_block_function_map_;
+
+ // Illegal redeclaration.
+ Expression* illegal_redecl_;
+
+ // Scope-specific information computed during parsing.
+ //
+ // This scope is inside a 'with' of some outer scope.
+ bool scope_inside_with_;
+ // This scope contains a 'with' statement.
+ bool scope_contains_with_;
+ // This scope or a nested catch scope or with scope contain an 'eval' call. At
+ // the 'eval' call site this scope is the declaration scope.
+ bool scope_calls_eval_;
+ // This scope uses "arguments".
+ bool scope_uses_arguments_;
+ // This scope uses "super" property ('super.foo').
+ bool scope_uses_super_property_;
+ // This scope contains an "use asm" annotation.
+ bool asm_module_;
+ // This scope's outer context is an asm module.
+ bool asm_function_;
+ // This scope's declarations might not be executed in order (e.g., switch).
+ bool scope_nonlinear_;
+ // The language mode of this scope.
+ LanguageMode language_mode_;
+ // Source positions.
+ int start_position_;
+ int end_position_;
+
+ // Computed via PropagateScopeInfo.
+ bool outer_scope_calls_sloppy_eval_;
+ bool inner_scope_calls_eval_;
+ bool force_eager_compilation_;
+ bool force_context_allocation_;
+
+ // True if it doesn't need scope resolution (e.g., if the scope was
+ // constructed based on a serialized scope info or a catch context).
+ bool already_resolved_;
+
+ // True if it holds 'var' declarations.
+ bool is_declaration_scope_;
+
+ // Computed as variables are declared.
+ int num_var_or_const_;
+
+ // Computed via AllocateVariables; function, block and catch scopes only.
+ int num_stack_slots_;
+ int num_heap_slots_;
+ int num_global_slots_;
+
+ // Info about the parameter list of a function.
+ int arity_;
+ bool has_simple_parameters_;
+ Variable* rest_parameter_;
+ int rest_index_;
+
+ // Serialized scope info support.
+ Handle<ScopeInfo> scope_info_;
+ bool already_resolved() { return already_resolved_; }
+
+ // Create a non-local variable with a given name.
+ // These variables are looked up dynamically at runtime.
+ Variable* NonLocal(const AstRawString* name, VariableMode mode);
+
+ // Variable resolution.
+ // Possible results of a recursive variable lookup telling if and how a
+ // variable is bound. These are returned in the output parameter *binding_kind
+ // of the LookupRecursive function.
+ enum BindingKind {
+ // The variable reference could be statically resolved to a variable binding
+ // which is returned. There is no 'with' statement between the reference and
+ // the binding and no scope between the reference scope (inclusive) and
+ // binding scope (exclusive) makes a sloppy 'eval' call.
+ BOUND,
+
+ // The variable reference could be statically resolved to a variable binding
+ // which is returned. There is no 'with' statement between the reference and
+ // the binding, but some scope between the reference scope (inclusive) and
+ // binding scope (exclusive) makes a sloppy 'eval' call, that might
+ // possibly introduce variable bindings shadowing the found one. Thus the
+ // found variable binding is just a guess.
+ BOUND_EVAL_SHADOWED,
+
+ // The variable reference could not be statically resolved to any binding
+ // and thus should be considered referencing a global variable. NULL is
+ // returned. The variable reference is not inside any 'with' statement and
+ // no scope between the reference scope (inclusive) and script scope
+ // (exclusive) makes a sloppy 'eval' call.
+ UNBOUND,
+
+ // The variable reference could not be statically resolved to any binding
+ // NULL is returned. The variable reference is not inside any 'with'
+ // statement, but some scope between the reference scope (inclusive) and
+ // script scope (exclusive) makes a sloppy 'eval' call, that might
+ // possibly introduce a variable binding. Thus the reference should be
+ // considered referencing a global variable unless it is shadowed by an
+ // 'eval' introduced binding.
+ UNBOUND_EVAL_SHADOWED,
+
+ // The variable could not be statically resolved and needs to be looked up
+ // dynamically. NULL is returned. There are two possible reasons:
+ // * A 'with' statement has been encountered and there is no variable
+ // binding for the name between the variable reference and the 'with'.
+ // The variable potentially references a property of the 'with' object.
+ // * The code is being executed as part of a call to 'eval' and the calling
+ // context chain contains either a variable binding for the name or it
+ // contains a 'with' context.
+ DYNAMIC_LOOKUP
+ };
+
+ // Lookup a variable reference given by name recursively starting with this
+ // scope. If the code is executed because of a call to 'eval', the context
+ // parameter should be set to the calling context of 'eval'.
+ Variable* LookupRecursive(VariableProxy* proxy, BindingKind* binding_kind,
+ AstNodeFactory* factory);
+ MUST_USE_RESULT
+ bool ResolveVariable(ParseInfo* info, VariableProxy* proxy,
+ AstNodeFactory* factory);
+ MUST_USE_RESULT
+ bool ResolveVariablesRecursively(ParseInfo* info, AstNodeFactory* factory);
+
+ bool CheckStrongModeDeclaration(VariableProxy* proxy, Variable* var);
+
+ // If this scope is a method scope of a class, return the corresponding
+ // class variable, otherwise nullptr.
+ ClassVariable* ClassVariableForMethod() const;
+
+ // Scope analysis.
+ void PropagateScopeInfo(bool outer_scope_calls_sloppy_eval);
+ bool HasTrivialContext() const;
+
+ // Predicates.
+ bool MustAllocate(Variable* var);
+ bool MustAllocateInContext(Variable* var);
+ bool HasArgumentsParameter(Isolate* isolate);
+
+ // Variable allocation.
+ void AllocateStackSlot(Variable* var);
+ void AllocateHeapSlot(Variable* var);
+ void AllocateParameterLocals(Isolate* isolate);
+ void AllocateNonParameterLocal(Isolate* isolate, Variable* var);
+ void AllocateDeclaredGlobal(Isolate* isolate, Variable* var);
+ void AllocateNonParameterLocalsAndDeclaredGlobals(Isolate* isolate);
+ void AllocateVariablesRecursively(Isolate* isolate);
+ void AllocateParameter(Variable* var, int index);
+ void AllocateReceiver();
+
+ // Resolve and fill in the allocation information for all variables
+ // in this scopes. Must be called *after* all scopes have been
+ // processed (parsed) to ensure that unresolved variables can be
+ // resolved properly.
+ //
+ // In the case of code compiled and run using 'eval', the context
+ // parameter is the context in which eval was called. In all other
+ // cases the context parameter is an empty handle.
+ MUST_USE_RESULT
+ bool AllocateVariables(ParseInfo* info, AstNodeFactory* factory);
+
+ // Construct a scope based on the scope info.
+ Scope(Zone* zone, Scope* inner_scope, ScopeType type,
+ Handle<ScopeInfo> scope_info, AstValueFactory* value_factory);
+
+ // Construct a catch scope with a binding for the name.
+ Scope(Zone* zone, Scope* inner_scope, const AstRawString* catch_variable_name,
+ AstValueFactory* value_factory);
+
+ void AddInnerScope(Scope* inner_scope) {
+ if (inner_scope != NULL) {
+ inner_scopes_.Add(inner_scope, zone_);
+ inner_scope->outer_scope_ = this;
+ }
+ }
+
+ void RemoveInnerScope(Scope* inner_scope) {
+ DCHECK_NOT_NULL(inner_scope);
+ for (int i = 0; i < inner_scopes_.length(); i++) {
+ if (inner_scopes_[i] == inner_scope) {
+ inner_scopes_.Remove(i);
+ break;
+ }
+ }
+ }
+
+ void SetDefaults(ScopeType type, Scope* outer_scope,
+ Handle<ScopeInfo> scope_info,
+ FunctionKind function_kind = kNormalFunction);
+
+ AstValueFactory* ast_value_factory_;
+ Zone* zone_;
+
+ PendingCompilationErrorHandler pending_error_handler_;
+
+ // For tracking which classes are declared consecutively. Needed for strong
+ // mode.
+ int class_declaration_group_start_;
+};
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_AST_SCOPES_H_
diff --git a/deps/v8/src/ast/variables.cc b/deps/v8/src/ast/variables.cc
new file mode 100644
index 0000000000..8e00782386
--- /dev/null
+++ b/deps/v8/src/ast/variables.cc
@@ -0,0 +1,82 @@
+// 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 "src/ast/variables.h"
+
+#include "src/ast/ast.h"
+#include "src/ast/scopes.h"
+
+namespace v8 {
+namespace internal {
+
+// ----------------------------------------------------------------------------
+// Implementation Variable.
+
+const char* Variable::Mode2String(VariableMode mode) {
+ switch (mode) {
+ case VAR: return "VAR";
+ case CONST_LEGACY: return "CONST_LEGACY";
+ case LET: return "LET";
+ case CONST: return "CONST";
+ case IMPORT: return "IMPORT";
+ case DYNAMIC: return "DYNAMIC";
+ case DYNAMIC_GLOBAL: return "DYNAMIC_GLOBAL";
+ case DYNAMIC_LOCAL: return "DYNAMIC_LOCAL";
+ case TEMPORARY: return "TEMPORARY";
+ }
+ UNREACHABLE();
+ return NULL;
+}
+
+
+Variable::Variable(Scope* scope, const AstRawString* name, VariableMode mode,
+ Kind kind, InitializationFlag initialization_flag,
+ MaybeAssignedFlag maybe_assigned_flag)
+ : scope_(scope),
+ name_(name),
+ mode_(mode),
+ kind_(kind),
+ location_(VariableLocation::UNALLOCATED),
+ index_(-1),
+ initializer_position_(RelocInfo::kNoPosition),
+ has_strong_mode_reference_(false),
+ strong_mode_reference_start_position_(RelocInfo::kNoPosition),
+ strong_mode_reference_end_position_(RelocInfo::kNoPosition),
+ local_if_not_shadowed_(NULL),
+ is_from_eval_(false),
+ force_context_allocation_(false),
+ is_used_(false),
+ initialization_flag_(initialization_flag),
+ maybe_assigned_(maybe_assigned_flag) {
+ // Var declared variables never need initialization.
+ DCHECK(!(mode == VAR && initialization_flag == kNeedsInitialization));
+}
+
+
+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() && !is_this();
+}
+
+
+bool Variable::IsStaticGlobalObjectProperty() const {
+ // Temporaries are never global, they must always be allocated in the
+ // activation frame.
+ return (IsDeclaredVariableMode(mode_) && !IsLexicalVariableMode(mode_)) &&
+ scope_ != NULL && scope_->is_script_scope() && !is_this();
+}
+
+
+int Variable::CompareIndex(Variable* const* v, Variable* const* w) {
+ int x = (*v)->index();
+ int y = (*w)->index();
+ // Consider sorting them according to type as well?
+ return x - y;
+}
+
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/ast/variables.h b/deps/v8/src/ast/variables.h
new file mode 100644
index 0000000000..ca5d1cdd40
--- /dev/null
+++ b/deps/v8/src/ast/variables.h
@@ -0,0 +1,218 @@
+// 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.
+
+#ifndef V8_AST_VARIABLES_H_
+#define V8_AST_VARIABLES_H_
+
+#include "src/ast/ast-value-factory.h"
+#include "src/zone.h"
+
+namespace v8 {
+namespace internal {
+
+// The AST refers to variables via VariableProxies - placeholders for the actual
+// variables. Variables themselves are never directly referred to from the AST,
+// they are maintained by scopes, and referred to from VariableProxies and Slots
+// after binding and variable allocation.
+
+class ClassVariable;
+
+class Variable: public ZoneObject {
+ public:
+ enum Kind { NORMAL, FUNCTION, CLASS, THIS, ARGUMENTS };
+
+ Variable(Scope* scope, const AstRawString* name, VariableMode mode, Kind kind,
+ InitializationFlag initialization_flag,
+ MaybeAssignedFlag maybe_assigned_flag = kNotAssigned);
+
+ virtual ~Variable() {}
+
+ // Printing support
+ static const char* Mode2String(VariableMode mode);
+
+ // The source code for an eval() call may refer to a variable that is
+ // in an outer scope about which we don't know anything (it may not
+ // be the script scope). scope() is NULL in that case. Currently the
+ // scope is only used to follow the context chain length.
+ Scope* scope() const { return scope_; }
+
+ // This is for adjusting the scope of temporaries used when desugaring
+ // parameter initializers.
+ void set_scope(Scope* scope) { scope_ = scope; }
+
+ Handle<String> name() const { return name_->string(); }
+ const AstRawString* raw_name() const { return name_; }
+ VariableMode mode() const { return mode_; }
+ bool has_forced_context_allocation() const {
+ return force_context_allocation_;
+ }
+ void ForceContextAllocation() {
+ force_context_allocation_ = true;
+ }
+ bool is_used() { return is_used_; }
+ void set_is_used() { is_used_ = true; }
+ MaybeAssignedFlag maybe_assigned() const { return maybe_assigned_; }
+ void set_maybe_assigned() { maybe_assigned_ = kMaybeAssigned; }
+
+ int initializer_position() { return initializer_position_; }
+ void set_initializer_position(int pos) { initializer_position_ = pos; }
+
+ bool IsVariable(Handle<String> n) const {
+ return !is_this() && name().is_identical_to(n);
+ }
+
+ bool IsUnallocated() const {
+ return location_ == VariableLocation::UNALLOCATED;
+ }
+ bool IsParameter() const { return location_ == VariableLocation::PARAMETER; }
+ bool IsStackLocal() const { return location_ == VariableLocation::LOCAL; }
+ bool IsStackAllocated() const { return IsParameter() || IsStackLocal(); }
+ bool IsContextSlot() const { return location_ == VariableLocation::CONTEXT; }
+ bool IsGlobalSlot() const { return location_ == VariableLocation::GLOBAL; }
+ bool IsUnallocatedOrGlobalSlot() const {
+ return IsUnallocated() || IsGlobalSlot();
+ }
+ bool IsLookupSlot() const { return location_ == VariableLocation::LOOKUP; }
+ bool IsGlobalObjectProperty() const;
+ bool IsStaticGlobalObjectProperty() const;
+
+ bool is_dynamic() const { return IsDynamicVariableMode(mode_); }
+ bool is_const_mode() const { return IsImmutableVariableMode(mode_); }
+ bool binding_needs_init() const {
+ return initialization_flag_ == kNeedsInitialization;
+ }
+
+ bool is_function() const { return kind_ == FUNCTION; }
+ bool is_class() const { return kind_ == CLASS; }
+ bool is_this() const { return kind_ == THIS; }
+ bool is_arguments() const { return kind_ == ARGUMENTS; }
+
+ // For script scopes, the "this" binding is provided by a ScriptContext added
+ // to the global's ScriptContextTable. This binding might not statically
+ // resolve to a Variable::THIS binding, instead being DYNAMIC_LOCAL. However
+ // any variable named "this" does indeed refer to a Variable::THIS binding;
+ // the grammar ensures this to be the case. So wherever a "this" binding
+ // might be provided by the global, use HasThisName instead of is_this().
+ bool HasThisName(Isolate* isolate) const {
+ return is_this() || *name() == *isolate->factory()->this_string();
+ }
+
+ ClassVariable* AsClassVariable() {
+ DCHECK(is_class());
+ return reinterpret_cast<ClassVariable*>(this);
+ }
+
+ // True if the variable is named eval and not known to be shadowed.
+ bool is_possibly_eval(Isolate* isolate) const {
+ return IsVariable(isolate->factory()->eval_string());
+ }
+
+ Variable* local_if_not_shadowed() const {
+ DCHECK(mode_ == DYNAMIC_LOCAL && local_if_not_shadowed_ != NULL);
+ return local_if_not_shadowed_;
+ }
+
+ void set_local_if_not_shadowed(Variable* local) {
+ local_if_not_shadowed_ = local;
+ }
+
+ VariableLocation location() const { return location_; }
+ int index() const { return index_; }
+ InitializationFlag initialization_flag() const {
+ return initialization_flag_;
+ }
+
+ void AllocateTo(VariableLocation location, int index) {
+ location_ = location;
+ index_ = index;
+ }
+
+ void SetFromEval() { is_from_eval_ = true; }
+
+ static int CompareIndex(Variable* const* v, Variable* const* w);
+
+ void RecordStrongModeReference(int start_position, int end_position) {
+ // Record the earliest reference to the variable. Used in error messages for
+ // strong mode references to undeclared variables.
+ if (has_strong_mode_reference_ &&
+ strong_mode_reference_start_position_ < start_position)
+ return;
+ has_strong_mode_reference_ = true;
+ strong_mode_reference_start_position_ = start_position;
+ strong_mode_reference_end_position_ = end_position;
+ }
+
+ bool has_strong_mode_reference() const { return has_strong_mode_reference_; }
+ int strong_mode_reference_start_position() const {
+ return strong_mode_reference_start_position_;
+ }
+ int strong_mode_reference_end_position() const {
+ return strong_mode_reference_end_position_;
+ }
+ PropertyAttributes DeclarationPropertyAttributes() const {
+ int property_attributes = NONE;
+ if (IsImmutableVariableMode(mode_)) {
+ property_attributes |= READ_ONLY;
+ }
+ if (is_from_eval_) {
+ property_attributes |= EVAL_DECLARED;
+ }
+ return static_cast<PropertyAttributes>(property_attributes);
+ }
+
+ private:
+ Scope* scope_;
+ const AstRawString* name_;
+ VariableMode mode_;
+ Kind kind_;
+ VariableLocation location_;
+ int index_;
+ int initializer_position_;
+ // Tracks whether the variable is bound to a VariableProxy which is in strong
+ // mode, and if yes, the source location of the reference.
+ bool has_strong_mode_reference_;
+ int strong_mode_reference_start_position_;
+ int strong_mode_reference_end_position_;
+
+ // If this field is set, this variable references the stored locally bound
+ // variable, but it might be shadowed by variable bindings introduced by
+ // sloppy 'eval' calls between the reference scope (inclusive) and the
+ // binding scope (exclusive).
+ Variable* local_if_not_shadowed_;
+
+ // True if this variable is introduced by a sloppy eval
+ bool is_from_eval_;
+
+ // Usage info.
+ bool force_context_allocation_; // set by variable resolver
+ bool is_used_;
+ InitializationFlag initialization_flag_;
+ MaybeAssignedFlag maybe_assigned_;
+};
+
+class ClassVariable : public Variable {
+ public:
+ ClassVariable(Scope* scope, const AstRawString* name, VariableMode mode,
+ InitializationFlag initialization_flag,
+ MaybeAssignedFlag maybe_assigned_flag = kNotAssigned,
+ int declaration_group_start = -1)
+ : Variable(scope, name, mode, Variable::CLASS, initialization_flag,
+ maybe_assigned_flag),
+ declaration_group_start_(declaration_group_start) {}
+
+ int declaration_group_start() const { return declaration_group_start_; }
+ void set_declaration_group_start(int declaration_group_start) {
+ declaration_group_start_ = declaration_group_start;
+ }
+
+ private:
+ // For classes we keep track of consecutive groups of delcarations. They are
+ // needed for strong mode scoping checks. TODO(marja, rossberg): Implement
+ // checks for functions too.
+ int declaration_group_start_;
+};
+} // namespace internal
+} // namespace v8
+
+#endif // V8_AST_VARIABLES_H_