Index: src/code-stub-assembler.cc |
diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc |
index 3bf07277044e05fb093777627b32c100556629ad..3b628d868337292ecc72b58b2d740d22466a48ce 100644 |
--- a/src/code-stub-assembler.cc |
+++ b/src/code-stub-assembler.cc |
@@ -3137,5 +3137,72 @@ void CodeStubAssembler::LoadGlobalIC(const LoadICParameters* p) { |
} |
} |
+Node* CodeStubAssembler::EnumLength(Node* map) { |
+ Node* bitfield_3 = LoadMapBitField3(map); |
+ Node* enum_length = BitFieldDecode<Map::EnumLengthBits>(bitfield_3); |
+ return SmiTag(enum_length); |
+} |
+ |
+void CodeStubAssembler::CheckEnumCache(Node* receiver, Label* use_cache, |
+ 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 loop(this, 2, loop_vars), next(this); |
+ |
+ // 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()); |
+ BranchIfWordEqual(enum_length, invalid_enum_cache_sentinel, use_runtime, |
+ &loop); |
+ } |
+ |
+ // Check that there are no elements. |current_js_object| contains |
+ // the current JS object we've reached through the prototype chain. |
+ Bind(&loop); |
+ { |
+ 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. |
+ BranchIfWordEqual(elements, empty_fixed_array, &if_no_elements, |
+ &if_elements); |
+ Bind(&if_elements); |
+ { |
+ // Second chance, the object may be using the empty slow element |
+ // dictionary. |
+ Node* slow_empty_dictionary = |
+ LoadRoot(Heap::kEmptySlowElementDictionaryRootIndex); |
+ BranchIfWordNotEqual(elements, slow_empty_dictionary, use_runtime, |
+ &if_no_elements); |
+ } |
+ |
+ Bind(&if_no_elements); |
+ { |
+ // Update map prototype. |
+ current_js_object.Bind(LoadMapPrototype(current_map.value())); |
+ BranchIfWordEqual(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), &loop, use_runtime); |
+ } |
+} |
+ |
} // namespace internal |
} // namespace v8 |