[stubs] Consolidate TryToName implementation

This extends TryToName by HeapNumber-to-intptr support and cached array
index retrieval from non-internalized strings, and uses it in the
KeyedLoadIC_Generic stub.

Bonus: avoid needless movsxlq on x64 in LoadFixed{,Double}ArrayElement
helpers by introducing INTPTR_PARAMETER mode.

Review-Url: https://codereview.chromium.org/2277363002
Cr-Commit-Position: refs/heads/master@{#39217}
This commit is contained in:
jkummerow 2016-09-06 09:17:08 -07:00 committed by Commit bot
parent b28b7e1328
commit 71dfcbacc2
6 changed files with 160 additions and 142 deletions

View File

@ -35,7 +35,7 @@ void Builtins::Generate_ObjectHasOwnProperty(CodeStubAssembler* assembler) {
Node* map = assembler->LoadMap(object); Node* map = assembler->LoadMap(object);
Node* instance_type = assembler->LoadMapInstanceType(map); Node* instance_type = assembler->LoadMapInstanceType(map);
Variable var_index(assembler, MachineRepresentation::kWord32); Variable var_index(assembler, MachineType::PointerRepresentation());
Label keyisindex(assembler), if_iskeyunique(assembler); Label keyisindex(assembler), if_iskeyunique(assembler);
assembler->TryToName(key, &keyisindex, &var_index, &if_iskeyunique, assembler->TryToName(key, &keyisindex, &var_index, &if_iskeyunique,

View File

@ -2255,45 +2255,42 @@ void CodeStubAssembler::Use(Label* label) {
void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex,
Variable* var_index, Label* if_keyisunique, Variable* var_index, Label* if_keyisunique,
Label* if_bailout) { Label* if_bailout) {
DCHECK_EQ(MachineRepresentation::kWord32, var_index->rep()); DCHECK_EQ(MachineType::PointerRepresentation(), var_index->rep());
Comment("TryToName"); Comment("TryToName");
Label if_keyissmi(this), if_keyisnotsmi(this); Label if_hascachedindex(this), if_keyisnotindex(this);
Branch(WordIsSmi(key), &if_keyissmi, &if_keyisnotsmi); // Handle Smi and HeapNumber keys.
Bind(&if_keyissmi); var_index->Bind(TryToIntptr(key, &if_keyisnotindex));
{
// Negative smi keys are named properties. Handle in the runtime.
GotoUnless(WordIsPositiveSmi(key), if_bailout);
var_index->Bind(SmiToWord32(key));
Goto(if_keyisindex); Goto(if_keyisindex);
}
Bind(&if_keyisnotsmi);
Bind(&if_keyisnotindex);
Node* key_instance_type = LoadInstanceType(key); Node* key_instance_type = LoadInstanceType(key);
// Symbols are unique. // Symbols are unique.
GotoIf(Word32Equal(key_instance_type, Int32Constant(SYMBOL_TYPE)), GotoIf(Word32Equal(key_instance_type, Int32Constant(SYMBOL_TYPE)),
if_keyisunique); if_keyisunique);
// Miss if |key| is not a String.
Label if_keyisinternalized(this); STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE);
Node* bits = GotoIf(
WordAnd(key_instance_type, Int32GreaterThan(key_instance_type, Int32Constant(FIRST_NONSTRING_TYPE)),
Int32Constant(kIsNotStringMask | kIsNotInternalizedMask)); if_bailout);
Branch(Word32Equal(bits, Int32Constant(kStringTag | kInternalizedTag)), // |key| is a String. Check if it has a cached array index.
&if_keyisinternalized, if_bailout);
Bind(&if_keyisinternalized);
// Check whether the key is an array index passed in as string. Handle
// uniform with smi keys if so.
// TODO(verwaest): Also support non-internalized strings.
Node* hash = LoadNameHashField(key); Node* hash = LoadNameHashField(key);
Node* bit = Word32And(hash, Int32Constant(Name::kIsNotArrayIndexMask)); Node* contains_index =
GotoIf(Word32NotEqual(bit, Int32Constant(0)), if_keyisunique); Word32And(hash, Int32Constant(Name::kContainsCachedArrayIndexMask));
// Key is an index. Check if it is small enough to be encoded in the GotoIf(Word32Equal(contains_index, Int32Constant(0)), &if_hascachedindex);
// hash_field. Handle too big array index in runtime. // No cached array index. If the string knows that it contains an index,
bit = Word32And(hash, Int32Constant(Name::kContainsCachedArrayIndexMask)); // then it must be an uncacheable index. Handle this case in the runtime.
GotoIf(Word32NotEqual(bit, Int32Constant(0)), if_bailout); Node* not_an_index =
Word32And(hash, Int32Constant(Name::kIsNotArrayIndexMask));
GotoIf(Word32Equal(not_an_index, Int32Constant(0)), if_bailout);
// Finally, check if |key| is internalized.
STATIC_ASSERT(kNotInternalizedTag != 0);
Node* not_internalized =
Word32And(key_instance_type, Int32Constant(kIsNotInternalizedMask));
GotoIf(Word32NotEqual(not_internalized, Int32Constant(0)), if_bailout);
Goto(if_keyisunique);
Bind(&if_hascachedindex);
var_index->Bind(BitFieldDecode<Name::ArrayIndexValueBits>(hash)); var_index->Bind(BitFieldDecode<Name::ArrayIndexValueBits>(hash));
Goto(if_keyisindex); Goto(if_keyisindex);
} }
@ -2387,7 +2384,8 @@ Node* CodeStubAssembler::ComputeIntegerHash(Node* key, Node* seed) {
} }
template <typename Dictionary> template <typename Dictionary>
void CodeStubAssembler::NumberDictionaryLookup(Node* dictionary, Node* key, void CodeStubAssembler::NumberDictionaryLookup(Node* dictionary,
Node* intptr_index,
Label* if_found, Label* if_found,
Variable* var_entry, Variable* var_entry,
Label* if_not_found) { Label* if_not_found) {
@ -2404,8 +2402,8 @@ void CodeStubAssembler::NumberDictionaryLookup(Node* dictionary, Node* key,
} else { } else {
seed = Int32Constant(kZeroHashSeed); seed = Int32Constant(kZeroHashSeed);
} }
Node* hash = ComputeIntegerHash(key, seed); Node* hash = ComputeIntegerHash(intptr_index, seed);
Node* key_as_float64 = ChangeUint32ToFloat64(key); Node* key_as_float64 = RoundIntPtrToFloat64(intptr_index);
// See Dictionary::FirstProbe(). // See Dictionary::FirstProbe().
Node* count = Int32Constant(0); Node* count = Int32Constant(0);
@ -2434,8 +2432,8 @@ void CodeStubAssembler::NumberDictionaryLookup(Node* dictionary, Node* key,
Branch(WordIsSmi(current), &if_currentissmi, &if_currentisnotsmi); Branch(WordIsSmi(current), &if_currentissmi, &if_currentisnotsmi);
Bind(&if_currentissmi); Bind(&if_currentissmi);
{ {
Node* current_value = SmiToWord32(current); Node* current_value = SmiUntag(current);
Branch(Word32Equal(current_value, key), if_found, &next_probe); Branch(WordEqual(current_value, intptr_index), if_found, &next_probe);
} }
Bind(&if_currentisnotsmi); Bind(&if_currentisnotsmi);
{ {
@ -2815,8 +2813,9 @@ void CodeStubAssembler::TryGetOwnProperty(
} }
void CodeStubAssembler::TryLookupElement(Node* object, Node* map, void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
Node* instance_type, Node* index, Node* instance_type,
Label* if_found, Label* if_not_found, Node* intptr_index, Label* if_found,
Label* if_not_found,
Label* if_bailout) { Label* if_bailout) {
// Handle special objects in runtime. // Handle special objects in runtime.
GotoIf(Int32LessThanOrEqual(instance_type, GotoIf(Int32LessThanOrEqual(instance_type,
@ -2828,7 +2827,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
// TODO(verwaest): Support other elements kinds as well. // TODO(verwaest): Support other elements kinds as well.
Label if_isobjectorsmi(this), if_isdouble(this), if_isdictionary(this), Label if_isobjectorsmi(this), if_isdouble(this), if_isdictionary(this),
if_isfaststringwrapper(this), if_isslowstringwrapper(this); if_isfaststringwrapper(this), if_isslowstringwrapper(this), if_oob(this);
// clang-format off // clang-format off
int32_t values[] = { int32_t values[] = {
// Handled by {if_isobjectorsmi}. // Handled by {if_isobjectorsmi}.
@ -2863,9 +2862,10 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
Node* elements = LoadElements(object); Node* elements = LoadElements(object);
Node* length = LoadAndUntagFixedArrayBaseLength(elements); Node* length = LoadAndUntagFixedArrayBaseLength(elements);
GotoUnless(Uint32LessThan(index, length), if_not_found); GotoUnless(UintPtrLessThan(intptr_index, length), &if_oob);
Node* element = LoadFixedArrayElement(elements, index); Node* element =
LoadFixedArrayElement(elements, intptr_index, 0, INTPTR_PARAMETERS);
Node* the_hole = TheHoleConstant(); Node* the_hole = TheHoleConstant();
Branch(WordEqual(element, the_hole), if_not_found, if_found); Branch(WordEqual(element, the_hole), if_not_found, if_found);
} }
@ -2874,17 +2874,17 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
Node* elements = LoadElements(object); Node* elements = LoadElements(object);
Node* length = LoadAndUntagFixedArrayBaseLength(elements); Node* length = LoadAndUntagFixedArrayBaseLength(elements);
GotoUnless(Uint32LessThan(index, length), if_not_found); GotoUnless(UintPtrLessThan(intptr_index, length), &if_oob);
if (kPointerSize == kDoubleSize) { if (kPointerSize == kDoubleSize) {
Node* element = Node* element = LoadFixedDoubleArrayElement(
LoadFixedDoubleArrayElement(elements, index, MachineType::Uint64()); elements, intptr_index, MachineType::Uint64(), 0, INTPTR_PARAMETERS);
Node* the_hole = Int64Constant(kHoleNanInt64); Node* the_hole = Int64Constant(kHoleNanInt64);
Branch(Word64Equal(element, the_hole), if_not_found, if_found); Branch(Word64Equal(element, the_hole), if_not_found, if_found);
} else { } else {
Node* element_upper = Node* element_upper = LoadFixedDoubleArrayElement(
LoadFixedDoubleArrayElement(elements, index, MachineType::Uint32(), elements, intptr_index, MachineType::Uint32(),
kIeeeDoubleExponentWordOffset); kIeeeDoubleExponentWordOffset, INTPTR_PARAMETERS);
Branch(Word32Equal(element_upper, Int32Constant(kHoleNanUpper32)), Branch(Word32Equal(element_upper, Int32Constant(kHoleNanUpper32)),
if_not_found, if_found); if_not_found, if_found);
} }
@ -2893,8 +2893,8 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
{ {
Variable var_entry(this, MachineRepresentation::kWord32); Variable var_entry(this, MachineRepresentation::kWord32);
Node* elements = LoadElements(object); Node* elements = LoadElements(object);
NumberDictionaryLookup<SeededNumberDictionary>(elements, index, if_found, NumberDictionaryLookup<SeededNumberDictionary>(
&var_entry, if_not_found); elements, intptr_index, if_found, &var_entry, if_not_found);
} }
Bind(&if_isfaststringwrapper); Bind(&if_isfaststringwrapper);
{ {
@ -2903,7 +2903,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
Assert(Int32LessThan(LoadInstanceType(string), Assert(Int32LessThan(LoadInstanceType(string),
Int32Constant(FIRST_NONSTRING_TYPE))); Int32Constant(FIRST_NONSTRING_TYPE)));
Node* length = LoadStringLength(string); Node* length = LoadStringLength(string);
GotoIf(Uint32LessThan(index, SmiToWord32(length)), if_found); GotoIf(UintPtrLessThan(intptr_index, SmiUntag(length)), if_found);
Goto(&if_isobjectorsmi); Goto(&if_isobjectorsmi);
} }
Bind(&if_isslowstringwrapper); Bind(&if_isslowstringwrapper);
@ -2913,9 +2913,16 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
Assert(Int32LessThan(LoadInstanceType(string), Assert(Int32LessThan(LoadInstanceType(string),
Int32Constant(FIRST_NONSTRING_TYPE))); Int32Constant(FIRST_NONSTRING_TYPE)));
Node* length = LoadStringLength(string); Node* length = LoadStringLength(string);
GotoIf(Uint32LessThan(index, SmiToWord32(length)), if_found); GotoIf(UintPtrLessThan(intptr_index, SmiUntag(length)), if_found);
Goto(&if_isdictionary); Goto(&if_isdictionary);
} }
Bind(&if_oob);
{
// Positive OOB indices mean "not found", negative indices must be
// converted to property names.
GotoIf(IntPtrLessThan(intptr_index, IntPtrConstant(0)), if_bailout);
Goto(if_not_found);
}
} }
// Instantiate template methods to workaround GCC compilation issue. // Instantiate template methods to workaround GCC compilation issue.
@ -2945,7 +2952,7 @@ void CodeStubAssembler::TryPrototypeChainLookup(
Bind(&if_objectisreceiver); Bind(&if_objectisreceiver);
} }
Variable var_index(this, MachineRepresentation::kWord32); Variable var_index(this, MachineType::PointerRepresentation());
Label if_keyisindex(this), if_iskeyunique(this); Label if_keyisindex(this), if_iskeyunique(this);
TryToName(key, &if_keyisindex, &var_index, &if_iskeyunique, if_bailout); TryToName(key, &if_keyisindex, &var_index, &if_iskeyunique, if_bailout);
@ -3177,15 +3184,19 @@ compiler::Node* CodeStubAssembler::ElementOffsetFromIndex(Node* index_node,
int element_size_shift = is_double ? kDoubleSizeLog2 : kPointerSizeLog2; int element_size_shift = is_double ? kDoubleSizeLog2 : kPointerSizeLog2;
int element_size = 1 << element_size_shift; int element_size = 1 << element_size_shift;
int const kSmiShiftBits = kSmiShiftSize + kSmiTagSize; int const kSmiShiftBits = kSmiShiftSize + kSmiTagSize;
int32_t index = 0; intptr_t index = 0;
bool constant_index = false; bool constant_index = false;
if (mode == SMI_PARAMETERS) { if (mode == SMI_PARAMETERS) {
element_size_shift -= kSmiShiftBits; element_size_shift -= kSmiShiftBits;
intptr_t temp = 0; constant_index = ToIntPtrConstant(index_node, index);
constant_index = ToIntPtrConstant(index_node, temp); index = index >> kSmiShiftBits;
index = temp >> kSmiShiftBits; } else if (mode == INTEGER_PARAMETERS) {
int32_t temp = 0;
constant_index = ToInt32Constant(index_node, temp);
index = static_cast<intptr_t>(temp);
} else { } else {
constant_index = ToInt32Constant(index_node, index); DCHECK(mode == INTPTR_PARAMETERS);
constant_index = ToIntPtrConstant(index_node, index);
} }
if (constant_index) { if (constant_index) {
return IntPtrConstant(base_size + element_size * index); return IntPtrConstant(base_size + element_size * index);
@ -3481,7 +3492,7 @@ Node* CodeStubAssembler::TryToIntptr(Node* key, Label* miss) {
void CodeStubAssembler::EmitFastElementsBoundsCheck(Node* object, void CodeStubAssembler::EmitFastElementsBoundsCheck(Node* object,
Node* elements, Node* elements,
Node* intptr_key, Node* intptr_index,
Node* is_jsarray_condition, Node* is_jsarray_condition,
Label* miss) { Label* miss) {
Variable var_length(this, MachineRepresentation::kTagged); Variable var_length(this, MachineRepresentation::kTagged);
@ -3497,12 +3508,11 @@ void CodeStubAssembler::EmitFastElementsBoundsCheck(Node* object,
Goto(&length_loaded); Goto(&length_loaded);
} }
Bind(&length_loaded); Bind(&length_loaded);
GotoUnless(UintPtrLessThan(intptr_key, var_length.value()), miss); GotoUnless(UintPtrLessThan(intptr_index, var_length.value()), miss);
} }
// |key| should be untagged (int32).
void CodeStubAssembler::EmitElementLoad(Node* object, Node* elements, void CodeStubAssembler::EmitElementLoad(Node* object, Node* elements,
Node* elements_kind, Node* key, Node* elements_kind, Node* intptr_index,
Node* is_jsarray_condition, Node* is_jsarray_condition,
Label* if_hole, Label* rebox_double, Label* if_hole, Label* rebox_double,
Variable* var_double_value, Variable* var_double_value,
@ -3515,8 +3525,8 @@ void CodeStubAssembler::EmitElementLoad(Node* object, Node* elements,
IntPtrGreaterThan(elements_kind, IntPtrConstant(LAST_FAST_ELEMENTS_KIND)), IntPtrGreaterThan(elements_kind, IntPtrConstant(LAST_FAST_ELEMENTS_KIND)),
&if_nonfast); &if_nonfast);
EmitFastElementsBoundsCheck(object, elements, key, is_jsarray_condition, EmitFastElementsBoundsCheck(object, elements, intptr_index,
out_of_bounds); is_jsarray_condition, out_of_bounds);
int32_t kinds[] = {// Handled by if_fast_packed. int32_t kinds[] = {// Handled by if_fast_packed.
FAST_SMI_ELEMENTS, FAST_ELEMENTS, FAST_SMI_ELEMENTS, FAST_ELEMENTS,
// Handled by if_fast_holey. // Handled by if_fast_holey.
@ -3539,16 +3549,14 @@ void CodeStubAssembler::EmitElementLoad(Node* object, Node* elements,
Bind(&if_fast_packed); Bind(&if_fast_packed);
{ {
Comment("fast packed elements"); Comment("fast packed elements");
// TODO(jkummerow): The Load*Element helpers add movsxlq instructions Return(LoadFixedArrayElement(elements, intptr_index, 0, INTPTR_PARAMETERS));
// on x64 which we don't need here, because |key| is an IntPtr already.
// Do something about that.
Return(LoadFixedArrayElement(elements, key));
} }
Bind(&if_fast_holey); Bind(&if_fast_holey);
{ {
Comment("fast holey elements"); Comment("fast holey elements");
Node* element = LoadFixedArrayElement(elements, key); Node* element =
LoadFixedArrayElement(elements, intptr_index, 0, INTPTR_PARAMETERS);
GotoIf(WordEqual(element, TheHoleConstant()), if_hole); GotoIf(WordEqual(element, TheHoleConstant()), if_hole);
Return(element); Return(element);
} }
@ -3556,8 +3564,8 @@ void CodeStubAssembler::EmitElementLoad(Node* object, Node* elements,
Bind(&if_fast_double); Bind(&if_fast_double);
{ {
Comment("packed double elements"); Comment("packed double elements");
var_double_value->Bind( var_double_value->Bind(LoadFixedDoubleArrayElement(
LoadFixedDoubleArrayElement(elements, key, MachineType::Float64())); elements, intptr_index, MachineType::Float64(), 0, INTPTR_PARAMETERS));
Goto(rebox_double); Goto(rebox_double);
} }
@ -3565,18 +3573,19 @@ void CodeStubAssembler::EmitElementLoad(Node* object, Node* elements,
{ {
Comment("holey double elements"); Comment("holey double elements");
if (kPointerSize == kDoubleSize) { if (kPointerSize == kDoubleSize) {
Node* raw_element = Node* raw_element = LoadFixedDoubleArrayElement(
LoadFixedDoubleArrayElement(elements, key, MachineType::Uint64()); elements, intptr_index, MachineType::Uint64(), 0, INTPTR_PARAMETERS);
Node* the_hole = Int64Constant(kHoleNanInt64); Node* the_hole = Int64Constant(kHoleNanInt64);
GotoIf(Word64Equal(raw_element, the_hole), if_hole); GotoIf(Word64Equal(raw_element, the_hole), if_hole);
} else { } else {
Node* element_upper = LoadFixedDoubleArrayElement( Node* element_upper = LoadFixedDoubleArrayElement(
elements, key, MachineType::Uint32(), kIeeeDoubleExponentWordOffset); elements, intptr_index, MachineType::Uint32(),
kIeeeDoubleExponentWordOffset, INTPTR_PARAMETERS);
GotoIf(Word32Equal(element_upper, Int32Constant(kHoleNanUpper32)), GotoIf(Word32Equal(element_upper, Int32Constant(kHoleNanUpper32)),
if_hole); if_hole);
} }
var_double_value->Bind( var_double_value->Bind(LoadFixedDoubleArrayElement(
LoadFixedDoubleArrayElement(elements, key, MachineType::Float64())); elements, intptr_index, MachineType::Float64(), 0, INTPTR_PARAMETERS));
Goto(rebox_double); Goto(rebox_double);
} }
@ -3595,11 +3604,11 @@ void CodeStubAssembler::EmitElementLoad(Node* object, Node* elements,
Bind(&if_dictionary); Bind(&if_dictionary);
{ {
Comment("dictionary elements"); Comment("dictionary elements");
GotoIf(IntPtrLessThan(key, IntPtrConstant(0)), out_of_bounds); GotoIf(IntPtrLessThan(intptr_index, IntPtrConstant(0)), out_of_bounds);
Variable var_entry(this, MachineRepresentation::kWord32); Variable var_entry(this, MachineRepresentation::kWord32);
Label if_found(this); Label if_found(this);
NumberDictionaryLookup<SeededNumberDictionary>(elements, key, &if_found, NumberDictionaryLookup<SeededNumberDictionary>(
&var_entry, if_hole); elements, intptr_index, &if_found, &var_entry, if_hole);
Bind(&if_found); Bind(&if_found);
// Check that the value is a data property. // Check that the value is a data property.
Node* details_index = EntryToIndex<SeededNumberDictionary>( Node* details_index = EntryToIndex<SeededNumberDictionary>(
@ -3628,7 +3637,7 @@ void CodeStubAssembler::EmitElementLoad(Node* object, Node* elements,
// Bounds check. // Bounds check.
Node* length = Node* length =
SmiUntag(LoadObjectField(object, JSTypedArray::kLengthOffset)); SmiUntag(LoadObjectField(object, JSTypedArray::kLengthOffset));
GotoUnless(UintPtrLessThan(key, length), out_of_bounds); GotoUnless(UintPtrLessThan(intptr_index, length), out_of_bounds);
// Backing store = external_pointer + base_pointer. // Backing store = external_pointer + base_pointer.
Node* external_pointer = Node* external_pointer =
@ -3659,43 +3668,43 @@ void CodeStubAssembler::EmitElementLoad(Node* object, Node* elements,
Bind(&uint8_elements); Bind(&uint8_elements);
{ {
Comment("UINT8_ELEMENTS"); // Handles UINT8_CLAMPED_ELEMENTS too. Comment("UINT8_ELEMENTS"); // Handles UINT8_CLAMPED_ELEMENTS too.
Return(SmiTag(Load(MachineType::Uint8(), backing_store, key))); Return(SmiTag(Load(MachineType::Uint8(), backing_store, intptr_index)));
} }
Bind(&int8_elements); Bind(&int8_elements);
{ {
Comment("INT8_ELEMENTS"); Comment("INT8_ELEMENTS");
Return(SmiTag(Load(MachineType::Int8(), backing_store, key))); Return(SmiTag(Load(MachineType::Int8(), backing_store, intptr_index)));
} }
Bind(&uint16_elements); Bind(&uint16_elements);
{ {
Comment("UINT16_ELEMENTS"); Comment("UINT16_ELEMENTS");
Node* index = WordShl(key, IntPtrConstant(1)); Node* index = WordShl(intptr_index, IntPtrConstant(1));
Return(SmiTag(Load(MachineType::Uint16(), backing_store, index))); Return(SmiTag(Load(MachineType::Uint16(), backing_store, index)));
} }
Bind(&int16_elements); Bind(&int16_elements);
{ {
Comment("INT16_ELEMENTS"); Comment("INT16_ELEMENTS");
Node* index = WordShl(key, IntPtrConstant(1)); Node* index = WordShl(intptr_index, IntPtrConstant(1));
Return(SmiTag(Load(MachineType::Int16(), backing_store, index))); Return(SmiTag(Load(MachineType::Int16(), backing_store, index)));
} }
Bind(&uint32_elements); Bind(&uint32_elements);
{ {
Comment("UINT32_ELEMENTS"); Comment("UINT32_ELEMENTS");
Node* index = WordShl(key, IntPtrConstant(2)); Node* index = WordShl(intptr_index, IntPtrConstant(2));
Node* element = Load(MachineType::Uint32(), backing_store, index); Node* element = Load(MachineType::Uint32(), backing_store, index);
Return(ChangeUint32ToTagged(element)); Return(ChangeUint32ToTagged(element));
} }
Bind(&int32_elements); Bind(&int32_elements);
{ {
Comment("INT32_ELEMENTS"); Comment("INT32_ELEMENTS");
Node* index = WordShl(key, IntPtrConstant(2)); Node* index = WordShl(intptr_index, IntPtrConstant(2));
Node* element = Load(MachineType::Int32(), backing_store, index); Node* element = Load(MachineType::Int32(), backing_store, index);
Return(ChangeInt32ToTagged(element)); Return(ChangeInt32ToTagged(element));
} }
Bind(&float32_elements); Bind(&float32_elements);
{ {
Comment("FLOAT32_ELEMENTS"); Comment("FLOAT32_ELEMENTS");
Node* index = WordShl(key, IntPtrConstant(2)); Node* index = WordShl(intptr_index, IntPtrConstant(2));
Node* element = Load(MachineType::Float32(), backing_store, index); Node* element = Load(MachineType::Float32(), backing_store, index);
var_double_value->Bind(ChangeFloat32ToFloat64(element)); var_double_value->Bind(ChangeFloat32ToFloat64(element));
Goto(rebox_double); Goto(rebox_double);
@ -3703,7 +3712,7 @@ void CodeStubAssembler::EmitElementLoad(Node* object, Node* elements,
Bind(&float64_elements); Bind(&float64_elements);
{ {
Comment("FLOAT64_ELEMENTS"); Comment("FLOAT64_ELEMENTS");
Node* index = WordShl(key, IntPtrConstant(3)); Node* index = WordShl(intptr_index, IntPtrConstant(3));
Node* element = Load(MachineType::Float64(), backing_store, index); Node* element = Load(MachineType::Float64(), backing_store, index);
var_double_value->Bind(element); var_double_value->Bind(element);
Goto(rebox_double); Goto(rebox_double);
@ -3734,7 +3743,7 @@ void CodeStubAssembler::HandleLoadICHandlerCase(
&property); &property);
Comment("element_load"); Comment("element_load");
Node* key = TryToIntptr(p->name, miss); Node* intptr_index = TryToIntptr(p->name, miss);
Node* elements = LoadElements(p->receiver); Node* elements = LoadElements(p->receiver);
Node* is_jsarray = Node* is_jsarray =
WordAnd(handler_word, IntPtrConstant(KeyedLoadIsJsArray::kMask)); WordAnd(handler_word, IntPtrConstant(KeyedLoadIsJsArray::kMask));
@ -3742,7 +3751,7 @@ void CodeStubAssembler::HandleLoadICHandlerCase(
Node* elements_kind = BitFieldDecode<KeyedLoadElementsKind>(handler_word); Node* elements_kind = BitFieldDecode<KeyedLoadElementsKind>(handler_word);
Label if_hole(this), unimplemented_elements_kind(this); Label if_hole(this), unimplemented_elements_kind(this);
Label* out_of_bounds = miss; Label* out_of_bounds = miss;
EmitElementLoad(p->receiver, elements, elements_kind, key, EmitElementLoad(p->receiver, elements, elements_kind, intptr_index,
is_jsarray_condition, &if_hole, &rebox_double, is_jsarray_condition, &if_hole, &rebox_double,
&var_double_value, &unimplemented_elements_kind, &var_double_value, &unimplemented_elements_kind,
out_of_bounds, miss); out_of_bounds, miss);
@ -3934,9 +3943,9 @@ void CodeStubAssembler::KeyedLoadIC(const LoadICParameters* p) {
void CodeStubAssembler::KeyedLoadICGeneric(const LoadICParameters* p) { void CodeStubAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
Variable var_index(this, MachineType::PointerRepresentation()); Variable var_index(this, MachineType::PointerRepresentation());
Label if_index(this), if_key_is_not_number(this), if_index_name(this), Label if_index(this), if_unique_name(this), if_element_hole(this),
if_unique_name(this), if_element_hole(this), if_oob(this), slow(this), if_oob(this), slow(this), stub_cache_miss(this),
stub_cache_miss(this), if_property_dictionary(this); if_property_dictionary(this);
Node* receiver = p->receiver; Node* receiver = p->receiver;
GotoIf(WordIsSmi(receiver), &slow); GotoIf(WordIsSmi(receiver), &slow);
@ -3948,43 +3957,8 @@ void CodeStubAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)), Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)),
&slow); &slow);
// Check what kind of key we have.
Node* key = p->name; Node* key = p->name;
var_index.Bind(TryToIntptr(key, &if_key_is_not_number)); TryToName(key, &if_index, &var_index, &if_unique_name, &slow);
Goto(&if_index);
Node* hash = nullptr;
// TODO(jkummerow): Unify this with CodeStubAssembler::TryToName().
Bind(&if_key_is_not_number);
{
Node* key_map = LoadMap(key);
Node* key_instance_type = LoadMapInstanceType(key_map);
// Jump to the runtime if key is neither String nor Symbol.
GotoIf(Int32GreaterThan(key_instance_type,
Int32Constant(LAST_UNIQUE_NAME_TYPE)),
&slow);
// Symbols are always unique names.
GotoIf(Word32Equal(key_instance_type, Int32Constant(LAST_UNIQUE_NAME_TYPE)),
&if_unique_name);
// |key| is a String. Check if it has a cached array index.
hash = LoadNameHashField(key);
Node* contains_index =
Word32And(hash, Int32Constant(Name::kContainsCachedArrayIndexMask));
GotoIf(Word32Equal(contains_index, Int32Constant(0)), &if_index_name);
// Otherwise, jump to the runtime if the string is not internalized.
STATIC_ASSERT(kNotInternalizedTag != 0);
Node* not_internalized =
Word32And(key_instance_type, Int32Constant(kIsNotInternalizedMask));
GotoIf(Word32NotEqual(not_internalized, Int32Constant(0)), &slow);
Goto(&if_unique_name);
}
Bind(&if_index_name);
{
Comment("string key with cached array index");
var_index.Bind(BitFieldDecode<String::ArrayIndexValueBits>(hash));
Goto(&if_index);
}
Bind(&if_index); Bind(&if_index);
{ {

View File

@ -46,7 +46,7 @@ class CodeStubAssembler : public compiler::CodeAssembler {
typedef base::Flags<AllocationFlag> AllocationFlags; typedef base::Flags<AllocationFlag> AllocationFlags;
enum ParameterMode { INTEGER_PARAMETERS, SMI_PARAMETERS }; enum ParameterMode { INTEGER_PARAMETERS, SMI_PARAMETERS, INTPTR_PARAMETERS };
compiler::Node* BooleanMapConstant(); compiler::Node* BooleanMapConstant();
compiler::Node* EmptyStringConstant(); compiler::Node* EmptyStringConstant();
@ -399,9 +399,9 @@ class CodeStubAssembler : public compiler::CodeAssembler {
compiler::Node* ComputeIntegerHash(compiler::Node* key, compiler::Node* seed); compiler::Node* ComputeIntegerHash(compiler::Node* key, compiler::Node* seed);
template <typename Dictionary> template <typename Dictionary>
void NumberDictionaryLookup(compiler::Node* dictionary, compiler::Node* key, void NumberDictionaryLookup(compiler::Node* dictionary,
Label* if_found, Variable* var_entry, compiler::Node* intptr_index, Label* if_found,
Label* if_not_found); Variable* var_entry, Label* if_not_found);
// Tries to check if {object} has own {unique_name} property. // Tries to check if {object} has own {unique_name} property.
void TryHasOwnProperty(compiler::Node* object, compiler::Node* map, void TryHasOwnProperty(compiler::Node* object, compiler::Node* map,
@ -454,9 +454,9 @@ class CodeStubAssembler : public compiler::CodeAssembler {
Label* if_not_found, Label* if_bailout); Label* if_not_found, Label* if_bailout);
void TryLookupElement(compiler::Node* object, compiler::Node* map, void TryLookupElement(compiler::Node* object, compiler::Node* map,
compiler::Node* instance_type, compiler::Node* index, compiler::Node* instance_type,
Label* if_found, Label* if_not_found, compiler::Node* intptr_index, Label* if_found,
Label* if_bailout); Label* if_not_found, Label* if_bailout);
// This is a type of a lookup in holder generator function. In case of a // This is a type of a lookup in holder generator function. In case of a
// property lookup the {key} is guaranteed to be a unique name and in case of // property lookup the {key} is guaranteed to be a unique name and in case of
@ -579,7 +579,7 @@ class CodeStubAssembler : public compiler::CodeAssembler {
compiler::Node* TryToIntptr(compiler::Node* key, Label* miss); compiler::Node* TryToIntptr(compiler::Node* key, Label* miss);
void EmitFastElementsBoundsCheck(compiler::Node* object, void EmitFastElementsBoundsCheck(compiler::Node* object,
compiler::Node* elements, compiler::Node* elements,
compiler::Node* intptr_key, compiler::Node* intptr_index,
compiler::Node* is_jsarray_condition, compiler::Node* is_jsarray_condition,
Label* miss); Label* miss);
void EmitElementLoad(compiler::Node* object, compiler::Node* elements, void EmitElementLoad(compiler::Node* object, compiler::Node* elements,

View File

@ -234,6 +234,13 @@ Node* CodeAssembler::ChangeInt32ToIntPtr(Node* value) {
return value; return value;
} }
Node* CodeAssembler::RoundIntPtrToFloat64(Node* value) {
if (raw_assembler_->machine()->Is64()) {
return raw_assembler_->RoundInt64ToFloat64(value);
}
return raw_assembler_->ChangeInt32ToFloat64(value);
}
#define DEFINE_CODE_ASSEMBLER_UNARY_OP(name) \ #define DEFINE_CODE_ASSEMBLER_UNARY_OP(name) \
Node* CodeAssembler::name(Node* a) { return raw_assembler_->name(a); } Node* CodeAssembler::name(Node* a) { return raw_assembler_->name(a); }
CODE_ASSEMBLER_UNARY_OP_LIST(DEFINE_CODE_ASSEMBLER_UNARY_OP) CODE_ASSEMBLER_UNARY_OP_LIST(DEFINE_CODE_ASSEMBLER_UNARY_OP)

View File

@ -283,6 +283,10 @@ class CodeAssembler {
CODE_ASSEMBLER_UNARY_OP_LIST(DECLARE_CODE_ASSEMBLER_UNARY_OP) CODE_ASSEMBLER_UNARY_OP_LIST(DECLARE_CODE_ASSEMBLER_UNARY_OP)
#undef DECLARE_CODE_ASSEMBLER_UNARY_OP #undef DECLARE_CODE_ASSEMBLER_UNARY_OP
// Changes an intptr_t to a double, e.g. for storing an element index
// outside Smi range in a HeapNumber. Lossless on 32-bit,
// rounds on 64-bit (which doesn't affect valid element indices).
Node* RoundIntPtrToFloat64(Node* value);
// No-op on 32-bit, otherwise zero extend. // No-op on 32-bit, otherwise zero extend.
Node* ChangeUint32ToWord(Node* value); Node* ChangeUint32ToWord(Node* value);
// No-op on 32-bit, otherwise sign extend. // No-op on 32-bit, otherwise sign extend.

View File

@ -135,7 +135,7 @@ TEST(TryToName) {
Label passed(&m), failed(&m); Label passed(&m), failed(&m);
Label if_keyisindex(&m), if_keyisunique(&m), if_bailout(&m); Label if_keyisindex(&m), if_keyisunique(&m), if_bailout(&m);
Variable var_index(&m, MachineRepresentation::kWord32); Variable var_index(&m, MachineType::PointerRepresentation());
m.TryToName(key, &if_keyisindex, &var_index, &if_keyisunique, &if_bailout); m.TryToName(key, &if_keyisindex, &var_index, &if_keyisunique, &if_bailout);
@ -143,8 +143,8 @@ TEST(TryToName) {
m.GotoUnless( m.GotoUnless(
m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kKeyIsIndex))), m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kKeyIsIndex))),
&failed); &failed);
m.Branch(m.Word32Equal(m.SmiToWord32(expected_arg), var_index.value()), m.Branch(m.WordEqual(m.SmiUntag(expected_arg), var_index.value()), &passed,
&passed, &failed); &failed);
m.Bind(&if_keyisunique); m.Bind(&if_keyisunique);
m.GotoUnless( m.GotoUnless(
@ -184,9 +184,17 @@ TEST(TryToName) {
} }
{ {
// TryToName(<negative smi>) => bailout. // TryToName(<negative smi>) => if_keyisindex: smi value.
// A subsequent bounds check needs to take care of this case.
Handle<Object> key(Smi::FromInt(-1), isolate); Handle<Object> key(Smi::FromInt(-1), isolate);
ft.CheckTrue(key, expect_bailout); ft.CheckTrue(key, expect_index, key);
}
{
// TryToName(<heap number with int value>) => if_keyisindex: number.
Handle<Object> key(isolate->factory()->NewHeapNumber(153));
Handle<Object> index(Smi::FromInt(153), isolate);
ft.CheckTrue(key, expect_index, index);
} }
{ {
@ -208,6 +216,31 @@ TEST(TryToName) {
ft.CheckTrue(key, expect_index, index); ft.CheckTrue(key, expect_index, index);
} }
{
// TryToName(<internalized uncacheable number string>) => bailout
Handle<Object> key =
isolate->factory()->InternalizeUtf8String("4294967294");
ft.CheckTrue(key, expect_bailout);
}
{
// TryToName(<non-internalized number string>) => if_keyisindex: number.
Handle<String> key = isolate->factory()->NewStringFromAsciiChecked("153");
uint32_t dummy;
CHECK(key->AsArrayIndex(&dummy));
CHECK(key->HasHashCode());
CHECK(!key->IsInternalizedString());
Handle<Object> index(Smi::FromInt(153), isolate);
ft.CheckTrue(key, expect_index, index);
}
{
// TryToName(<number string without cached index>) => bailout.
Handle<String> key = isolate->factory()->NewStringFromAsciiChecked("153");
CHECK(!key->HasHashCode());
ft.CheckTrue(key, expect_bailout);
}
{ {
// TryToName(<non-internalized string>) => bailout. // TryToName(<non-internalized string>) => bailout.
Handle<Object> key = isolate->factory()->NewStringFromAsciiChecked("test"); Handle<Object> key = isolate->factory()->NewStringFromAsciiChecked("test");