Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(118)

Unified Diff: src/compiler/ast-graph-builder.cc

Issue 798873006: First simple implementation of class literals in TurboFan. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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);
}
« no previous file with comments | « src/compiler/ast-graph-builder.h ('k') | src/compiler/pipeline.cc » ('j') | src/types.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698