Index: src/interpreter/bytecode-generator.cc |
diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc |
index a8ba7e88e8605d141d7dce4222998fd543fccffd..d31ebeeca5fb8207398167cf8569205671eda230 100644 |
--- a/src/interpreter/bytecode-generator.cc |
+++ b/src/interpreter/bytecode-generator.cc |
@@ -1228,9 +1228,148 @@ void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { |
void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) { |
- UNIMPLEMENTED(); |
+ if (expr->scope()->ContextLocalCount() > 0) { |
+ VisitNewLocalBlockContext(expr->scope()); |
+ ContextScope scope(this, expr->scope()); |
+ VisitDeclarations(expr->scope()->declarations()); |
+ VisitClassLiteralContents(expr); |
+ } else { |
+ VisitDeclarations(expr->scope()->declarations()); |
+ VisitClassLiteralContents(expr); |
+ } |
} |
+void BytecodeGenerator::VisitClassLiteralContents(ClassLiteral* expr) { |
+ VisitClassLiteralForRuntimeDefinition(expr); |
+ // The prototype is ensured to exist by Runtime_DefineClass in |
+ // VisitClassForRuntimeDefinition. No access check is needed here |
+ // since the constructor is created by the class literal. |
+ register_allocator()->PrepareForConsecutiveAllocations(2); |
+ Register literal = register_allocator()->NextConsecutiveRegister(); |
+ Register prototype = register_allocator()->NextConsecutiveRegister(); |
+ builder() |
+ ->StoreAccumulatorInRegister(literal) |
+ .LoadPrototypeOrInitialMap() |
+ .StoreAccumulatorInRegister(prototype); |
+ |
+ VisitClassLiteralProperties(expr, literal, prototype); |
+ builder()->CallRuntime(Runtime::kFinalizeClassDefinition, literal, 2); |
+ // Assign to class variable. |
+ if (expr->class_variable_proxy() != nullptr) { |
+ Variable* var = expr->class_variable_proxy()->var(); |
+ FeedbackVectorSlot slot = expr->NeedsProxySlot() |
+ ? expr->ProxySlot() |
+ : FeedbackVectorSlot::Invalid(); |
+ VisitVariableAssignment(var, slot); |
+ } |
+ execution_result()->SetResultInAccumulator(); |
+} |
+ |
+void BytecodeGenerator::VisitClassLiteralForRuntimeDefinition( |
+ ClassLiteral* expr) { |
+ AccumulatorResultScope result_scope(this); |
+ register_allocator()->PrepareForConsecutiveAllocations(4); |
+ Register extends = register_allocator()->NextConsecutiveRegister(); |
+ Register constructor = register_allocator()->NextConsecutiveRegister(); |
+ Register start_position = register_allocator()->NextConsecutiveRegister(); |
+ Register end_position = register_allocator()->NextConsecutiveRegister(); |
+ |
+ VisitForAccumulatorValueOrTheHole(expr->extends()); |
+ builder()->StoreAccumulatorInRegister(extends); |
+ |
+ VisitForAccumulatorValue(expr->constructor()); |
+ builder() |
+ ->StoreAccumulatorInRegister(constructor) |
+ .LoadLiteral(Smi::FromInt(expr->start_position())) |
+ .StoreAccumulatorInRegister(start_position) |
+ .LoadLiteral(Smi::FromInt(expr->end_position())) |
+ .StoreAccumulatorInRegister(end_position) |
+ .CallRuntime(Runtime::kDefineClass, extends, 4); |
+ result_scope.SetResultInAccumulator(); |
+} |
+ |
+void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr, |
+ Register literal, |
+ Register prototype) { |
+ RegisterAllocationScope register_scope(this); |
+ register_allocator()->PrepareForConsecutiveAllocations(4); |
+ Register receiver = register_allocator()->NextConsecutiveRegister(); |
+ Register key = register_allocator()->NextConsecutiveRegister(); |
+ Register value = register_allocator()->NextConsecutiveRegister(); |
+ Register attr = register_allocator()->NextConsecutiveRegister(); |
+ |
+ bool attr_assigned = false; |
+ Register old_receiver = Register::invalid_value(); |
+ |
+ // 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); |
+ |
+ // Set-up receiver. |
+ Register new_receiver = property->is_static() ? literal : prototype; |
+ if (new_receiver != old_receiver) { |
+ builder()->MoveRegister(new_receiver, receiver); |
+ old_receiver = new_receiver; |
+ } |
+ |
+ VisitForAccumulatorValue(property->key()); |
+ builder()->CastAccumulatorToName().StoreAccumulatorInRegister(key); |
+ // The static prototype property is read only. We handle the non computed |
+ // property name case in the parser. Since this is the only case where we |
+ // need to check for an own read only property we special case this so we do |
+ // not need to do this for every property. |
+ if (property->is_static() && property->is_computed_name()) { |
+ VisitClassLiteralStaticPrototypeWithComputedName(key); |
+ } |
+ VisitForAccumulatorValue(property->value()); |
+ builder()->StoreAccumulatorInRegister(value); |
+ |
+ VisitSetHomeObject(value, receiver, property); |
+ |
+ if ((property->kind() == ObjectLiteral::Property::GETTER || |
+ property->kind() == ObjectLiteral::Property::SETTER) && |
+ !attr_assigned) { |
+ builder() |
+ ->LoadLiteral(Smi::FromInt(DONT_ENUM)) |
+ .StoreAccumulatorInRegister(attr); |
+ attr_assigned = true; |
+ } |
+ |
+ switch (property->kind()) { |
+ case ObjectLiteral::Property::CONSTANT: |
+ case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
+ case ObjectLiteral::Property::PROTOTYPE: |
+ // Invalid properties for ES6 classes. |
+ UNREACHABLE(); |
+ break; |
+ case ObjectLiteral::Property::COMPUTED: { |
+ builder()->CallRuntime(Runtime::kDefineClassMethod, receiver, 3); |
+ break; |
+ } |
+ case ObjectLiteral::Property::GETTER: { |
+ builder()->CallRuntime(Runtime::kDefineGetterPropertyUnchecked, |
+ receiver, 4); |
+ break; |
+ } |
+ case ObjectLiteral::Property::SETTER: { |
+ builder()->CallRuntime(Runtime::kDefineSetterPropertyUnchecked, |
+ receiver, 4); |
+ break; |
+ } |
+ } |
+ } |
+} |
+ |
+void BytecodeGenerator::VisitClassLiteralStaticPrototypeWithComputedName( |
+ Register key) { |
+ BytecodeLabel done; |
+ builder() |
+ ->LoadLiteral(isolate()->factory()->prototype_string()) |
+ .CompareOperation(Token::Value::EQ_STRICT, key, Strength::WEAK) |
+ .JumpIfFalse(&done) |
+ .CallRuntime(Runtime::kThrowStaticPrototypeError, Register(0), 0) |
+ .Bind(&done); |
+} |
void BytecodeGenerator::VisitNativeFunctionLiteral( |
NativeFunctionLiteral* expr) { |
@@ -2520,6 +2659,13 @@ void BytecodeGenerator::VisitForAccumulatorValue(Expression* expr) { |
Visit(expr); |
} |
+void BytecodeGenerator::VisitForAccumulatorValueOrTheHole(Expression* expr) { |
+ if (expr == nullptr) { |
+ builder()->LoadTheHole(); |
+ } else { |
+ VisitForAccumulatorValue(expr); |
+ } |
+} |
// Visits the expression |expr| and discards the result. |
void BytecodeGenerator::VisitForEffect(Expression* expr) { |