Chromium Code Reviews| Index: src/compiler/ast-graph-builder.cc |
| diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc |
| index c42d26c0629b631f38ba4d7b75bc47a964cc9975..71398d24c9780941eb179e864acb1195593f12e1 100644 |
| --- a/src/compiler/ast-graph-builder.cc |
| +++ b/src/compiler/ast-graph-builder.cc |
| @@ -133,6 +133,24 @@ bool AstGraphBuilder::CreateGraph() { |
| } |
| +// Helper class to create a new context for block scopes. This also implicitly |
| +// pushes a ContextScope and visits declarations for the newly created context. |
| +class AstGraphBuilder::BlockContextScope FINAL : public ContextScope { |
| + public: |
| + BlockContextScope(AstGraphBuilder* owner, Scope* scope) |
| + : ContextScope(owner, scope, CreateBlockContext(owner, scope)) { |
| + owner->VisitDeclarations(scope->declarations()); |
| + } |
| + |
| + private: |
| + static Node* CreateBlockContext(AstGraphBuilder* owner, Scope* scope) { |
| + const Operator* op = owner->javascript()->CreateBlockContext(); |
| + Node* scope_info = owner->jsgraph()->Constant(scope->GetScopeInfo()); |
| + return owner->NewNode(op, scope_info, owner->GetFunctionClosure()); |
| + } |
| +}; |
| + |
| + |
| // Left-hand side can only be a property, a global or a variable slot. |
| enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| @@ -320,6 +338,14 @@ void AstGraphBuilder::VisitForValueOrNull(Expression* expr) { |
| } |
| +void AstGraphBuilder::VisitForValueOrTheHole(Expression* expr) { |
| + if (expr == NULL) { |
| + return environment()->Push(jsgraph()->TheHoleConstant()); |
|
arv (Not doing code reviews)
2015/01/14 15:49:10
I could also have the parser use TheHole instead o
Michael Starzinger
2015/01/14 16:02:19
Hmm, I don't have an opinion either way. On the on
rossberg
2015/01/15 15:31:19
Using the hole here would be confusing levels. We
Michael Starzinger
2015/01/16 09:43:54
Acknowledged.
|
| + } |
| + VisitForValue(expr); |
| +} |
| + |
| + |
| void AstGraphBuilder::VisitForValues(ZoneList<Expression*>* exprs) { |
| for (int i = 0; i < exprs->length(); ++i) { |
| VisitForValue(exprs->at(i)); |
| @@ -469,13 +495,8 @@ 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. |
| - VisitDeclarations(stmt->scope()->declarations()); |
| + BlockContextScope scope(this, stmt->scope()); |
| VisitStatements(stmt->statements()); |
| } |
| if (stmt->labels() != NULL) block.EndBlock(); |
| @@ -834,7 +855,102 @@ 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. |
| + BlockContextScope scope(this, expr->scope()); |
| + 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: |
| + 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::kDefineClassGetter, 3); |
| + NewNode(op, receiver, key, value); |
| + break; |
| + } |
| + case ObjectLiteral::Property::SETTER: { |
| + const Operator* op = |
| + javascript()->CallRuntime(Runtime::kDefineClassSetter, 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); |
| } |