Index: src/compiler/ast-graph-builder.cc |
diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc |
index 4a22abf286237f5fa33bfa322481471d9ef30bbb..c4b9b31bcee45b8a10661526adc3d96be7bd322a 100644 |
--- a/src/compiler/ast-graph-builder.cc |
+++ b/src/compiler/ast-graph-builder.cc |
@@ -320,6 +320,14 @@ void AstGraphBuilder::VisitForValueOrNull(Expression* expr) { |
} |
+void AstGraphBuilder::VisitForValueOrTheHole(Expression* expr) { |
+ if (expr == NULL) { |
+ return environment()->Push(jsgraph()->TheHoleConstant()); |
+ } |
+ VisitForValue(expr); |
+} |
+ |
+ |
void AstGraphBuilder::VisitForValues(ZoneList<Expression*>* exprs) { |
for (int i = 0; i < exprs->length(); ++i) { |
VisitForValue(exprs->at(i)); |
@@ -469,12 +477,9 @@ void AstGraphBuilder::VisitBlock(Block* stmt) { |
// Visit statements in the same scope, no declarations. |
VisitStatements(stmt->statements()); |
} else { |
- const Operator* op = javascript()->CreateBlockContext(); |
- Node* scope_info = jsgraph()->Constant(stmt->scope()->GetScopeInfo()); |
- Node* context = NewNode(op, scope_info, GetFunctionClosure()); |
- ContextScope scope(this, stmt->scope(), context); |
- |
// Visit declarations and statements in a block scope. |
+ Node* context = BuildLocalBlockContext(stmt->scope()); |
+ ContextScope scope(this, stmt->scope(), context); |
VisitDeclarations(stmt->scope()->declarations()); |
VisitStatements(stmt->statements()); |
} |
@@ -842,7 +847,105 @@ void AstGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { |
void AstGraphBuilder::VisitClassLiteral(ClassLiteral* expr) { |
- UNREACHABLE(); |
+ if (expr->scope() == NULL) { |
+ // Visit class literal in the same scope, no declarations. |
+ VisitClassLiteralContents(expr); |
+ } else { |
+ // Visit declarations and class literal in a block scope. |
+ Node* context = BuildLocalBlockContext(expr->scope()); |
+ ContextScope scope(this, expr->scope(), context); |
+ VisitDeclarations(expr->scope()->declarations()); |
+ VisitClassLiteralContents(expr); |
+ } |
+} |
+ |
+ |
+void AstGraphBuilder::VisitClassLiteralContents(ClassLiteral* expr) { |
+ Node* class_name = expr->raw_name() ? jsgraph()->Constant(expr->name()) |
+ : jsgraph()->UndefinedConstant(); |
+ |
+ // The class name is expected on the operand stack. |
+ environment()->Push(class_name); |
+ VisitForValueOrTheHole(expr->extends()); |
+ VisitForValue(expr->constructor()); |
+ |
+ // Create node to instantiate a new class. |
+ Node* constructor = environment()->Pop(); |
+ Node* extends = environment()->Pop(); |
+ Node* name = environment()->Pop(); |
+ Node* script = jsgraph()->Constant(info()->script()); |
+ Node* start = jsgraph()->Constant(expr->start_position()); |
+ Node* end = jsgraph()->Constant(expr->end_position()); |
+ const Operator* opc = javascript()->CallRuntime(Runtime::kDefineClass, 6); |
+ Node* literal = NewNode(opc, name, extends, constructor, script, start, end); |
+ |
+ // The prototype is ensured to exist by Runtime_DefineClass. No access check |
+ // is needed here since the constructor is created by the class literal. |
+ Node* proto = |
+ BuildLoadObjectField(literal, JSFunction::kPrototypeOrInitialMapOffset); |
+ |
+ // The class literal and the prototype are both expected on the operand stack |
+ // during evaluation of the method values. |
+ environment()->Push(literal); |
+ environment()->Push(proto); |
+ |
+ // Create nodes to store method values into the literal. |
+ for (int i = 0; i < expr->properties()->length(); i++) { |
+ ObjectLiteral::Property* property = expr->properties()->at(i); |
+ environment()->Push(property->is_static() ? literal : proto); |
+ |
+ VisitForValue(property->key()); |
+ VisitForValue(property->value()); |
+ Node* value = environment()->Pop(); |
+ Node* key = environment()->Pop(); |
+ Node* receiver = environment()->Pop(); |
+ switch (property->kind()) { |
+ case ObjectLiteral::Property::CONSTANT: |
+ case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
+ UNREACHABLE(); |
+ case ObjectLiteral::Property::COMPUTED: |
+ case ObjectLiteral::Property::PROTOTYPE: { |
+ const Operator* op = |
+ javascript()->CallRuntime(Runtime::kDefineClassMethod, 3); |
+ NewNode(op, receiver, key, value); |
+ break; |
+ } |
+ case ObjectLiteral::Property::GETTER: { |
+ const Operator* op = javascript()->CallRuntime( |
+ Runtime::kDefineGetterPropertyUnchecked, 3); |
+ NewNode(op, receiver, key, value); |
+ break; |
+ } |
+ case ObjectLiteral::Property::SETTER: { |
+ const Operator* op = javascript()->CallRuntime( |
+ Runtime::kDefineSetterPropertyUnchecked, 3); |
+ NewNode(op, receiver, key, value); |
+ break; |
+ } |
+ } |
+ |
+ // TODO(mstarzinger): This is temporary to make "super" work and replicates |
+ // the existing FullCodeGenerator::NeedsHomeObject predicate. |
+ if (FunctionLiteral::NeedsHomeObject(property->value())) { |
+ Unique<Name> name = |
+ MakeUnique(isolate()->factory()->home_object_symbol()); |
+ NewNode(javascript()->StoreNamed(strict_mode(), name), value, receiver); |
+ } |
+ } |
+ |
+ // Transform both the class literal and the prototype to fast properties. |
+ const Operator* op = javascript()->CallRuntime(Runtime::kToFastProperties, 1); |
+ NewNode(op, environment()->Pop()); // prototype |
+ NewNode(op, environment()->Pop()); // literal |
+ |
+ // Assign to class variable. |
+ if (expr->scope() != NULL) { |
+ DCHECK_NOT_NULL(expr->class_variable_proxy()); |
+ Variable* var = expr->class_variable_proxy()->var(); |
+ BuildVariableAssignment(var, literal, Token::INIT_CONST, BailoutId::None()); |
+ } |
+ |
+ ast_context()->ProduceValue(literal); |
} |
@@ -1829,6 +1932,18 @@ Node* AstGraphBuilder::BuildLocalFunctionContext(Node* context, Node* closure) { |
} |
+Node* AstGraphBuilder::BuildLocalBlockContext(Scope* scope) { |
+ Node* closure = GetFunctionClosure(); |
+ |
+ // Allocate a new local context. |
+ const Operator* op = javascript()->CreateBlockContext(); |
+ Node* scope_info = jsgraph()->Constant(scope->GetScopeInfo()); |
+ Node* local_context = NewNode(op, scope_info, closure); |
+ |
+ return local_context; |
+} |
+ |
+ |
Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) { |
if (arguments == NULL) return NULL; |