Index: src/code-stub-assembler.cc |
diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc |
index 34b480705c0fe2633d5c5fc5457b650ec4986e5d..d746e5ece7a850f27d44f39ab760c85d933fd199 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()); |
} |
@@ -1487,6 +1502,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); |
@@ -1529,15 +1545,20 @@ void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, |
} |
template <typename Dictionary> |
+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 <typename Dictionary> |
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))); |
@@ -1549,11 +1570,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<Dictionary>(entry); |
+ var_name_index->Bind(index); |
+ |
+ Node* current = LoadFixedArrayElement(dictionary, index); |
GotoIf(WordEqual(current, unique_name), if_found); |
// See Dictionary::NextProbe(). |
@@ -1564,20 +1584,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(); |
+ |
+ Node* index = EntryToIndex<Dictionary>(entry); |
+ var_name_index->Bind(index); |
- // See Dictionary::EntryToIndex() |
- Node* index = Int32Mul(entry, Int32Constant(Dictionary::kEntrySize)); |
- Node* current = |
- LoadFixedArrayElement(dictionary, index, kElementsStartOffset); |
+ Node* current = LoadFixedArrayElement(dictionary, index); |
GotoIf(WordEqual(current, undefined), if_not_found); |
GotoIf(WordEqual(current, unique_name), if_found); |
@@ -1586,7 +1607,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); |
} |
} |
@@ -1617,9 +1638,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))); |
@@ -1652,10 +1671,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<Dictionary>(entry); |
+ Node* current = LoadFixedArrayElement(dictionary, index); |
GotoIf(WordEqual(current, undefined), if_not_found); |
Label next_probe(this); |
{ |
@@ -1687,23 +1704,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<Map::DictionaryMap>(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<Map::NumberOfOwnDescriptorsBits>(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. |
@@ -1712,6 +1738,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); |
@@ -1720,13 +1747,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); |
@@ -1734,22 +1763,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<NameDictionary>(dictionary, unique_name, if_found, |
- &var_entry, if_not_found); |
+ NameDictionaryLookup<NameDictionary>(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); |
+ |
+ // 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<GlobalDictionary>( |
+ 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<PropertyDetails::LocationField>(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<PropertyDetails::FieldIndexField>(details); |
+ Node* representation = |
+ BitFieldDecode<PropertyDetails::RepresentationField>(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; |
- NameDictionaryLookup<GlobalDictionary>(dictionary, unique_name, if_found, |
- &var_entry, if_not_found); |
+ 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<PropertyDetails::KindField>(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); |
+ } |
} |
} |