Index: src/ast.cc |
diff --git a/src/ast.cc b/src/ast.cc |
index 53d27999ea073768fd0f879121cddf7964974732..bb05c3a21263339bf1613c0d627cdbcdf6783771 100644 |
--- a/src/ast.cc |
+++ b/src/ast.cc |
@@ -220,26 +220,142 @@ bool ObjectLiteral::Property::emit_store() { |
} |
+enum ObjectLiteralPropertyState { |
+ kNoPropertyState = 0, |
+ kDataPropertyState = 1, |
+ kGetterPropertyState = 2, |
+ kSetterPropertyState = 3, |
+ kAccessorPropertyState = 4 // Getter and setter fixed. |
+}; |
+ |
+ |
void ObjectLiteral::CalculateEmitStore(Zone* zone) { |
ZoneAllocationPolicy allocator(zone); |
+ // Map of Literal -> ObjectLiteralPropertyState |
ZoneHashMap table(Literal::Match, ZoneHashMap::kDefaultHashMapCapacity, |
allocator); |
+ |
+ bool has_dunder_proto = false; |
+ |
+ // Visit properties from last to first. |
for (int i = properties()->length() - 1; i >= 0; i--) { |
ObjectLiteral::Property* property = properties()->at(i); |
Literal* literal = property->key(); |
- if (literal->value()->IsNull()) continue; |
+ ASSERT(!literal->value()->IsNull()); |
uint32_t hash = literal->Hash(); |
- // If the key of a computed property is in the table, do not emit |
- // a store for the property later. |
- if ((property->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL || |
- property->kind() == ObjectLiteral::Property::COMPUTED) && |
- table.Lookup(literal, hash, false, allocator) != NULL) { |
+ |
+ if (property->IsCompileTimeValue()) |
property->set_emit_store(false); |
- } else { |
- // Add key to the table. |
- table.Lookup(literal, hash, true, allocator); |
+ |
+ ObjectLiteralPropertyState old_state, new_state; |
+ |
+ ZoneHashMap::Entry *entry = table.Lookup(literal, hash, true, allocator); |
+ uintptr_t old_state_bits = reinterpret_cast<uintptr_t>(entry->value); |
+ old_state = static_cast<ObjectLiteralPropertyState>(old_state_bits); |
+ new_state = old_state; |
+ switch (old_state) { |
+ case kNoPropertyState: |
+ switch (property->kind()) { |
+ case ObjectLiteral::Property::CONSTANT: |
+ case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
+ case ObjectLiteral::Property::COMPUTED: |
+ new_state = kDataPropertyState; |
+ break; |
+ case ObjectLiteral::Property::GETTER: |
+ new_state = kGetterPropertyState; |
+ break; |
+ case ObjectLiteral::Property::SETTER: |
+ new_state = kSetterPropertyState; |
+ break; |
+ case ObjectLiteral::Property::PROTOTYPE: |
+ if (has_dunder_proto) property->set_emit_store(false); |
+ has_dunder_proto = true; |
+ continue; |
+ } |
+ break; |
+ case kDataPropertyState: |
+ // This property is overridden by a later data property. |
+ switch (property->kind()) { |
+ case ObjectLiteral::Property::CONSTANT: |
+ case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
+ case ObjectLiteral::Property::COMPUTED: |
+ case ObjectLiteral::Property::GETTER: |
+ case ObjectLiteral::Property::SETTER: |
+ property->set_emit_store(false); |
+ break; |
+ case ObjectLiteral::Property::PROTOTYPE: |
+ if (has_dunder_proto) property->set_emit_store(false); |
+ has_dunder_proto = true; |
+ break; |
+ } |
+ break; |
+ case kGetterPropertyState: |
+ switch (property->kind()) { |
+ case ObjectLiteral::Property::CONSTANT: |
+ case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
+ case ObjectLiteral::Property::COMPUTED: |
+ // This getter will not have a corresponding setter. |
+ new_state = kAccessorPropertyState; |
+ property->set_emit_store(false); |
+ break; |
+ case ObjectLiteral::Property::GETTER: |
+ property->set_emit_store(false); |
+ break; |
+ case ObjectLiteral::Property::SETTER: |
+ new_state = kAccessorPropertyState; |
+ break; |
+ case ObjectLiteral::Property::PROTOTYPE: |
+ // This getter will not have a corresponding setter. |
+ new_state = kAccessorPropertyState; |
+ if (has_dunder_proto) property->set_emit_store(false); |
+ has_dunder_proto = true; |
+ break; |
+ } |
+ break; |
+ case kSetterPropertyState: |
+ switch (property->kind()) { |
+ case ObjectLiteral::Property::CONSTANT: |
+ case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
+ case ObjectLiteral::Property::COMPUTED: |
+ // This setter will not have a corresponding getter. |
+ new_state = kAccessorPropertyState; |
+ property->set_emit_store(false); |
+ break; |
+ case ObjectLiteral::Property::GETTER: |
+ new_state = kAccessorPropertyState; |
+ break; |
+ case ObjectLiteral::Property::SETTER: |
+ property->set_emit_store(false); |
+ break; |
+ case ObjectLiteral::Property::PROTOTYPE: |
+ // This setter will not have a corresponding getter. |
+ new_state = kAccessorPropertyState; |
+ if (has_dunder_proto) property->set_emit_store(false); |
+ has_dunder_proto = true; |
+ break; |
+ } |
+ break; |
+ case kAccessorPropertyState: |
+ // This property is overridden by a later accessor property. |
+ switch (property->kind()) { |
+ case ObjectLiteral::Property::CONSTANT: |
+ case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
+ case ObjectLiteral::Property::COMPUTED: |
+ case ObjectLiteral::Property::GETTER: |
+ case ObjectLiteral::Property::SETTER: |
+ property->set_emit_store(false); |
+ break; |
+ case ObjectLiteral::Property::PROTOTYPE: |
+ if (has_dunder_proto) property->set_emit_store(false); |
+ has_dunder_proto = true; |
+ break; |
+ } |
+ break; |
+ default: |
+ UNREACHABLE(); |
} |
+ entry->value = reinterpret_cast<void*>(new_state); |
} |
} |