From 23332fe8296b48e66775e352de4759494553c12c Mon Sep 17 00:00:00 2001 From: ishell Date: Mon, 27 Jun 2016 05:26:57 -0700 Subject: [PATCH] [stubs] Implementing CodeStubAssembler::GetOwnProperty(). This is a building block for GetPropertyStub. It supports querying fast, slow and global objects without native accessors and interceptors. BUG=v8:4911 LOG=Y Review-Url: https://codereview.chromium.org/2079823002 Cr-Commit-Position: refs/heads/master@{#37291} --- src/builtins.cc | 2 +- src/code-stub-assembler.cc | 398 +++++++++++++++++++++--- src/code-stub-assembler.h | 68 +++- src/code-stubs.cc | 2 +- src/objects-inl.h | 10 +- src/objects.cc | 11 +- src/objects.h | 24 +- test/cctest/test-code-stub-assembler.cc | 316 ++++++++++++++++++- 8 files changed, 753 insertions(+), 78 deletions(-) diff --git a/src/builtins.cc b/src/builtins.cc index e5b6660c39..d79e857f33 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -368,7 +368,7 @@ void Builtins::Generate_ObjectHasOwnProperty(CodeStubAssembler* assembler) { &call_runtime); assembler->Bind(&if_iskeyunique); - assembler->TryLookupProperty(object, map, instance_type, key, &return_true, + assembler->TryHasOwnProperty(object, map, instance_type, key, &return_true, &return_false, &call_runtime); assembler->Bind(&keyisindex); diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc index 1d04964350..dca216718e 100644 --- a/src/code-stub-assembler.cc +++ b/src/code-stub-assembler.cc @@ -28,12 +28,12 @@ CodeStubAssembler::CodeStubAssembler(Isolate* isolate, Zone* zone, void CodeStubAssembler::Assert(Node* condition) { #if defined(DEBUG) Label ok(this); - Label not_ok(this); - Branch(condition, &ok, ¬_ok); - Bind(¬_ok); + Comment("[ Assert"); + GotoIf(condition, &ok); DebugBreak(); Goto(&ok); Bind(&ok); + Comment("] Assert"); #endif } @@ -494,6 +494,11 @@ Node* CodeStubAssembler::LoadObjectField(Node* object, int offset, return Load(rep, object, IntPtrConstant(offset - kHeapObjectTag)); } +Node* CodeStubAssembler::LoadObjectField(Node* object, Node* offset, + MachineType rep) { + return Load(rep, object, IntPtrSub(offset, IntPtrConstant(kHeapObjectTag))); +} + Node* CodeStubAssembler::LoadHeapNumberValue(Node* object) { return LoadObjectField(object, HeapNumber::kValueOffset, MachineType::Float64()); @@ -552,6 +557,16 @@ Node* CodeStubAssembler::LoadMapInstanceSize(Node* map) { return LoadObjectField(map, Map::kInstanceSizeOffset, MachineType::Uint8()); } +Node* CodeStubAssembler::LoadMapInobjectProperties(Node* map) { + // See Map::GetInObjectProperties() for details. + STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE); + Assert(Int32GreaterThanOrEqual(LoadMapInstanceType(map), + Int32Constant(FIRST_JS_OBJECT_TYPE))); + return LoadObjectField( + map, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset, + MachineType::Uint8()); +} + Node* CodeStubAssembler::LoadNameHashField(Node* name) { return LoadObjectField(name, Name::kHashFieldOffset, MachineType::Uint32()); } @@ -1491,6 +1506,7 @@ void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, Variable* var_index, Label* if_keyisunique, Label* if_bailout) { DCHECK_EQ(MachineRepresentation::kWord32, var_index->rep()); + Comment("TryToName"); Label if_keyissmi(this), if_keyisnotsmi(this); Branch(WordIsSmi(key), &if_keyissmi, &if_keyisnotsmi); @@ -1532,16 +1548,21 @@ void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, Goto(if_keyisindex); } +template +Node* CodeStubAssembler::EntryToIndex(Node* entry, int field_index) { + Node* entry_index = Int32Mul(entry, Int32Constant(Dictionary::kEntrySize)); + return Int32Add(entry_index, + Int32Constant(Dictionary::kElementsStartIndex + field_index)); +} + template void CodeStubAssembler::NameDictionaryLookup(Node* dictionary, Node* unique_name, Label* if_found, - Variable* var_entry, + Variable* var_name_index, Label* if_not_found, int inlined_probes) { - DCHECK_EQ(MachineRepresentation::kWord32, var_entry->rep()); - - const int kElementsStartOffset = - Dictionary::kElementsStartIndex * kPointerSize; + DCHECK_EQ(MachineRepresentation::kWord32, var_name_index->rep()); + Comment("NameDictionaryLookup"); Node* capacity = SmiToWord32(LoadFixedArrayElement( dictionary, Int32Constant(Dictionary::kCapacityIndex))); @@ -1553,11 +1574,10 @@ void CodeStubAssembler::NameDictionaryLookup(Node* dictionary, Node* entry = Word32And(hash, mask); for (int i = 0; i < inlined_probes; i++) { - // See Dictionary::EntryToIndex() - Node* index = Int32Mul(entry, Int32Constant(Dictionary::kEntrySize)); - Node* current = - LoadFixedArrayElement(dictionary, index, kElementsStartOffset); - var_entry->Bind(entry); + Node* index = EntryToIndex(entry); + var_name_index->Bind(index); + + Node* current = LoadFixedArrayElement(dictionary, index); GotoIf(WordEqual(current, unique_name), if_found); // See Dictionary::NextProbe(). @@ -1568,20 +1588,21 @@ void CodeStubAssembler::NameDictionaryLookup(Node* dictionary, Node* undefined = UndefinedConstant(); Variable var_count(this, MachineRepresentation::kWord32); - Variable* loop_vars[] = {&var_count, var_entry}; - Label loop(this, 2, loop_vars); + Variable var_entry(this, MachineRepresentation::kWord32); + Variable* loop_vars[] = {&var_count, &var_entry, var_name_index}; + Label loop(this, 3, loop_vars); var_count.Bind(count); - var_entry->Bind(entry); + var_entry.Bind(entry); Goto(&loop); Bind(&loop); { Node* count = var_count.value(); - Node* entry = var_entry->value(); + Node* entry = var_entry.value(); - // See Dictionary::EntryToIndex() - Node* index = Int32Mul(entry, Int32Constant(Dictionary::kEntrySize)); - Node* current = - LoadFixedArrayElement(dictionary, index, kElementsStartOffset); + Node* index = EntryToIndex(entry); + var_name_index->Bind(index); + + Node* current = LoadFixedArrayElement(dictionary, index); GotoIf(WordEqual(current, undefined), if_not_found); GotoIf(WordEqual(current, unique_name), if_found); @@ -1590,7 +1611,7 @@ void CodeStubAssembler::NameDictionaryLookup(Node* dictionary, entry = Word32And(Int32Add(entry, count), mask); var_count.Bind(count); - var_entry->Bind(entry); + var_entry.Bind(entry); Goto(&loop); } } @@ -1621,9 +1642,7 @@ void CodeStubAssembler::NumberDictionaryLookup(Node* dictionary, Node* key, Variable* var_entry, Label* if_not_found) { DCHECK_EQ(MachineRepresentation::kWord32, var_entry->rep()); - - const int kElementsStartOffset = - Dictionary::kElementsStartIndex * kPointerSize; + Comment("NumberDictionaryLookup"); Node* capacity = SmiToWord32(LoadFixedArrayElement( dictionary, Int32Constant(Dictionary::kCapacityIndex))); @@ -1656,10 +1675,8 @@ void CodeStubAssembler::NumberDictionaryLookup(Node* dictionary, Node* key, Node* count = var_count.value(); Node* entry = var_entry->value(); - // See Dictionary::EntryToIndex() - Node* index = Int32Mul(entry, Int32Constant(Dictionary::kEntrySize)); - Node* current = - LoadFixedArrayElement(dictionary, index, kElementsStartOffset); + Node* index = EntryToIndex(entry); + Node* current = LoadFixedArrayElement(dictionary, index); GotoIf(WordEqual(current, undefined), if_not_found); Label next_probe(this); { @@ -1691,23 +1708,32 @@ void CodeStubAssembler::NumberDictionaryLookup(Node* dictionary, Node* key, } } -void CodeStubAssembler::TryLookupProperty(Node* object, Node* map, - Node* instance_type, - Node* unique_name, Label* if_found, - Label* if_not_found, - Label* if_bailout) { +void CodeStubAssembler::TryLookupProperty( + Node* object, Node* map, Node* instance_type, Node* unique_name, + Label* if_found_fast, Label* if_found_dict, Label* if_found_global, + Variable* var_meta_storage, Variable* var_name_index, Label* if_not_found, + Label* if_bailout) { + DCHECK_EQ(MachineRepresentation::kTagged, var_meta_storage->rep()); + DCHECK_EQ(MachineRepresentation::kWord32, var_name_index->rep()); + Label if_objectisspecial(this); STATIC_ASSERT(JS_GLOBAL_OBJECT_TYPE <= LAST_SPECIAL_RECEIVER_TYPE); GotoIf(Int32LessThanOrEqual(instance_type, Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)), &if_objectisspecial); + Node* bit_field = LoadMapBitField(map); + Node* mask = Int32Constant(1 << Map::kHasNamedInterceptor | + 1 << Map::kIsAccessCheckNeeded); + Assert(Word32Equal(Word32And(bit_field, mask), Int32Constant(0))); + Node* bit_field3 = LoadMapBitField3(map); Node* bit = BitFieldDecode(bit_field3); Label if_isfastmap(this), if_isslowmap(this); Branch(Word32Equal(bit, Int32Constant(0)), &if_isfastmap, &if_isslowmap); Bind(&if_isfastmap); { + Comment("DescriptorArrayLookup"); Node* nof = BitFieldDecode(bit_field3); // Bail out to the runtime for large numbers of own descriptors. The stub // only does linear search, which becomes too expensive in that case. @@ -1716,6 +1742,7 @@ void CodeStubAssembler::TryLookupProperty(Node* object, Node* map, GotoIf(Int32GreaterThan(nof, Int32Constant(kMaxLinear)), if_bailout); } Node* descriptors = LoadMapDescriptors(map); + var_meta_storage->Bind(descriptors); Variable var_descriptor(this, MachineRepresentation::kWord32); Label loop(this, &var_descriptor); @@ -1724,13 +1751,15 @@ void CodeStubAssembler::TryLookupProperty(Node* object, Node* map, Bind(&loop); { Node* index = var_descriptor.value(); - Node* offset = Int32Constant(DescriptorArray::ToKeyIndex(0)); + Node* name_offset = Int32Constant(DescriptorArray::ToKeyIndex(0)); Node* factor = Int32Constant(DescriptorArray::kDescriptorSize); GotoIf(Word32Equal(index, nof), if_not_found); - Node* array_index = Int32Add(offset, Int32Mul(index, factor)); - Node* current = LoadFixedArrayElement(descriptors, array_index); - GotoIf(WordEqual(current, unique_name), if_found); + Node* name_index = Int32Add(name_offset, Int32Mul(index, factor)); + Node* name = LoadFixedArrayElement(descriptors, name_index); + + var_name_index->Bind(name_index); + GotoIf(WordEqual(name, unique_name), if_found_fast); var_descriptor.Bind(Int32Add(index, Int32Constant(1))); Goto(&loop); @@ -1738,22 +1767,301 @@ void CodeStubAssembler::TryLookupProperty(Node* object, Node* map, } Bind(&if_isslowmap); { - Variable var_entry(this, MachineRepresentation::kWord32); Node* dictionary = LoadProperties(object); + var_meta_storage->Bind(dictionary); - NameDictionaryLookup(dictionary, unique_name, if_found, - &var_entry, if_not_found); + NameDictionaryLookup(dictionary, unique_name, if_found_dict, + var_name_index, if_not_found); } Bind(&if_objectisspecial); { // Handle global object here and other special objects in runtime. GotoUnless(Word32Equal(instance_type, Int32Constant(JS_GLOBAL_OBJECT_TYPE)), if_bailout); - Variable var_entry(this, MachineRepresentation::kWord32); - Node* dictionary = LoadProperties(object); - NameDictionaryLookup(dictionary, unique_name, if_found, - &var_entry, if_not_found); + // Handle interceptors and access checks in runtime. + Node* bit_field = LoadMapBitField(map); + Node* mask = Int32Constant(1 << Map::kHasNamedInterceptor | + 1 << Map::kIsAccessCheckNeeded); + GotoIf(Word32NotEqual(Word32And(bit_field, mask), Int32Constant(0)), + if_bailout); + + Node* dictionary = LoadProperties(object); + var_meta_storage->Bind(dictionary); + + NameDictionaryLookup( + dictionary, unique_name, if_found_global, var_name_index, if_not_found); + } +} + +void CodeStubAssembler::TryHasOwnProperty(compiler::Node* object, + compiler::Node* map, + compiler::Node* instance_type, + compiler::Node* unique_name, + Label* if_found, Label* if_not_found, + Label* if_bailout) { + Comment("TryHasOwnProperty"); + Variable var_meta_storage(this, MachineRepresentation::kTagged); + Variable var_name_index(this, MachineRepresentation::kWord32); + + Label if_found_global(this); + TryLookupProperty(object, map, instance_type, unique_name, if_found, if_found, + &if_found_global, &var_meta_storage, &var_name_index, + if_not_found, if_bailout); + Bind(&if_found_global); + { + Variable var_value(this, MachineRepresentation::kTagged); + Variable var_details(this, MachineRepresentation::kWord32); + // Check if the property cell is not deleted. + LoadPropertyFromGlobalDictionary(var_meta_storage.value(), + var_name_index.value(), &var_value, + &var_details, if_not_found); + Goto(if_found); + } +} + +void CodeStubAssembler::LoadPropertyFromFastObject(Node* object, Node* map, + Node* descriptors, + Node* name_index, + Variable* var_details, + Variable* var_value) { + DCHECK_EQ(MachineRepresentation::kWord32, var_details->rep()); + DCHECK_EQ(MachineRepresentation::kTagged, var_value->rep()); + Comment("[ LoadPropertyFromFastObject"); + + const int name_to_details_offset = + (DescriptorArray::kDescriptorDetails - DescriptorArray::kDescriptorKey) * + kPointerSize; + const int name_to_value_offset = + (DescriptorArray::kDescriptorValue - DescriptorArray::kDescriptorKey) * + kPointerSize; + + Node* details = SmiToWord32( + LoadFixedArrayElement(descriptors, name_index, name_to_details_offset)); + var_details->Bind(details); + + Node* location = BitFieldDecode(details); + + Label if_in_field(this), if_in_descriptor(this), done(this); + Branch(Word32Equal(location, Int32Constant(kField)), &if_in_field, + &if_in_descriptor); + Bind(&if_in_field); + { + Node* field_index = + BitFieldDecode(details); + Node* representation = + BitFieldDecode(details); + + Node* inobject_properties = LoadMapInobjectProperties(map); + + Label if_inobject(this), if_backing_store(this); + Variable var_double_value(this, MachineRepresentation::kFloat64); + Label rebox_double(this, &var_double_value); + BranchIfInt32LessThan(field_index, inobject_properties, &if_inobject, + &if_backing_store); + Bind(&if_inobject); + { + Comment("if_inobject"); + Node* field_offset = ChangeInt32ToIntPtr( + Int32Mul(Int32Sub(LoadMapInstanceSize(map), + Int32Sub(inobject_properties, field_index)), + Int32Constant(kPointerSize))); + + Label if_double(this), if_tagged(this); + BranchIfWord32NotEqual(representation, + Int32Constant(Representation::kDouble), &if_tagged, + &if_double); + Bind(&if_tagged); + { + var_value->Bind(LoadObjectField(object, field_offset)); + Goto(&done); + } + Bind(&if_double); + { + if (FLAG_unbox_double_fields) { + var_double_value.Bind( + LoadObjectField(object, field_offset, MachineType::Float64())); + } else { + Node* mutable_heap_number = LoadObjectField(object, field_offset); + var_double_value.Bind(LoadHeapNumberValue(mutable_heap_number)); + } + Goto(&rebox_double); + } + } + Bind(&if_backing_store); + { + Comment("if_backing_store"); + Node* properties = LoadProperties(object); + field_index = Int32Sub(field_index, inobject_properties); + Node* value = LoadFixedArrayElement(properties, field_index); + + Label if_double(this), if_tagged(this); + BranchIfWord32NotEqual(representation, + Int32Constant(Representation::kDouble), &if_tagged, + &if_double); + Bind(&if_tagged); + { + var_value->Bind(value); + Goto(&done); + } + Bind(&if_double); + { + var_double_value.Bind(LoadHeapNumberValue(value)); + Goto(&rebox_double); + } + } + Bind(&rebox_double); + { + Comment("rebox_double"); + Node* heap_number = AllocateHeapNumber(); + StoreHeapNumberValue(heap_number, var_double_value.value()); + var_value->Bind(heap_number); + Goto(&done); + } + } + Bind(&if_in_descriptor); + { + Node* value = + LoadFixedArrayElement(descriptors, name_index, name_to_value_offset); + var_value->Bind(value); + Goto(&done); + } + Bind(&done); + + Comment("] LoadPropertyFromFastObject"); +} + +void CodeStubAssembler::LoadPropertyFromNameDictionary(Node* dictionary, + Node* name_index, + Variable* var_details, + Variable* var_value) { + Comment("LoadPropertyFromNameDictionary"); + + const int name_to_details_offset = + (NameDictionary::kEntryDetailsIndex - NameDictionary::kEntryKeyIndex) * + kPointerSize; + const int name_to_value_offset = + (NameDictionary::kEntryValueIndex - NameDictionary::kEntryKeyIndex) * + kPointerSize; + + Node* details = SmiToWord32( + LoadFixedArrayElement(dictionary, name_index, name_to_details_offset)); + + var_details->Bind(details); + var_value->Bind( + LoadFixedArrayElement(dictionary, name_index, name_to_value_offset)); + + Comment("] LoadPropertyFromNameDictionary"); +} + +void CodeStubAssembler::LoadPropertyFromGlobalDictionary(Node* dictionary, + Node* name_index, + Variable* var_details, + Variable* var_value, + Label* if_deleted) { + Comment("[ LoadPropertyFromGlobalDictionary"); + + const int name_to_value_offset = + (GlobalDictionary::kEntryValueIndex - GlobalDictionary::kEntryKeyIndex) * + kPointerSize; + + Node* property_cell = + LoadFixedArrayElement(dictionary, name_index, name_to_value_offset); + + Node* value = LoadObjectField(property_cell, PropertyCell::kValueOffset); + GotoIf(WordEqual(value, TheHoleConstant()), if_deleted); + + var_value->Bind(value); + + Node* details = + SmiToWord32(LoadObjectField(property_cell, PropertyCell::kDetailsOffset)); + var_details->Bind(details); + + Comment("] LoadPropertyFromGlobalDictionary"); +} + +void CodeStubAssembler::TryGetOwnProperty( + Node* context, Node* receiver, Node* object, Node* map, Node* instance_type, + Node* unique_name, Label* if_found_value, Variable* var_value, + Label* if_not_found, Label* if_bailout) { + DCHECK_EQ(MachineRepresentation::kTagged, var_value->rep()); + Comment("TryGetOwnProperty"); + + Variable var_meta_storage(this, MachineRepresentation::kTagged); + Variable var_entry(this, MachineRepresentation::kWord32); + + Label if_found_fast(this), if_found_dict(this), if_found_global(this); + + Variable var_details(this, MachineRepresentation::kWord32); + Variable* vars[] = {var_value, &var_details}; + Label if_found(this, 2, vars); + + TryLookupProperty(object, map, instance_type, unique_name, &if_found_fast, + &if_found_dict, &if_found_global, &var_meta_storage, + &var_entry, if_not_found, if_bailout); + Bind(&if_found_fast); + { + Node* descriptors = var_meta_storage.value(); + Node* name_index = var_entry.value(); + + LoadPropertyFromFastObject(object, map, descriptors, name_index, + &var_details, var_value); + Goto(&if_found); + } + Bind(&if_found_dict); + { + Node* dictionary = var_meta_storage.value(); + Node* entry = var_entry.value(); + LoadPropertyFromNameDictionary(dictionary, entry, &var_details, var_value); + Goto(&if_found); + } + Bind(&if_found_global); + { + Node* dictionary = var_meta_storage.value(); + Node* entry = var_entry.value(); + + LoadPropertyFromGlobalDictionary(dictionary, entry, &var_details, var_value, + if_not_found); + Goto(&if_found); + } + // Here we have details and value which could be an accessor. + Bind(&if_found); + { + Node* details = var_details.value(); + Node* kind = BitFieldDecode(details); + + Label if_accessor(this); + Branch(Word32Equal(kind, Int32Constant(kData)), if_found_value, + &if_accessor); + Bind(&if_accessor); + { + Node* accessor_pair = var_value->value(); + GotoIf(Word32Equal(LoadInstanceType(accessor_pair), + Int32Constant(ACCESSOR_INFO_TYPE)), + if_bailout); + AssertInstanceType(accessor_pair, ACCESSOR_PAIR_TYPE); + Node* getter = + LoadObjectField(accessor_pair, AccessorPair::kGetterOffset); + Node* getter_map = LoadMap(getter); + Node* instance_type = LoadMapInstanceType(getter_map); + // FunctionTemplateInfo getters are not supported yet. + GotoIf(Word32Equal(instance_type, + Int32Constant(FUNCTION_TEMPLATE_INFO_TYPE)), + if_bailout); + + // Return undefined if the {getter} is not callable. + var_value->Bind(UndefinedConstant()); + GotoIf(Word32Equal(Word32And(LoadMapBitField(getter_map), + Int32Constant(1 << Map::kIsCallable)), + Int32Constant(0)), + if_found_value); + + // Call the accessor. + Callable callable = CodeFactory::Call(isolate()); + Node* result = CallJS(callable, context, getter, receiver); + var_value->Bind(result); + Goto(if_found_value); + } } } diff --git a/src/code-stub-assembler.h b/src/code-stub-assembler.h index 9585436c71..f10e3ad948 100644 --- a/src/code-stub-assembler.h +++ b/src/code-stub-assembler.h @@ -117,6 +117,10 @@ class CodeStubAssembler : public compiler::CodeAssembler { // Load a field from an object on the heap. compiler::Node* LoadObjectField(compiler::Node* object, int offset, MachineType rep = MachineType::AnyTagged()); + compiler::Node* LoadObjectField(compiler::Node* object, + compiler::Node* offset, + MachineType rep = MachineType::AnyTagged()); + // Load the floating point value of a HeapNumber. compiler::Node* LoadHeapNumberValue(compiler::Node* object); // Load the Map of an HeapObject. @@ -145,6 +149,8 @@ class CodeStubAssembler : public compiler::CodeAssembler { compiler::Node* LoadMapPrototype(compiler::Node* map); // Load the instance size of a Map. compiler::Node* LoadMapInstanceSize(compiler::Node* map); + // Load the inobject properties count of a Map (valid only for JSObjects). + compiler::Node* LoadMapInobjectProperties(compiler::Node* map); // Load the hash field of a name. compiler::Node* LoadNameHashField(compiler::Node* name); @@ -268,11 +274,24 @@ class CodeStubAssembler : public compiler::CodeAssembler { void TryToName(compiler::Node* key, Label* if_keyisindex, Variable* var_index, Label* if_keyisunique, Label* if_bailout); + // Calculates array index for given dictionary entry and entry field. + // See Dictionary::EntryToIndex(). + template + compiler::Node* EntryToIndex(compiler::Node* entry, int field_index); + template + compiler::Node* EntryToIndex(compiler::Node* entry) { + return EntryToIndex(entry, Dictionary::kEntryKeyIndex); + } + + // Looks up an entry in a NameDictionaryBase successor. If the entry is found + // control goes to {if_found} and {var_name_index} contains an index of the + // key field of the entry found. If the key is not found control goes to + // {if_not_found}. static const int kInlinedDictionaryProbes = 4; template void NameDictionaryLookup(compiler::Node* dictionary, compiler::Node* unique_name, Label* if_found, - Variable* var_entry, Label* if_not_found, + Variable* var_name_index, Label* if_not_found, int inlined_probes = kInlinedDictionaryProbes); compiler::Node* ComputeIntegerHash(compiler::Node* key, compiler::Node* seed); @@ -282,11 +301,56 @@ class CodeStubAssembler : public compiler::CodeAssembler { Label* if_found, Variable* var_entry, Label* if_not_found); - void TryLookupProperty(compiler::Node* object, compiler::Node* map, + // Tries to check if {object} has own {unique_name} property. + void TryHasOwnProperty(compiler::Node* object, compiler::Node* map, compiler::Node* instance_type, compiler::Node* unique_name, Label* if_found, Label* if_not_found, Label* if_bailout); + // Tries to get {object}'s own {unique_name} property value. If the property + // is an accessor then it also calls a getter. If the property is a double + // field it re-wraps value in an immutable heap number. + void TryGetOwnProperty(compiler::Node* context, compiler::Node* receiver, + compiler::Node* object, compiler::Node* map, + compiler::Node* instance_type, + compiler::Node* unique_name, Label* if_found, + Variable* var_value, Label* if_not_found, + Label* if_bailout); + + void LoadPropertyFromFastObject(compiler::Node* object, compiler::Node* map, + compiler::Node* descriptors, + compiler::Node* name_index, + Variable* var_details, Variable* var_value); + + void LoadPropertyFromNameDictionary(compiler::Node* dictionary, + compiler::Node* entry, + Variable* var_details, + Variable* var_value); + + void LoadPropertyFromGlobalDictionary(compiler::Node* dictionary, + compiler::Node* entry, + Variable* var_details, + Variable* var_value, Label* if_deleted); + + // Generic property lookup generator. If the {object} is fast and + // {unique_name} property is found then the control goes to {if_found_fast} + // label and {var_meta_storage} and {var_name_index} will contain + // DescriptorArray and an index of the descriptor's name respectively. + // If the {object} is slow or global then the control goes to {if_found_dict} + // or {if_found_global} and the {var_meta_storage} and {var_name_index} will + // contain a dictionary and an index of the key field of the found entry. + // If property is not found or given lookup is not supported then + // the control goes to {if_not_found} or {if_bailout} respectively. + // + // Note: this code does not check if the global dictionary points to deleted + // entry! This has to be done by the caller. + void TryLookupProperty(compiler::Node* object, compiler::Node* map, + compiler::Node* instance_type, + compiler::Node* unique_name, Label* if_found_fast, + Label* if_found_dict, Label* if_found_global, + Variable* var_meta_storage, Variable* var_name_index, + Label* if_not_found, Label* if_bailout); + void TryLookupElement(compiler::Node* object, compiler::Node* map, compiler::Node* instance_type, compiler::Node* index, Label* if_found, Label* if_not_found, diff --git a/src/code-stubs.cc b/src/code-stubs.cc index 705701d3d8..ae3adb7b6f 100644 --- a/src/code-stubs.cc +++ b/src/code-stubs.cc @@ -4343,7 +4343,7 @@ compiler::Node* HasPropertyStub::Generate(CodeStubAssembler* assembler, assembler->Bind(&loop); { Label next_proto(assembler); - assembler->TryLookupProperty(var_object.value(), var_map.value(), + assembler->TryHasOwnProperty(var_object.value(), var_map.value(), var_instance_type.value(), key, &return_true, &next_proto, &call_runtime); assembler->Bind(&next_proto); diff --git a/src/objects-inl.h b/src/objects-inl.h index fea3019945..d972666f4f 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -7424,9 +7424,9 @@ void BaseDictionaryShape::SetEntry(Dictionary* dict, int entry, int index = dict->EntryToIndex(entry); DisallowHeapAllocation no_gc; WriteBarrierMode mode = dict->GetWriteBarrierMode(no_gc); - dict->set(index, *key, mode); - dict->set(index + 1, *value, mode); - dict->set(index + 2, details.AsSmi()); + dict->set(index + Dictionary::kEntryKeyIndex, *key, mode); + dict->set(index + Dictionary::kEntryValueIndex, *value, mode); + dict->set(index + Dictionary::kEntryDetailsIndex, details.AsSmi()); } @@ -7440,8 +7440,8 @@ void GlobalDictionaryShape::SetEntry(Dictionary* dict, int entry, int index = dict->EntryToIndex(entry); DisallowHeapAllocation no_gc; WriteBarrierMode mode = dict->GetWriteBarrierMode(no_gc); - dict->set(index, *key, mode); - dict->set(index + 1, *value, mode); + dict->set(index + Dictionary::kEntryKeyIndex, *key, mode); + dict->set(index + Dictionary::kEntryValueIndex, *value, mode); PropertyCell::cast(*value)->set_property_details(details); } diff --git a/src/objects.cc b/src/objects.cc index eca07b3193..fd2fda4ce7 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -16202,8 +16202,7 @@ int NameDictionaryBase::FindEntry(Handle key) { uint32_t count = 1; Isolate* isolate = this->GetIsolate(); while (true) { - int index = Derived::EntryToIndex(entry); - Object* element = this->get(index); + Object* element = this->KeyAt(entry); if (element->IsUndefined(isolate)) break; // Empty entry. if (*key == element) return entry; DCHECK(element->IsTheHole(isolate) || element->IsUniqueName()); @@ -16299,11 +16298,11 @@ void HashTable::Rehash(Key key) { // are placed correctly. Other elements might need to be moved. done = true; for (uint32_t current = 0; current < capacity; current++) { - Object* current_key = get(EntryToIndex(current)); + Object* current_key = KeyAt(current); if (IsKey(isolate, current_key)) { uint32_t target = EntryForProbe(key, current_key, probe, current); if (current == target) continue; - Object* target_key = get(EntryToIndex(target)); + Object* target_key = KeyAt(target); if (!IsKey(target_key) || EntryForProbe(key, target_key, probe, target) != target) { // Put the current element into the correct position. @@ -16322,8 +16321,8 @@ void HashTable::Rehash(Key key) { Object* the_hole = isolate->heap()->the_hole_value(); Object* undefined = isolate->heap()->undefined_value(); for (uint32_t current = 0; current < capacity; current++) { - if (get(EntryToIndex(current)) == the_hole) { - set(EntryToIndex(current), undefined); + if (KeyAt(current) == the_hole) { + set(EntryToIndex(current) + Derived::kEntryKeyIndex, undefined); } } SetNumberOfDeletedElements(0); diff --git a/src/objects.h b/src/objects.h index d256fc4740..76396f786c 100644 --- a/src/objects.h +++ b/src/objects.h @@ -3236,10 +3236,12 @@ class HashTable : public HashTableBase { void Rehash(Key key); // Returns the key at entry. - Object* KeyAt(int entry) { return get(EntryToIndex(entry)); } + Object* KeyAt(int entry) { return get(EntryToIndex(entry) + kEntryKeyIndex); } static const int kElementsStartIndex = kPrefixStartIndex + Shape::kPrefixSize; static const int kEntrySize = Shape::kEntrySize; + STATIC_ASSERT(kEntrySize > 0); + static const int kEntryKeyIndex = 0; static const int kElementsStartOffset = kHeaderSize + kElementsStartIndex * kPointerSize; static const int kCapacityOffset = @@ -3554,15 +3556,16 @@ class BaseDictionaryShape : public BaseShape { static inline PropertyDetails DetailsAt(Dictionary* dict, int entry) { STATIC_ASSERT(Dictionary::kEntrySize == 3); DCHECK(entry >= 0); // Not found is -1, which is not caught by get(). - return PropertyDetails( - Smi::cast(dict->get(Dictionary::EntryToIndex(entry) + 2))); + return PropertyDetails(Smi::cast(dict->get( + Dictionary::EntryToIndex(entry) + Dictionary::kEntryDetailsIndex))); } template static inline void DetailsAtPut(Dictionary* dict, int entry, PropertyDetails value) { STATIC_ASSERT(Dictionary::kEntrySize == 3); - dict->set(Dictionary::EntryToIndex(entry) + 2, value.AsSmi()); + dict->set(Dictionary::EntryToIndex(entry) + Dictionary::kEntryDetailsIndex, + value.AsSmi()); } template @@ -3584,6 +3587,8 @@ class NameDictionaryShape : public BaseDictionaryShape > { static inline Handle AsHandle(Isolate* isolate, Handle key); static const int kPrefixSize = 2; static const int kEntrySize = 3; + static const int kEntryValueIndex = 1; + static const int kEntryDetailsIndex = 2; static const bool kIsEnumerable = true; }; @@ -3598,6 +3603,9 @@ class NameDictionary inline static Handle DoGenerateNewEnumerationIndices( Handle dictionary); + + static const int kEntryValueIndex = 1; + static const int kEntryDetailsIndex = 2; }; @@ -3625,6 +3633,8 @@ class GlobalDictionary : public NameDictionaryBase { public: DECLARE_CAST(GlobalDictionary) + + static const int kEntryValueIndex = 1; }; @@ -3698,6 +3708,9 @@ class SeededNumberDictionary // requires_slow_elements returns false. inline uint32_t max_number_key(); + static const int kEntryValueIndex = 1; + static const int kEntryDetailsIndex = 2; + // Bit masks. static const int kRequiresSlowElementsMask = 1; static const int kRequiresSlowElementsTagSize = 1; @@ -3728,6 +3741,9 @@ class UnseededNumberDictionary Handle dictionary, uint32_t key, Handle value); + + static const int kEntryValueIndex = 1; + static const int kEntryDetailsIndex = 2; }; diff --git a/test/cctest/test-code-stub-assembler.cc b/test/cctest/test-code-stub-assembler.cc index 539a0fd13c..2d9b666b6d 100644 --- a/test/cctest/test-code-stub-assembler.cc +++ b/test/cctest/test-code-stub-assembler.cc @@ -232,15 +232,15 @@ void TestNameDictionaryLookup() { Label passed(&m), failed(&m); Label if_found(&m), if_not_found(&m); - Variable var_entry(&m, MachineRepresentation::kWord32); + Variable var_name_index(&m, MachineRepresentation::kWord32); m.NameDictionaryLookup(dictionary, unique_name, &if_found, - &var_entry, &if_not_found); + &var_name_index, &if_not_found); m.Bind(&if_found); m.GotoUnless( m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))), &failed); - m.Branch(m.Word32Equal(m.SmiToWord32(expected_arg), var_entry.value()), + m.Branch(m.Word32Equal(m.SmiToWord32(expected_arg), var_name_index.value()), &passed, &failed); m.Bind(&if_not_found); @@ -284,10 +284,12 @@ void TestNameDictionaryLookup() { for (size_t i = 0; i < arraysize(keys); i++) { int entry = dictionary->FindEntry(keys[i]); + int name_index = + Dictionary::EntryToIndex(entry) + Dictionary::kEntryKeyIndex; CHECK_NE(Dictionary::kNotFound, entry); - Handle expected_entry(Smi::FromInt(entry), isolate); - ft.CheckTrue(dictionary, keys[i], expect_found, expected_entry); + Handle expected_name_index(Smi::FromInt(name_index), isolate); + ft.CheckTrue(dictionary, keys[i], expect_found, expected_name_index); } Handle non_existing_keys[] = { @@ -418,15 +420,46 @@ namespace { void AddProperties(Handle object, Handle names[], size_t count) { - Handle value(Smi::FromInt(42), object->GetIsolate()); + Isolate* isolate = object->GetIsolate(); for (size_t i = 0; i < count; i++) { + Handle value(Smi::FromInt(static_cast(42 + i)), isolate); JSObject::AddProperty(object, names[i], value, NONE); } } +Handle CreateAccessorPair(FunctionTester* ft, + const char* getter_body, + const char* setter_body) { + Handle pair = ft->isolate->factory()->NewAccessorPair(); + if (getter_body) { + pair->set_getter(*ft->NewFunction(getter_body)); + } + if (setter_body) { + pair->set_setter(*ft->NewFunction(setter_body)); + } + return pair; +} + +void AddProperties(Handle object, Handle names[], + size_t names_count, Handle values[], + size_t values_count, int seed = 0) { + Isolate* isolate = object->GetIsolate(); + for (size_t i = 0; i < names_count; i++) { + Handle value = values[(seed + i) % values_count]; + if (value->IsAccessorPair()) { + Handle pair = Handle::cast(value); + Handle getter(pair->getter(), isolate); + Handle setter(pair->setter(), isolate); + JSObject::DefineAccessor(object, names[i], getter, setter, NONE).Check(); + } else { + JSObject::AddProperty(object, names[i], value, NONE); + } + } +} + } // namespace -TEST(TryLookupProperty) { +TEST(TryHasOwnProperty) { typedef CodeStubAssembler::Label Label; Isolate* isolate(CcTest::InitIsolateOnce()); @@ -445,7 +478,7 @@ TEST(TryLookupProperty) { Node* map = m.LoadMap(object); Node* instance_type = m.LoadMapInstanceType(map); - m.TryLookupProperty(object, map, instance_type, unique_name, &if_found, + m.TryHasOwnProperty(object, map, instance_type, unique_name, &if_found, &if_not_found, &if_bailout); m.Bind(&if_found); @@ -477,6 +510,10 @@ TEST(TryLookupProperty) { Handle expect_bailout(Smi::FromInt(kBailout), isolate); Factory* factory = isolate->factory(); + + Handle deleted_property_name = + factory->InternalizeUtf8String("deleted"); + Handle names[] = { factory->InternalizeUtf8String("a"), factory->InternalizeUtf8String("bb"), @@ -492,25 +529,59 @@ TEST(TryLookupProperty) { std::vector> objects; { - Handle function = factory->NewFunction(factory->empty_string()); - Handle object = factory->NewJSObject(function); + // Fast object, no inobject properties. + int inobject_properties = 0; + Handle map = Map::Create(isolate, inobject_properties); + Handle object = factory->NewJSObjectFromMap(map); AddProperties(object, names, arraysize(names)); CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type()); + CHECK_EQ(inobject_properties, object->map()->GetInObjectProperties()); CHECK(!object->map()->is_dictionary_map()); objects.push_back(object); } { + // Fast object, all inobject properties. + int inobject_properties = arraysize(names) * 2; + Handle map = Map::Create(isolate, inobject_properties); + Handle object = factory->NewJSObjectFromMap(map); + AddProperties(object, names, arraysize(names)); + CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type()); + CHECK_EQ(inobject_properties, object->map()->GetInObjectProperties()); + CHECK(!object->map()->is_dictionary_map()); + objects.push_back(object); + } + + { + // Fast object, half inobject properties. + int inobject_properties = arraysize(names) / 2; + Handle map = Map::Create(isolate, inobject_properties); + Handle object = factory->NewJSObjectFromMap(map); + AddProperties(object, names, arraysize(names)); + CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type()); + CHECK_EQ(inobject_properties, object->map()->GetInObjectProperties()); + CHECK(!object->map()->is_dictionary_map()); + objects.push_back(object); + } + + { + // Dictionary mode object. Handle function = factory->NewFunction(factory->empty_string()); Handle object = factory->NewJSObject(function); AddProperties(object, names, arraysize(names)); JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0, "test"); + + JSObject::AddProperty(object, deleted_property_name, object, NONE); + CHECK(JSObject::DeleteProperty(object, deleted_property_name, SLOPPY) + .FromJust()); + CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type()); CHECK(object->map()->is_dictionary_map()); objects.push_back(object); } { + // Global object. Handle function = factory->NewFunction(factory->empty_string()); JSFunction::EnsureHasInitialMap(function); function->initial_map()->set_instance_type(JS_GLOBAL_OBJECT_TYPE); @@ -518,6 +589,11 @@ TEST(TryLookupProperty) { function->initial_map()->set_dictionary_map(true); Handle object = factory->NewJSGlobalObject(function); AddProperties(object, names, arraysize(names)); + + JSObject::AddProperty(object, deleted_property_name, object, NONE); + CHECK(JSObject::DeleteProperty(object, deleted_property_name, SLOPPY) + .FromJust()); + CHECK_EQ(JS_GLOBAL_OBJECT_TYPE, object->map()->instance_type()); CHECK(object->map()->is_dictionary_map()); objects.push_back(object); @@ -535,17 +611,20 @@ TEST(TryLookupProperty) { { Handle non_existing_names[] = { + factory->NewSymbol(), factory->InternalizeUtf8String("ne_a"), factory->InternalizeUtf8String("ne_bb"), + factory->NewPrivateSymbol(), factory->InternalizeUtf8String("ne_ccc"), factory->InternalizeUtf8String("ne_dddd"), + deleted_property_name, }; for (Handle object : objects) { for (size_t key_index = 0; key_index < arraysize(non_existing_names); key_index++) { - Handle key = non_existing_names[key_index]; - CHECK(!JSReceiver::HasProperty(object, key).FromJust()); - ft.CheckTrue(object, key, expect_not_found); + Handle name = non_existing_names[key_index]; + CHECK(!JSReceiver::HasProperty(object, name).FromJust()); + ft.CheckTrue(object, name, expect_not_found); } } } @@ -564,6 +643,215 @@ TEST(TryLookupProperty) { } } +TEST(TryGetOwnProperty) { + typedef CodeStubAssembler::Label Label; + typedef CodeStubAssembler::Variable Variable; + Isolate* isolate(CcTest::InitIsolateOnce()); + Factory* factory = isolate->factory(); + + const int kNumParams = 2; + CodeStubAssemblerTester m(isolate, kNumParams); + + Handle not_found_symbol = factory->NewSymbol(); + Handle bailout_symbol = factory->NewSymbol(); + { + Node* object = m.Parameter(0); + Node* unique_name = m.Parameter(1); + Node* context = m.Parameter(kNumParams + 2); + + Variable var_value(&m, MachineRepresentation::kTagged); + Label if_found(&m), if_not_found(&m), if_bailout(&m); + + Node* map = m.LoadMap(object); + Node* instance_type = m.LoadMapInstanceType(map); + + m.TryGetOwnProperty(context, object, object, map, instance_type, + unique_name, &if_found, &var_value, &if_not_found, + &if_bailout); + + m.Bind(&if_found); + m.Return(var_value.value()); + + m.Bind(&if_not_found); + m.Return(m.HeapConstant(not_found_symbol)); + + m.Bind(&if_bailout); + m.Return(m.HeapConstant(bailout_symbol)); + } + + Handle code = m.GenerateCode(); + FunctionTester ft(code, kNumParams); + + Handle deleted_property_name = + factory->InternalizeUtf8String("deleted"); + + Handle names[] = { + factory->InternalizeUtf8String("bb"), + factory->NewSymbol(), + factory->InternalizeUtf8String("a"), + factory->InternalizeUtf8String("ccc"), + factory->InternalizeUtf8String("esajefe"), + factory->NewPrivateSymbol(), + factory->InternalizeUtf8String("eeeee"), + factory->InternalizeUtf8String("p1"), + factory->InternalizeUtf8String("acshw23e"), + factory->InternalizeUtf8String(""), + factory->InternalizeUtf8String("dddd"), + factory->NewPrivateSymbol(), + factory->InternalizeUtf8String("name"), + factory->InternalizeUtf8String("p2"), + factory->InternalizeUtf8String("p3"), + factory->InternalizeUtf8String("p4"), + factory->NewPrivateSymbol(), + }; + Handle values[] = { + factory->NewFunction(factory->empty_string()), + factory->NewSymbol(), + factory->InternalizeUtf8String("a"), + CreateAccessorPair(&ft, "() => 188;", "() => 199;"), + factory->NewFunction(factory->InternalizeUtf8String("bb")), + factory->InternalizeUtf8String("ccc"), + CreateAccessorPair(&ft, "() => 88;", nullptr), + handle(Smi::FromInt(1), isolate), + factory->InternalizeUtf8String(""), + CreateAccessorPair(&ft, nullptr, "() => 99;"), + factory->NewHeapNumber(4.2), + handle(Smi::FromInt(153), isolate), + factory->NewJSObject(factory->NewFunction(factory->empty_string())), + factory->NewPrivateSymbol(), + }; + STATIC_ASSERT(arraysize(values) < arraysize(names)); + + base::RandomNumberGenerator rand_gen(FLAG_random_seed); + + std::vector> objects; + + { + // Fast object, no inobject properties. + int inobject_properties = 0; + Handle map = Map::Create(isolate, inobject_properties); + Handle object = factory->NewJSObjectFromMap(map); + AddProperties(object, names, arraysize(names), values, arraysize(values), + rand_gen.NextInt()); + CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type()); + CHECK_EQ(inobject_properties, object->map()->GetInObjectProperties()); + CHECK(!object->map()->is_dictionary_map()); + objects.push_back(object); + } + + { + // Fast object, all inobject properties. + int inobject_properties = arraysize(names) * 2; + Handle map = Map::Create(isolate, inobject_properties); + Handle object = factory->NewJSObjectFromMap(map); + AddProperties(object, names, arraysize(names), values, arraysize(values), + rand_gen.NextInt()); + CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type()); + CHECK_EQ(inobject_properties, object->map()->GetInObjectProperties()); + CHECK(!object->map()->is_dictionary_map()); + objects.push_back(object); + } + + { + // Fast object, half inobject properties. + int inobject_properties = arraysize(names) / 2; + Handle map = Map::Create(isolate, inobject_properties); + Handle object = factory->NewJSObjectFromMap(map); + AddProperties(object, names, arraysize(names), values, arraysize(values), + rand_gen.NextInt()); + CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type()); + CHECK_EQ(inobject_properties, object->map()->GetInObjectProperties()); + CHECK(!object->map()->is_dictionary_map()); + objects.push_back(object); + } + + { + // Dictionary mode object. + Handle function = factory->NewFunction(factory->empty_string()); + Handle object = factory->NewJSObject(function); + AddProperties(object, names, arraysize(names), values, arraysize(values), + rand_gen.NextInt()); + JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0, "test"); + + JSObject::AddProperty(object, deleted_property_name, object, NONE); + CHECK(JSObject::DeleteProperty(object, deleted_property_name, SLOPPY) + .FromJust()); + + CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type()); + CHECK(object->map()->is_dictionary_map()); + objects.push_back(object); + } + + { + // Global object. + Handle object = isolate->global_object(); + AddProperties(object, names, arraysize(names), values, arraysize(values), + rand_gen.NextInt()); + + JSObject::AddProperty(object, deleted_property_name, object, NONE); + CHECK(JSObject::DeleteProperty(object, deleted_property_name, SLOPPY) + .FromJust()); + + CHECK_EQ(JS_GLOBAL_OBJECT_TYPE, object->map()->instance_type()); + CHECK(object->map()->is_dictionary_map()); + objects.push_back(object); + } + + // TODO(ishell): test proxy and interceptors when they are supported. + + { + for (Handle object : objects) { + for (size_t name_index = 0; name_index < arraysize(names); name_index++) { + Handle name = names[name_index]; + Handle expected_value = + JSReceiver::GetProperty(object, name).ToHandleChecked(); + Handle value = ft.Call(object, name).ToHandleChecked(); + CHECK(expected_value->SameValue(*value)); + } + } + } + + { + Handle non_existing_names[] = { + factory->NewSymbol(), + factory->InternalizeUtf8String("ne_a"), + factory->InternalizeUtf8String("ne_bb"), + factory->NewPrivateSymbol(), + factory->InternalizeUtf8String("ne_ccc"), + factory->InternalizeUtf8String("ne_dddd"), + deleted_property_name, + }; + for (Handle object : objects) { + for (size_t key_index = 0; key_index < arraysize(non_existing_names); + key_index++) { + Handle name = non_existing_names[key_index]; + Handle expected_value = + JSReceiver::GetProperty(object, name).ToHandleChecked(); + CHECK(expected_value->IsUndefined(isolate)); + Handle value = ft.Call(object, name).ToHandleChecked(); + CHECK_EQ(*not_found_symbol, *value); + } + } + } + + { + Handle function = factory->NewFunction(factory->empty_string()); + Handle object = factory->NewJSProxy(function, objects[0]); + CHECK_EQ(JS_PROXY_TYPE, object->map()->instance_type()); + Handle value = ft.Call(object, names[0]).ToHandleChecked(); + // Proxies are not supported yet. + CHECK_EQ(*bailout_symbol, *value); + } + + { + Handle object = isolate->global_proxy(); + CHECK_EQ(JS_GLOBAL_PROXY_TYPE, object->map()->instance_type()); + // Global proxies are not supported yet. + Handle value = ft.Call(object, names[0]).ToHandleChecked(); + CHECK_EQ(*bailout_symbol, *value); + } +} + namespace { void AddElement(Handle object, uint32_t index, Handle value, @@ -577,7 +865,7 @@ TEST(TryLookupElement) { typedef CodeStubAssembler::Label Label; Isolate* isolate(CcTest::InitIsolateOnce()); - const int kNumParams = 4; + const int kNumParams = 3; CodeStubAssemblerTester m(isolate, kNumParams); enum Result { kFound, kNotFound, kBailout };