Chromium Code Reviews| Index: src/interpreter/bytecode-generator.cc |
| diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc |
| index be2a558b86d0c9fe1abfd377b82c649bc55408d9..2346444d4b1e9c14da5dd6db4c824fc3a6c1a456 100644 |
| --- a/src/interpreter/bytecode-generator.cc |
| +++ b/src/interpreter/bytecode-generator.cc |
| @@ -1226,9 +1226,145 @@ 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); |
| + builder()->LoadPrototypeOrInitialMap(); |
|
rmcilroy
2016/02/04 14:56:41
nit - chain builders (in functions below too) ?
oth
2016/02/04 16:59:48
Done.
|
| + builder()->StoreAccumulatorInRegister(prototype); |
| + VisitClassLiteralProperties(expr, literal, prototype); |
| + |
| + // Set both the prototype and constructor to have fast properties, and also |
| + // freeze them in strong mode. |
|
rmcilroy
2016/02/04 14:56:41
Remove the comment about strong mode (we don't sup
oth
2016/02/04 16:59:48
Done.
|
| + 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()); |
|
rmcilroy
2016/02/04 14:56:41
nit - newline above (bit of a wall of text otherwi
oth
2016/02/04 16:59:48
Done.
|
| + builder()->StoreAccumulatorInRegister(extends); |
| + VisitForAccumulatorValue(expr->constructor()); |
| + builder()->StoreAccumulatorInRegister(constructor); |
| + builder()->LoadLiteral(Smi::FromInt(expr->start_position())); |
| + builder()->StoreAccumulatorInRegister(start_position); |
| + builder()->LoadLiteral(Smi::FromInt(expr->end_position())); |
| + builder()->StoreAccumulatorInRegister(end_position); |
| + builder()->CallRuntime(Runtime::kDefineClass, extends, 4); |
| + result_scope.SetResultInAccumulator(); |
| +} |
| + |
| +void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr, |
| + Register literal, |
| + Register prototype) { |
| + EffectResultScope result_scope(this); |
|
rmcilroy
2016/02/04 14:56:41
Remove please (or replace with a RegisterAllocatio
oth
2016/02/04 16:59:48
Done.
|
| + |
| + 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(); |
| + builder()->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. |
|
rmcilroy
2016/02/04 14:56:40
I think this comment might make more sense in Visi
oth
2016/02/04 16:59:48
It seems like the right place as it explains the p
rmcilroy
2016/02/04 17:37:06
Yeah sorry you are right, it belongs here.
|
| + 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: |
| + UNREACHABLE(); |
|
rmcilroy
2016/02/04 14:56:41
nit - comment on why this should be unreachable an
oth
2016/02/04 16:59:48
Done.
|
| + 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()); |
| + builder()->CompareOperation(Token::Value::EQ_STRICT, key, Strength::WEAK); |
| + builder()->JumpIfFalse(&done); |
| + builder()->CallRuntime(Runtime::kThrowStaticPrototypeError, Register(0), 0); |
| + builder()->Bind(&done); |
| +} |
| void BytecodeGenerator::VisitNativeFunctionLiteral( |
| NativeFunctionLiteral* expr) { |
| @@ -2518,6 +2654,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) { |