Index: src/interpreter/bytecode-generator.cc |
diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc |
index cf20652a58a93dbf1ce6f3acc7a13883e5914e93..259d5eed54947e9c34a0b8beb28a61dcf26550b1 100644 |
--- a/src/interpreter/bytecode-generator.cc |
+++ b/src/interpreter/bytecode-generator.cc |
@@ -7,6 +7,7 @@ |
#include <stack> |
#include "src/compiler.h" |
+#include "src/full-codegen/full-codegen.h" |
#include "src/interpreter/control-flow-builders.h" |
#include "src/objects.h" |
#include "src/parser.h" |
@@ -497,7 +498,185 @@ void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
- UNIMPLEMENTED(); |
+ // Deep-copy the literal boilerplate. |
+ builder() |
+ ->LoadLiteral(expr->constant_properties()) |
+ .CreateObjectLiteral(expr->literal_index(), expr->ComputeFlags(true)); |
+ |
+ TemporaryRegisterScope temporary_register_scope(builder()); |
+ Register literal; |
+ |
+ // Store computed values into the literal. |
+ bool literal_in_accumulator = true; |
+ int property_index = 0; |
+ AccessorTable accessor_table(zone()); |
+ for (; property_index < expr->properties()->length(); property_index++) { |
+ TemporaryRegisterScope inner_temporary_register_scope(builder()); |
+ ObjectLiteral::Property* property = expr->properties()->at(property_index); |
+ if (property->is_computed_name()) break; |
+ if (property->IsCompileTimeValue()) continue; |
+ |
+ if (literal_in_accumulator) { |
+ literal = temporary_register_scope.NewRegister(); |
+ builder()->StoreAccumulatorInRegister(literal); |
+ literal_in_accumulator = false; |
+ } |
+ |
+ Literal* literal_key = property->key()->AsLiteral(); |
+ switch (property->kind()) { |
+ case ObjectLiteral::Property::CONSTANT: |
+ UNREACHABLE(); |
+ case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
+ DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value())); |
+ // Fall through. |
+ case ObjectLiteral::Property::COMPUTED: { |
+ // It is safe to use [[Put]] here because the boilerplate already |
+ // contains computed properties with an uninitialized value. |
+ if (literal_key->value()->IsInternalizedString()) { |
+ if (property->emit_store()) { |
+ Register name = inner_temporary_register_scope.NewRegister(); |
+ builder() |
+ ->LoadLiteral(literal_key->AsPropertyName()) |
+ .StoreAccumulatorInRegister(name); |
+ Visit(property->value()); |
+ builder()->StoreNamedProperty(literal, name, |
+ feedback_index(property->GetSlot(0)), |
+ language_mode()); |
+ } else { |
+ Visit(property->value()); |
+ } |
+ } else { |
+ Register key = inner_temporary_register_scope.NewRegister(); |
+ Register value = inner_temporary_register_scope.NewRegister(); |
+ Register language = inner_temporary_register_scope.NewRegister(); |
+ DCHECK(Register::AreContiguous(literal, key, value, language)); |
+ Visit(property->key()); |
+ builder()->StoreAccumulatorInRegister(key); |
+ Visit(property->value()); |
+ builder()->StoreAccumulatorInRegister(value); |
+ if (property->emit_store()) { |
+ builder() |
+ ->LoadLiteral(Smi::FromInt(SLOPPY)) |
+ .StoreAccumulatorInRegister(language) |
+ .CallRuntime(Runtime::kSetProperty, literal, 4); |
+ VisitSetHomeObject(value, literal, property); |
+ } |
+ } |
+ break; |
+ } |
+ case ObjectLiteral::Property::PROTOTYPE: { |
+ DCHECK(property->emit_store()); |
+ Register value = inner_temporary_register_scope.NewRegister(); |
+ DCHECK(Register::AreContiguous(literal, value)); |
+ Visit(property->value()); |
+ builder()->StoreAccumulatorInRegister(value).CallRuntime( |
+ Runtime::kInternalSetPrototype, literal, 2); |
+ break; |
+ } |
+ case ObjectLiteral::Property::GETTER: |
+ if (property->emit_store()) { |
+ accessor_table.lookup(literal_key)->second->getter = property; |
+ } |
+ break; |
+ case ObjectLiteral::Property::SETTER: |
+ if (property->emit_store()) { |
+ accessor_table.lookup(literal_key)->second->setter = property; |
+ } |
+ break; |
+ } |
+ } |
+ |
+ // Create nodes to define accessors, using only a single call to the runtime |
+ // for each pair of corresponding getters and setters. |
+ for (AccessorTable::Iterator it = accessor_table.begin(); |
+ it != accessor_table.end(); ++it) { |
+ TemporaryRegisterScope inner_temporary_register_scope(builder()); |
+ Register name = inner_temporary_register_scope.NewRegister(); |
+ Register getter = inner_temporary_register_scope.NewRegister(); |
+ Register setter = inner_temporary_register_scope.NewRegister(); |
+ Register attr = inner_temporary_register_scope.NewRegister(); |
+ DCHECK(Register::AreContiguous(literal, name, getter, setter, attr)); |
+ Visit(it->first); |
+ builder()->StoreAccumulatorInRegister(name); |
+ VisitObjectLiteralAccessor(literal, it->second->getter, getter); |
+ VisitObjectLiteralAccessor(literal, it->second->setter, setter); |
+ builder() |
+ ->LoadLiteral(Smi::FromInt(NONE)) |
+ .StoreAccumulatorInRegister(attr) |
+ .CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, literal, 5); |
+ } |
+ |
+ // Object literals have two parts. The "static" part on the left contains no |
+ // computed property names, and so we can compute its map ahead of time; see |
+ // Runtime_CreateObjectLiteralBoilerplate. The second "dynamic" part starts |
+ // with the first computed property name and continues with all properties to |
+ // its right. All the code from above initializes the static component of the |
+ // object literal, and arranges for the map of the result to reflect the |
+ // static order in which the keys appear. For the dynamic properties, we |
+ // compile them into a series of "SetOwnProperty" runtime calls. This will |
+ // preserve insertion order. |
+ for (; property_index < expr->properties()->length(); property_index++) { |
+ ObjectLiteral::Property* property = expr->properties()->at(property_index); |
+ |
+ if (literal_in_accumulator) { |
+ literal = temporary_register_scope.NewRegister(); |
+ builder()->StoreAccumulatorInRegister(literal); |
+ literal_in_accumulator = false; |
+ } |
+ |
+ if (property->kind() == ObjectLiteral::Property::PROTOTYPE) { |
+ DCHECK(property->emit_store()); |
+ TemporaryRegisterScope inner_temporary_register_scope(builder()); |
+ Register value = inner_temporary_register_scope.NewRegister(); |
+ DCHECK(Register::AreContiguous(literal, value)); |
+ Visit(property->value()); |
+ builder()->StoreAccumulatorInRegister(value).CallRuntime( |
+ Runtime::kInternalSetPrototype, literal, 2); |
+ continue; |
+ } |
+ |
+ TemporaryRegisterScope inner_temporary_register_scope(builder()); |
+ Register key = inner_temporary_register_scope.NewRegister(); |
+ Register value = inner_temporary_register_scope.NewRegister(); |
+ Register attr = inner_temporary_register_scope.NewRegister(); |
+ DCHECK(Register::AreContiguous(literal, key, value, attr)); |
+ |
+ Visit(property->key()); |
+ builder()->CastAccumulatorToName().StoreAccumulatorInRegister(key); |
+ Visit(property->value()); |
+ builder()->StoreAccumulatorInRegister(value); |
+ VisitSetHomeObject(value, literal, property); |
+ builder()->LoadLiteral(Smi::FromInt(NONE)).StoreAccumulatorInRegister(attr); |
+ Runtime::FunctionId function_id = static_cast<Runtime::FunctionId>(-1); |
+ switch (property->kind()) { |
+ case ObjectLiteral::Property::CONSTANT: |
+ case ObjectLiteral::Property::COMPUTED: |
+ case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
+ function_id = Runtime::kDefineDataPropertyUnchecked; |
+ break; |
+ case ObjectLiteral::Property::PROTOTYPE: |
+ UNREACHABLE(); // Handled specially above. |
+ break; |
+ case ObjectLiteral::Property::GETTER: |
+ function_id = Runtime::kDefineGetterPropertyUnchecked; |
+ break; |
+ case ObjectLiteral::Property::SETTER: |
+ function_id = Runtime::kDefineSetterPropertyUnchecked; |
+ break; |
+ } |
+ builder()->CallRuntime(function_id, literal, 4); |
+ } |
+ |
+ // Transform literals that contain functions to fast properties. |
+ if (expr->has_function()) { |
+ DCHECK(!literal_in_accumulator); |
+ builder()->CallRuntime(Runtime::kToFastProperties, literal, 1); |
+ } |
+ |
+ if (!literal_in_accumulator) { |
+ // Restore literal array into accumulator. |
+ builder()->LoadAccumulatorWithRegister(literal); |
+ } |
} |
@@ -509,11 +688,11 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
.CreateArrayLiteral(expr->literal_index(), expr->ComputeFlags(true)); |
TemporaryRegisterScope temporary_register_scope(builder()); |
- Register index, literal_array; |
+ Register index, literal; |
// Create nodes to evaluate all the non-constant subexpressions and to store |
// them into the newly cloned array. |
- bool literal_array_in_accumulator = true; |
+ bool literal_in_accumulator = true; |
for (int array_index = 0; array_index < expr->values()->length(); |
array_index++) { |
Expression* subexpr = expr->values()->at(array_index); |
@@ -523,23 +702,23 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
UNIMPLEMENTED(); |
} |
- if (literal_array_in_accumulator) { |
+ if (literal_in_accumulator) { |
index = temporary_register_scope.NewRegister(); |
- literal_array = temporary_register_scope.NewRegister(); |
- builder()->StoreAccumulatorInRegister(literal_array); |
- literal_array_in_accumulator = false; |
+ literal = temporary_register_scope.NewRegister(); |
+ builder()->StoreAccumulatorInRegister(literal); |
+ literal_in_accumulator = false; |
} |
builder() |
->LoadLiteral(Smi::FromInt(array_index)) |
.StoreAccumulatorInRegister(index); |
Visit(subexpr); |
- builder()->GenericStoreKeyedProperty(literal_array, index); |
+ builder()->GenericStoreKeyedProperty(literal, index); |
} |
- if (!literal_array_in_accumulator) { |
+ if (!literal_in_accumulator) { |
// Restore literal array into accumulator. |
- builder()->LoadAccumulatorWithRegister(literal_array); |
+ builder()->LoadAccumulatorWithRegister(literal); |
} |
} |
@@ -937,7 +1116,7 @@ void BytecodeGenerator::VisitNewLocalFunctionContext() { |
TemporaryRegisterScope temporary_register_scope(builder()); |
Register closure = temporary_register_scope.NewRegister(); |
Register scope_info = temporary_register_scope.NewRegister(); |
- DCHECK_EQ(closure.index() + 1, scope_info.index()); |
+ DCHECK(Register::AreContiguous(closure, scope_info)); |
builder() |
->LoadAccumulatorWithRegister(Register::function_closure()) |
.StoreAccumulatorInRegister(closure) |
@@ -979,6 +1158,41 @@ void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* binop) { |
} |
+void BytecodeGenerator::VisitObjectLiteralAccessor( |
+ Register home_object, ObjectLiteralProperty* property, Register value_out) { |
+ // TODO(rmcilroy): Replace value_out with VisitForRegister(); |
+ if (property == nullptr) { |
+ builder()->LoadNull().StoreAccumulatorInRegister(value_out); |
+ } else { |
+ Visit(property->value()); |
+ builder()->StoreAccumulatorInRegister(value_out); |
+ VisitSetHomeObject(value_out, home_object, property); |
+ } |
+} |
+ |
+ |
+void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object, |
+ ObjectLiteralProperty* property, |
+ int slot_number) { |
+ Expression* expr = property->value(); |
+ if (!FunctionLiteral::NeedsHomeObject(expr)) return; |
+ |
+ // TODO(rmcilroy): Remove UNIMPLEMENTED once we have tests for setting the |
+ // home object. |
+ UNIMPLEMENTED(); |
+ |
+ TemporaryRegisterScope temporary_register_scope(builder()); |
+ Register name = temporary_register_scope.NewRegister(); |
+ isolate()->factory()->home_object_symbol(); |
+ builder() |
+ ->LoadLiteral(isolate()->factory()->home_object_symbol()) |
+ .StoreAccumulatorInRegister(name) |
+ .StoreNamedProperty(home_object, name, |
+ feedback_index(property->GetSlot(slot_number)), |
+ language_mode()); |
+} |
+ |
+ |
LanguageMode BytecodeGenerator::language_mode() const { |
return info()->language_mode(); |
} |