| 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
|
|
|