Index: src/interpreter/interpreter-assembler.cc |
diff --git a/src/interpreter/interpreter-assembler.cc b/src/interpreter/interpreter-assembler.cc |
index 8f5d941e5a2e6632fd93c8a0965fc5999375e629..00cfd165001281e71f640969f7a7e0df963fbf71 100644 |
--- a/src/interpreter/interpreter-assembler.cc |
+++ b/src/interpreter/interpreter-assembler.cc |
@@ -630,6 +630,76 @@ Node* InterpreterAssembler::CallRuntimeN(Node* function_id, Node* context, |
first_arg, function_entry, result_size); |
} |
+Node* InterpreterAssembler::EnumLength(Node* map) { |
+ Node* bitfield_3 = LoadMapBitField3(map); |
+ Node* enum_length = BitFieldDecode<Map::EnumLengthBits>(bitfield_3); |
+ return SmiTag(enum_length); |
+} |
+ |
+void InterpreterAssembler::CheckEnumCache(Node* receiver, Label* use_cache, |
rmcilroy
2016/07/19 11:08:54
Could we move these both to CodeStubAssembler - th
oth
2016/07/19 12:59:25
Done.
|
+ Label* use_runtime) { |
+ Variable current_js_object(this, MachineRepresentation::kTagged); |
+ current_js_object.Bind(receiver); |
+ |
+ Variable current_map(this, MachineRepresentation::kTagged); |
+ current_map.Bind(LoadMap(current_js_object.value())); |
+ |
+ // These variables are updated in the loop below. |
+ Variable* loop_vars[2] = {¤t_js_object, ¤t_map}; |
+ Label start(this, 2, loop_vars); |
rmcilroy
2016/07/19 11:08:54
nit - start->loop
oth
2016/07/19 12:59:25
Done.
|
+ |
+ // Check if the enum length field is properly initialized, indicating that |
+ // there is an enum cache. |
+ { |
+ Node* invalid_enum_cache_sentinel = |
+ SmiConstant(Smi::FromInt(kInvalidEnumCacheSentinel)); |
+ Node* enum_length = EnumLength(current_map.value()); |
+ |
+ Node* condition = WordEqual(enum_length, invalid_enum_cache_sentinel); |
+ BranchIf(condition, use_runtime, &start); |
+ } |
+ |
+ Label next(this); |
rmcilroy
2016/07/19 11:08:54
nit - move definition next to start
oth
2016/07/19 12:59:25
Done.
|
+ |
+ // Check that there are no elements. prototype contains the current JS |
rmcilroy
2016/07/19 11:08:54
/s/prototype/|current_js_object| ?
oth
2016/07/19 12:59:25
Done.
|
+ // object we've reached through the prototype chain. |
+ Bind(&start); |
+ { |
+ Label if_elements(this), if_no_elements(this); |
+ Node* elements = LoadElements(current_js_object.value()); |
+ Node* empty_fixed_array = LoadRoot(Heap::kEmptyFixedArrayRootIndex); |
+ // Check that there are no elements. |
+ BranchIf(WordEqual(elements, empty_fixed_array), &if_no_elements, |
rmcilroy
2016/07/19 11:08:54
You can do BranchIfWordEqual if you like.
oth
2016/07/19 12:59:25
Done.
|
+ &if_elements); |
+ Bind(&if_elements); |
+ { |
+ // Second chance, the object may be using the empty slow element |
+ // dictionary. |
+ Node* slow_empty_dictionary = |
+ LoadRoot(Heap::kEmptySlowElementDictionaryRootIndex); |
+ BranchIf(WordNotEqual(elements, slow_empty_dictionary), use_runtime, |
+ &if_no_elements); |
+ } |
+ |
+ Bind(&if_no_elements); |
+ { |
+ // Update map prototype. |
+ current_js_object.Bind(LoadMapPrototype(current_map.value())); |
+ BranchIf(WordEqual(current_js_object.value(), NullConstant()), use_cache, |
+ &next); |
+ } |
+ } |
+ |
+ Bind(&next); |
+ { |
+ // For all objects but the receiver, check that the cache is empty. |
+ current_map.Bind(LoadMap(current_js_object.value())); |
+ Node* enum_length = EnumLength(current_map.value()); |
+ Node* zero_constant = SmiConstant(Smi::FromInt(0)); |
+ BranchIf(WordEqual(enum_length, zero_constant), &start, use_runtime); |
+ } |
+} |
+ |
void InterpreterAssembler::UpdateInterruptBudget(Node* weight) { |
Label ok(this), interrupt_check(this, Label::kDeferred), end(this); |
Node* budget_offset = |