From 9b4f836a2d168644d657e2d86f4d50ebe027e8b2 Mon Sep 17 00:00:00 2001 From: ishell Date: Wed, 1 Jun 2016 14:08:22 -0700 Subject: [PATCH] Revert of Extend HasProperty stub with dictionary-mode and double-elements objects support. (patchset #8 id:280001 of https://codereview.chromium.org/1995453002/ ) Reason for revert: There are crashes on Win32 and Win64 bots. Original issue's description: > Extend HasProperty stub with dictionary-mode, string wrapper and double-elements objects support. > > This CL also replaces some Branch() usages with GotoIf/GotoUnless. > > BUG=v8:2743 > LOG=Y > > Committed: https://crrev.com/24066b6df4259b302edfa1db884c479008776a7e > Cr-Commit-Position: refs/heads/master@{#36657} TBR=verwaest@chromium.org # Skipping CQ checks because original CL landed less than 1 days ago. NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=v8:2743 Review-Url: https://codereview.chromium.org/2028333002 Cr-Commit-Position: refs/heads/master@{#36659} --- src/code-stub-assembler.cc | 458 ++----- src/code-stub-assembler.h | 48 +- src/globals.h | 9 - src/objects-printer.cc | 2 +- src/objects.cc | 19 +- src/objects.h | 45 +- src/utils.cc | 7 +- test/cctest/BUILD.gn | 2 +- test/cctest/cctest.gyp | 2 +- test/cctest/compiler/function-tester.h | 56 +- .../compiler/test-code-stub-assembler.cc | 394 ++++++ test/cctest/test-code-stub-assembler.cc | 1059 ----------------- 12 files changed, 560 insertions(+), 1541 deletions(-) create mode 100644 test/cctest/compiler/test-code-stub-assembler.cc delete mode 100644 test/cctest/test-code-stub-assembler.cc diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc index fbf3feb48a..9aa67811cd 100644 --- a/src/code-stub-assembler.cc +++ b/src/code-stub-assembler.cc @@ -58,14 +58,6 @@ Node* CodeStubAssembler::UndefinedConstant() { return LoadRoot(Heap::kUndefinedValueRootIndex); } -Node* CodeStubAssembler::TheHoleConstant() { - return LoadRoot(Heap::kTheHoleValueRootIndex); -} - -Node* CodeStubAssembler::HashSeed() { - return SmiToWord32(LoadRoot(Heap::kHashSeedRootIndex)); -} - Node* CodeStubAssembler::StaleRegisterConstant() { return LoadRoot(Heap::kStaleRegisterRootIndex); } @@ -493,10 +485,6 @@ Node* CodeStubAssembler::LoadInstanceType(Node* object) { return LoadMapInstanceType(LoadMap(object)); } -Node* CodeStubAssembler::LoadProperties(Node* object) { - return LoadObjectField(object, JSObject::kPropertiesOffset); -} - Node* CodeStubAssembler::LoadElements(Node* object) { return LoadObjectField(object, JSObject::kElementsOffset); } @@ -533,35 +521,11 @@ Node* CodeStubAssembler::LoadMapPrototype(Node* map) { return LoadObjectField(map, Map::kPrototypeOffset); } -Node* CodeStubAssembler::LoadMapInstanceSize(Node* map) { - return Load(MachineType::Uint8(), map, - IntPtrConstant(Map::kInstanceSizeOffset - kHeapObjectTag)); -} - -Node* CodeStubAssembler::LoadNameHashField(Node* name) { +Node* CodeStubAssembler::LoadNameHash(Node* name) { return Load(MachineType::Uint32(), name, IntPtrConstant(Name::kHashFieldOffset - kHeapObjectTag)); } -Node* CodeStubAssembler::LoadNameHash(Node* name, Label* if_hash_not_computed) { - Node* hash_field = LoadNameHashField(name); - if (if_hash_not_computed != nullptr) { - GotoIf(WordEqual( - Word32And(hash_field, Int32Constant(Name::kHashNotComputedMask)), - Int32Constant(0)), - if_hash_not_computed); - } - return Word32Shr(hash_field, Int32Constant(Name::kHashShift)); -} - -Node* CodeStubAssembler::LoadStringLength(Node* object) { - return LoadObjectField(object, String::kLengthOffset); -} - -Node* CodeStubAssembler::LoadJSValueValue(Node* object) { - return LoadObjectField(object, JSValue::kValueOffset); -} - Node* CodeStubAssembler::AllocateUninitializedFixedArray(Node* length) { Node* header_size = IntPtrConstant(FixedArray::kHeaderSize); Node* data_size = WordShl(length, IntPtrConstant(kPointerSizeLog2)); @@ -585,14 +549,9 @@ Node* CodeStubAssembler::LoadFixedArrayElement(Node* object, Node* index_node, return Load(MachineType::AnyTagged(), object, offset); } -Node* CodeStubAssembler::LoadFixedDoubleArrayElement( - Node* object, Node* index_node, MachineType machine_type, - int additional_offset, ParameterMode parameter_mode) { - int32_t header_size = - FixedDoubleArray::kHeaderSize + additional_offset - kHeapObjectTag; - Node* offset = ElementOffsetFromIndex(index_node, FAST_HOLEY_DOUBLE_ELEMENTS, - parameter_mode, header_size); - return Load(machine_type, object, offset); +Node* CodeStubAssembler::LoadMapInstanceSize(Node* map) { + return Load(MachineType::Uint8(), map, + IntPtrConstant(Map::kInstanceSizeOffset - kHeapObjectTag)); } Node* CodeStubAssembler::LoadNativeContext(Node* context) { @@ -1434,7 +1393,7 @@ Node* CodeStubAssembler::BitFieldDecode(Node* word32, uint32_t shift, void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, Variable* var_index, Label* if_keyisunique, - Label* if_bailout) { + Label* call_runtime) { DCHECK_EQ(MachineRepresentation::kWord32, var_index->rep()); Label if_keyissmi(this), if_keyisnotsmi(this); @@ -1442,7 +1401,9 @@ void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, Bind(&if_keyissmi); { // Negative smi keys are named properties. Handle in the runtime. - GotoUnless(WordIsPositiveSmi(key), if_bailout); + Label if_keyispositive(this); + Branch(WordIsPositiveSmi(key), &if_keyispositive, call_runtime); + Bind(&if_keyispositive); var_index->Bind(SmiToWord32(key)); Goto(if_keyisindex); @@ -1451,372 +1412,125 @@ void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, Bind(&if_keyisnotsmi); Node* key_instance_type = LoadInstanceType(key); - // Symbols are unique. - GotoIf(Word32Equal(key_instance_type, Int32Constant(SYMBOL_TYPE)), - if_keyisunique); - - Label if_keyisinternalized(this); - Node* bits = - WordAnd(key_instance_type, - Int32Constant(kIsNotStringMask | kIsNotInternalizedMask)); - Branch(Word32Equal(bits, Int32Constant(kStringTag | kInternalizedTag)), - &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* bit = Word32And(hash, Int32Constant(Name::kIsNotArrayIndexMask)); - GotoIf(Word32NotEqual(bit, Int32Constant(0)), if_keyisunique); - // Key is an index. Check if it is small enough to be encoded in the - // hash_field. Handle too big array index in runtime. - bit = Word32And(hash, Int32Constant(Name::kContainsCachedArrayIndexMask)); - GotoIf(Word32NotEqual(bit, Int32Constant(0)), if_bailout); - var_index->Bind(BitFieldDecode(hash)); - Goto(if_keyisindex); -} - -template -void CodeStubAssembler::NameDictionaryLookup( - Node* dictionary, Node* unique_name, Label* if_found_, Variable* var_entry, - Label* if_not_found, int inlined_probes) { - DCHECK_EQ(MachineRepresentation::kWord32, var_entry->rep()); - - // TODO(ishell): Remove this trampoline block once crbug/615621 is fixed. - // This trampoline block is currently necessary here to generate a correct - // phi for |var_entry|. - Label if_found(this, var_entry); - - const int kElementsStartOffset = - Dictionary::kElementsStartIndex * kPointerSize; - - Node* capacity = SmiToWord32(LoadFixedArrayElement( - dictionary, Int32Constant(Dictionary::kCapacityIndex))); - Node* mask = Int32Sub(capacity, Int32Constant(1)); - Node* hash = LoadNameHash(unique_name); - - // See Dictionary::FirstProbe(). - Node* count = Int32Constant(0); - 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); - GotoIf(WordEqual(current, unique_name), &if_found); - - // See Dictionary::NextProbe(). - count = Int32Constant(i + 1); - entry = Word32And(Int32Add(entry, count), mask); - } - - Node* undefined = UndefinedConstant(); - - Variable var_count(this, MachineRepresentation::kWord32); - Variable* loop_vars[] = {&var_count, var_entry}; - Label loop(this, 2, loop_vars); - var_count.Bind(count); - var_entry->Bind(entry); - Goto(&loop); - Bind(&loop); + Label if_keyisnotsymbol(this); + Branch(Word32Equal(key_instance_type, Int32Constant(SYMBOL_TYPE)), + if_keyisunique, &if_keyisnotsymbol); + Bind(&if_keyisnotsymbol); { - Node* count = var_count.value(); - Node* entry = var_entry->value(); + Label if_keyisinternalized(this); + Node* bits = + WordAnd(key_instance_type, + Int32Constant(kIsNotStringMask | kIsNotInternalizedMask)); + Branch(Word32Equal(bits, Int32Constant(kStringTag | kInternalizedTag)), + &if_keyisinternalized, call_runtime); + Bind(&if_keyisinternalized); - // See Dictionary::EntryToIndex() - Node* index = Int32Mul(entry, Int32Constant(Dictionary::kEntrySize)); - Node* current = - LoadFixedArrayElement(dictionary, index, kElementsStartOffset); - GotoIf(WordEqual(current, undefined), if_not_found); - GotoIf(WordEqual(current, unique_name), &if_found); - - // See Dictionary::NextProbe(). - count = Int32Add(count, Int32Constant(1)); - entry = Word32And(Int32Add(entry, count), mask); - - var_count.Bind(count); - var_entry->Bind(entry); - Goto(&loop); - } - Bind(&if_found); - Goto(if_found_); -} - -// Instantiate template methods to workaround GCC compilation issue. -template void CodeStubAssembler::NameDictionaryLookup( - Node*, Node*, Label*, Variable*, Label*, int); -template void CodeStubAssembler::NameDictionaryLookup( - Node*, Node*, Label*, Variable*, Label*, int); - -Node* CodeStubAssembler::ComputeIntegerHash(Node* key, Node* seed) { - // See v8::internal::ComputeIntegerHash() - Node* hash = key; - hash = Word32Xor(hash, seed); - hash = Int32Add(Word32Xor(hash, Int32Constant(0xffffffff)), - Word32Shl(hash, Int32Constant(15))); - hash = Word32Xor(hash, Word32Shr(hash, Int32Constant(12))); - hash = Int32Add(hash, Word32Shl(hash, Int32Constant(2))); - hash = Word32Xor(hash, Word32Shr(hash, Int32Constant(4))); - hash = Int32Mul(hash, Int32Constant(2057)); - hash = Word32Xor(hash, Word32Shr(hash, Int32Constant(16))); - return Word32And(hash, Int32Constant(0x3fffffff)); -} - -template -void CodeStubAssembler::NumberDictionaryLookup(Node* dictionary, Node* key, - Label* if_found, - Variable* var_entry, - Label* if_not_found) { - DCHECK_EQ(MachineRepresentation::kWord32, var_entry->rep()); - - const int kElementsStartOffset = - Dictionary::kElementsStartIndex * kPointerSize; - - Node* capacity = SmiToWord32(LoadFixedArrayElement( - dictionary, Int32Constant(Dictionary::kCapacityIndex))); - Node* mask = Int32Sub(capacity, Int32Constant(1)); - - Node* seed; - if (Dictionary::ShapeT::UsesSeed) { - seed = HashSeed(); - } else { - seed = Int32Constant(kZeroHashSeed); - } - Node* hash = ComputeIntegerHash(key, seed); - Node* key_as_float64 = ChangeUint32ToFloat64(key); - - // See Dictionary::FirstProbe(). - Node* count = Int32Constant(0); - Node* entry = Word32And(hash, mask); - - Node* undefined = UndefinedConstant(); - Node* the_hole = TheHoleConstant(); - - Variable var_count(this, MachineRepresentation::kWord32); - Variable* loop_vars[] = {&var_count, var_entry}; - Label loop(this, 2, loop_vars); - var_count.Bind(count); - var_entry->Bind(entry); - Goto(&loop); - Bind(&loop); - { - 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); - GotoIf(WordEqual(current, undefined), if_not_found); - Label next_probe(this); - { - Label if_currentissmi(this), if_currentisnotsmi(this); - Branch(WordIsSmi(current), &if_currentissmi, &if_currentisnotsmi); - Bind(&if_currentissmi); - { - Node* current_value = SmiToWord32(current); - Branch(Word32Equal(current_value, key), if_found, &next_probe); - } - Bind(&if_currentisnotsmi); - { - GotoIf(WordEqual(current, the_hole), &next_probe); - // Current must be the Number. - Node* current_value = LoadHeapNumberValue(current); - Branch(Float64Equal(current_value, key_as_float64), if_found, - &next_probe); - } - } - - Bind(&next_probe); - // See Dictionary::NextProbe(). - count = Int32Add(count, Int32Constant(1)); - entry = Word32And(Int32Add(entry, count), mask); - - var_count.Bind(count); - var_entry->Bind(entry); - Goto(&loop); + // 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 = LoadNameHash(key); + Node* bit = + Word32And(hash, Int32Constant(internal::Name::kIsNotArrayIndexMask)); + Label if_isarrayindex(this); + Branch(Word32Equal(bit, Int32Constant(0)), &if_isarrayindex, + if_keyisunique); + Bind(&if_isarrayindex); + var_index->Bind(BitFieldDecode(hash)); + Goto(if_keyisindex); } } void CodeStubAssembler::TryLookupProperty(Node* object, Node* map, - Node* instance_type, - Node* unique_name, Label* if_found, - Label* if_not_found, - Label* if_bailout) { - 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* instance_type, Node* name, + Label* if_found, Label* if_not_found, + Label* call_runtime) { + { + Label if_objectissimple(this); + Branch(Int32LessThanOrEqual(instance_type, + Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)), + call_runtime, &if_objectissimple); + Bind(&if_objectissimple); + } + // TODO(verwaest): Perform a dictonary lookup on slow-mode receivers. 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); + Label if_isfastmap(this); + Branch(Word32Equal(bit, Int32Constant(0)), &if_isfastmap, call_runtime); Bind(&if_isfastmap); + 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. { - 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. - { - static const int32_t kMaxLinear = 210; - GotoIf(Int32GreaterThan(nof, Int32Constant(kMaxLinear)), if_bailout); - } - Node* descriptors = LoadMapDescriptors(map); + static const int32_t kMaxLinear = 210; + Label above_max(this), below_max(this); + Branch(Int32LessThanOrEqual(nof, Int32Constant(kMaxLinear)), &below_max, + call_runtime); + Bind(&below_max); + } + Node* descriptors = LoadMapDescriptors(map); - Variable var_descriptor(this, MachineRepresentation::kWord32); - Label loop(this, &var_descriptor); - var_descriptor.Bind(Int32Constant(0)); - Goto(&loop); - Bind(&loop); + Variable var_descriptor(this, MachineRepresentation::kWord32); + Label loop(this, &var_descriptor); + var_descriptor.Bind(Int32Constant(0)); + Goto(&loop); + Bind(&loop); + { + Node* index = var_descriptor.value(); + Node* offset = Int32Constant(DescriptorArray::ToKeyIndex(0)); + Node* factor = Int32Constant(DescriptorArray::kDescriptorSize); + Label if_notdone(this); + Branch(Word32Equal(index, nof), if_not_found, &if_notdone); + Bind(&if_notdone); { - Node* index = var_descriptor.value(); - Node* 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); + Label if_unequal(this); + Branch(WordEqual(current, name), if_found, &if_unequal); + Bind(&if_unequal); var_descriptor.Bind(Int32Add(index, Int32Constant(1))); Goto(&loop); } } - Bind(&if_isslowmap); - { - Variable var_entry(this, MachineRepresentation::kWord32); - Node* dictionary = LoadProperties(object); - - NameDictionaryLookup(dictionary, unique_name, if_found, - &var_entry, 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); - } } void CodeStubAssembler::TryLookupElement(Node* object, Node* map, Node* instance_type, Node* index, Label* if_found, Label* if_not_found, - Label* if_bailout) { - // Handle special objects in runtime. - GotoIf(Int32LessThanOrEqual(instance_type, - Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)), - if_bailout); + Label* call_runtime) { + { + Label if_objectissimple(this); + Branch(Int32LessThanOrEqual(instance_type, + Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)), + call_runtime, &if_objectissimple); + Bind(&if_objectissimple); + } Node* bit_field2 = LoadMapBitField2(map); Node* elements_kind = BitFieldDecode(bit_field2); // TODO(verwaest): Support other elements kinds as well. - Label if_isobjectorsmi(this), if_isdouble(this), if_isdictionary(this), - if_isfaststringwrapper(this), if_isslowstringwrapper(this); - // clang-format off - int32_t values[] = { - // Handled by {if_isobjectorsmi}. - FAST_SMI_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, FAST_ELEMENTS, - FAST_HOLEY_ELEMENTS, - // Handled by {if_isdouble}. - FAST_DOUBLE_ELEMENTS, FAST_HOLEY_DOUBLE_ELEMENTS, - // Handled by {if_isdictionary}. - DICTIONARY_ELEMENTS, - // Handled by {if_isfaststringwrapper}. - FAST_STRING_WRAPPER_ELEMENTS, - // Handled by {if_isslowstringwrapper}. - SLOW_STRING_WRAPPER_ELEMENTS, - // Handled by {if_not_found}. - NO_ELEMENTS, - }; - Label* labels[] = { - &if_isobjectorsmi, &if_isobjectorsmi, &if_isobjectorsmi, - &if_isobjectorsmi, - &if_isdouble, &if_isdouble, - &if_isdictionary, - &if_isfaststringwrapper, - &if_isslowstringwrapper, - if_not_found, - }; - // clang-format on - STATIC_ASSERT(arraysize(values) == arraysize(labels)); - Switch(elements_kind, if_bailout, values, labels, arraysize(values)); - + Label if_isobjectorsmi(this); + Branch( + Int32LessThanOrEqual(elements_kind, Int32Constant(FAST_HOLEY_ELEMENTS)), + &if_isobjectorsmi, call_runtime); Bind(&if_isobjectorsmi); { Node* elements = LoadElements(object); Node* length = LoadFixedArrayBaseLength(elements); - GotoIf(Int32GreaterThanOrEqual(index, SmiToWord32(length)), if_not_found); + Label if_iskeyinrange(this); + Branch(Int32LessThan(index, SmiToWord32(length)), &if_iskeyinrange, + if_not_found); + Bind(&if_iskeyinrange); Node* element = LoadFixedArrayElement(elements, index); - Node* the_hole = TheHoleConstant(); + Node* the_hole = LoadRoot(Heap::kTheHoleValueRootIndex); Branch(WordEqual(element, the_hole), if_not_found, if_found); } - Bind(&if_isdouble); - { - Node* elements = LoadElements(object); - Node* length = LoadFixedArrayBaseLength(elements); - - GotoIf(Int32GreaterThanOrEqual(index, SmiToWord32(length)), if_not_found); - - if (kPointerSize == kDoubleSize) { - Node* element = - LoadFixedDoubleArrayElement(elements, index, MachineType::Uint64()); - Node* the_hole = Int64Constant(kHoleNanInt64); - Branch(Word64Equal(element, the_hole), if_not_found, if_found); - } else { - Node* element_upper = - LoadFixedDoubleArrayElement(elements, index, MachineType::Uint32(), - kIeeeDoubleExponentWordOffset); - Branch(Word32Equal(element_upper, Int32Constant(kHoleNanUpper32)), - if_not_found, if_found); - } - } - Bind(&if_isdictionary); - { - Variable var_entry(this, MachineRepresentation::kWord32); - Node* elements = LoadElements(object); - NumberDictionaryLookup(elements, index, if_found, - &var_entry, if_not_found); - } - Bind(&if_isfaststringwrapper); - { - Assert(Word32Equal(LoadInstanceType(object), Int32Constant(JS_VALUE_TYPE))); - Node* string = LoadJSValueValue(object); - Assert(Int32LessThan(LoadInstanceType(string), - Int32Constant(FIRST_NONSTRING_TYPE))); - Node* length = LoadStringLength(string); - GotoIf(Int32LessThan(index, SmiToWord32(length)), if_found); - Goto(&if_isobjectorsmi); - } - Bind(&if_isslowstringwrapper); - { - Assert(Word32Equal(LoadInstanceType(object), Int32Constant(JS_VALUE_TYPE))); - Node* string = LoadJSValueValue(object); - Assert(Int32LessThan(LoadInstanceType(string), - Int32Constant(FIRST_NONSTRING_TYPE))); - Node* length = LoadStringLength(string); - GotoIf(Int32LessThan(index, SmiToWord32(length)), if_found); - Goto(&if_isdictionary); - } } -// Instantiate template methods to workaround GCC compilation issue. -template void CodeStubAssembler::NumberDictionaryLookup( - Node*, Node*, Label*, Variable*, Label*); -template void CodeStubAssembler::NumberDictionaryLookup< - UnseededNumberDictionary>(Node*, Node*, Label*, Variable*, Label*); - Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable, Node* object) { Variable var_result(this, MachineRepresentation::kTagged); diff --git a/src/code-stub-assembler.h b/src/code-stub-assembler.h index 8d964b1362..ac08b5073e 100644 --- a/src/code-stub-assembler.h +++ b/src/code-stub-assembler.h @@ -40,8 +40,6 @@ class CodeStubAssembler : public compiler::CodeAssembler { compiler::Node* NoContextConstant(); compiler::Node* NullConstant(); compiler::Node* UndefinedConstant(); - compiler::Node* TheHoleConstant(); - compiler::Node* HashSeed(); compiler::Node* StaleRegisterConstant(); // Float64 operations. @@ -114,8 +112,6 @@ class CodeStubAssembler : public compiler::CodeAssembler { compiler::Node* LoadMap(compiler::Node* object); // Load the instance type of an HeapObject. compiler::Node* LoadInstanceType(compiler::Node* object); - // Load the properties backing store of a JSObject. - compiler::Node* LoadProperties(compiler::Node* object); // Load the elements backing store of a JSObject. compiler::Node* LoadElements(compiler::Node* object); // Load the length of a fixed array base instance. @@ -132,20 +128,11 @@ class CodeStubAssembler : public compiler::CodeAssembler { compiler::Node* LoadMapDescriptors(compiler::Node* map); // Load the prototype of a map. compiler::Node* LoadMapPrototype(compiler::Node* map); - // Load the instance size of a Map. - compiler::Node* LoadMapInstanceSize(compiler::Node* map); // Load the hash field of a name. - compiler::Node* LoadNameHashField(compiler::Node* name); - // Load the hash value of a name. If {if_hash_not_computed} label - // is specified then it also checks if hash is actually computed. - compiler::Node* LoadNameHash(compiler::Node* name, - Label* if_hash_not_computed = nullptr); - - // Load length field of a String object. - compiler::Node* LoadStringLength(compiler::Node* object); - // Load value field of a JSValue object. - compiler::Node* LoadJSValueValue(compiler::Node* object); + compiler::Node* LoadNameHash(compiler::Node* name); + // Load the instance size of a Map. + compiler::Node* LoadMapInstanceSize(compiler::Node* map); compiler::Node* AllocateUninitializedFixedArray(compiler::Node* length); @@ -154,11 +141,6 @@ class CodeStubAssembler : public compiler::CodeAssembler { compiler::Node* object, compiler::Node* int32_index, int additional_offset = 0, ParameterMode parameter_mode = INTEGER_PARAMETERS); - // Load an array element from a FixedDoubleArray. - compiler::Node* LoadFixedDoubleArrayElement( - compiler::Node* object, compiler::Node* int32_index, - MachineType machine_type, int additional_offset = 0, - ParameterMode parameter_mode = INTEGER_PARAMETERS); // Context manipulation compiler::Node* LoadNativeContext(compiler::Node* context); @@ -248,31 +230,17 @@ class CodeStubAssembler : public compiler::CodeAssembler { // Various building blocks for stubs doing property lookups. void TryToName(compiler::Node* key, Label* if_keyisindex, Variable* var_index, - Label* if_keyisunique, Label* if_bailout); - - 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, - int inlined_probes = kInlinedDictionaryProbes); - - compiler::Node* ComputeIntegerHash(compiler::Node* key, compiler::Node* seed); - - template - void NumberDictionaryLookup(compiler::Node* dictionary, compiler::Node* key, - Label* if_found, Variable* var_entry, - Label* if_not_found); + Label* if_keyisunique, Label* call_runtime); void TryLookupProperty(compiler::Node* object, compiler::Node* map, - compiler::Node* instance_type, - compiler::Node* unique_name, Label* if_found, - Label* if_not_found, Label* if_bailout); + compiler::Node* instance_type, compiler::Node* name, + Label* if_found, Label* if_not_found, + Label* call_runtime); void TryLookupElement(compiler::Node* object, compiler::Node* map, compiler::Node* instance_type, compiler::Node* index, Label* if_found, Label* if_not_found, - Label* if_bailout); + Label* call_runtime); // Instanceof helpers. // ES6 section 7.3.19 OrdinaryHasInstance (C, O) diff --git a/src/globals.h b/src/globals.h index 7ef81afb8d..41f68b66e2 100644 --- a/src/globals.h +++ b/src/globals.h @@ -644,15 +644,6 @@ union IeeeDoubleBigEndianArchType { } bits; }; -#if V8_TARGET_LITTLE_ENDIAN -typedef IeeeDoubleLittleEndianArchType IeeeDoubleArchType; -const int kIeeeDoubleMantissaWordOffset = 0; -const int kIeeeDoubleExponentWordOffset = 4; -#else -typedef IeeeDoubleBigEndianArchType IeeeDoubleArchType; -const int kIeeeDoubleMantissaWordOffset = 4; -const int kIeeeDoubleExponentWordOffset = 0; -#endif // AccessorCallback struct AccessorDescriptor { diff --git a/src/objects-printer.cc b/src/objects-printer.cc index 57957e602d..183306583d 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -380,7 +380,7 @@ void JSObject::PrintElements(std::ostream& os) { // NOLINT case DICTIONARY_ELEMENTS: case SLOW_STRING_WRAPPER_ELEMENTS: - SeededNumberDictionary::cast(elements())->Print(os); + elements()->Print(os); break; case FAST_SLOPPY_ARGUMENTS_ELEMENTS: case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { diff --git a/src/objects.cc b/src/objects.cc index 11c4ed7f15..de0d756966 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -11139,8 +11139,8 @@ uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) { value |= length << String::ArrayIndexLengthBits::kShift; DCHECK((value & String::kIsNotArrayIndexMask) == 0); - DCHECK_EQ(length <= String::kMaxCachedArrayIndexLength, - (value & String::kContainsCachedArrayIndexMask) == 0); + DCHECK((length > String::kMaxCachedArrayIndexLength) || + (value & String::kContainsCachedArrayIndexMask) == 0); return value; } @@ -15170,11 +15170,6 @@ void Dictionary::Print(std::ostream& os) { // NOLINT } } } -template -void Dictionary::Print() { - OFStream os(stdout); - Print(os); -} #endif @@ -15906,7 +15901,15 @@ int NameDictionaryBase::FindEntry(Handle key) { Object* element = this->get(index); if (element->IsUndefined()) break; // Empty entry. if (*key == element) return entry; - DCHECK(element->IsTheHole() || element->IsUniqueName()); + if (!element->IsUniqueName() && + !element->IsTheHole() && + Name::cast(element)->Equals(*key)) { + // Replace a key that is a non-internalized string by the equivalent + // internalized string for faster further lookups. + this->set(index, *key); + return entry; + } + DCHECK(element->IsTheHole() || !Name::cast(element)->Equals(*key)); entry = Derived::NextProbe(entry, count++, capacity); } return Derived::kNotFound; diff --git a/src/objects.h b/src/objects.h index 8ff688e507..631615a50d 100644 --- a/src/objects.h +++ b/src/objects.h @@ -3189,8 +3189,6 @@ class HashTableBase : public FixedArray { template class HashTable : public HashTableBase { public: - typedef Shape ShapeT; - // Wrapper methods inline uint32_t Hash(Key key) { if (Shape::UsesSeed) { @@ -3477,9 +3475,6 @@ class Dictionary: public HashTable { static Handle EnsureCapacity(Handle obj, int n, Key key); #ifdef OBJECT_PRINT - // For our gdb macros, we should perhaps change these in the future. - void Print(); - void Print(std::ostream& os); // NOLINT #endif // Returns the key (slow). @@ -8575,10 +8570,6 @@ class Name: public HeapObject { // Array index strings this short can keep their index in the hash field. static const int kMaxCachedArrayIndexLength = 7; - // Maximum number of characters to consider when trying to convert a string - // value into an array index. - static const int kMaxArrayIndexSize = 10; - // For strings which are array indexes the hash value has the string length // mixed into the hash, mainly to avoid a hash value of zero which would be // the case for the string '0'. 24 bits are used for the array index value. @@ -8586,8 +8577,7 @@ class Name: public HeapObject { static const int kArrayIndexLengthBits = kBitsPerInt - kArrayIndexValueBits - kNofHashBitFields; - STATIC_ASSERT(kArrayIndexLengthBits > 0); - STATIC_ASSERT(kMaxArrayIndexSize < (1 << kArrayIndexLengthBits)); + STATIC_ASSERT((kArrayIndexLengthBits > 0)); class ArrayIndexValueBits : public BitField {}; // NOLINT @@ -8677,6 +8667,34 @@ class String: public Name { public: enum Encoding { ONE_BYTE_ENCODING, TWO_BYTE_ENCODING }; + // Array index strings this short can keep their index in the hash field. + static const int kMaxCachedArrayIndexLength = 7; + + // For strings which are array indexes the hash value has the string length + // mixed into the hash, mainly to avoid a hash value of zero which would be + // the case for the string '0'. 24 bits are used for the array index value. + static const int kArrayIndexValueBits = 24; + static const int kArrayIndexLengthBits = + kBitsPerInt - kArrayIndexValueBits - kNofHashBitFields; + + STATIC_ASSERT((kArrayIndexLengthBits > 0)); + + class ArrayIndexValueBits : public BitField {}; // NOLINT + class ArrayIndexLengthBits : public BitField {}; // NOLINT + + // Check that kMaxCachedArrayIndexLength + 1 is a power of two so we + // could use a mask to test if the length of string is less than or equal to + // kMaxCachedArrayIndexLength. + STATIC_ASSERT(IS_POWER_OF_TWO(kMaxCachedArrayIndexLength + 1)); + + static const unsigned int kContainsCachedArrayIndexMask = + (~static_cast(kMaxCachedArrayIndexLength) + << ArrayIndexLengthBits::kShift) | + kIsNotArrayIndexMask; + class SubStringRange { public: explicit inline SubStringRange(String* string, int first = 0, @@ -8888,6 +8906,11 @@ class String: public Name { static const int kLengthOffset = Name::kSize; static const int kSize = kLengthOffset + kPointerSize; + // Maximum number of characters to consider when trying to convert a string + // value into an array index. + static const int kMaxArrayIndexSize = 10; + STATIC_ASSERT(kMaxArrayIndexSize < (1 << kArrayIndexLengthBits)); + // Max char codes. static const int32_t kMaxOneByteCharCode = unibrow::Latin1::kMaxChar; static const uint32_t kMaxOneByteCharCodeU = unibrow::Latin1::kMaxChar; diff --git a/src/utils.cc b/src/utils.cc index 16b5b7c61f..c46028f059 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -430,8 +430,11 @@ void init_memcopy_functions(Isolate* isolate) { bool DoubleToBoolean(double d) { // NaN, +0, and -0 should return the false object - IeeeDoubleArchType u; - +#if V8_TARGET_LITTLE_ENDIAN + union IeeeDoubleLittleEndianArchType u; +#else + union IeeeDoubleBigEndianArchType u; +#endif u.d = d; if (u.bits.exp == 2047) { // Detect NaN for IEEE double precision floating point. diff --git a/test/cctest/BUILD.gn b/test/cctest/BUILD.gn index c085e1b959..50465d80a6 100644 --- a/test/cctest/BUILD.gn +++ b/test/cctest/BUILD.gn @@ -19,6 +19,7 @@ executable("cctest") { "compiler/graph-builder-tester.h", "compiler/test-basic-block-profiler.cc", "compiler/test-branch-combine.cc", + "compiler/test-code-stub-assembler.cc", "compiler/test-gap-resolver.cc", "compiler/test-graph-visualizer.cc", "compiler/test-instruction.cc", @@ -92,7 +93,6 @@ executable("cctest") { "test-bignum.cc", "test-bit-vector.cc", "test-circular-queue.cc", - "test-code-stub-assembler.cc", "test-compiler.cc", "test-constantpool.cc", "test-conversions.cc", diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp index f4af90677d..fb8be88a5d 100644 --- a/test/cctest/cctest.gyp +++ b/test/cctest/cctest.gyp @@ -53,6 +53,7 @@ 'compiler/graph-builder-tester.h', 'compiler/test-basic-block-profiler.cc', 'compiler/test-branch-combine.cc', + 'compiler/test-code-stub-assembler.cc', 'compiler/test-gap-resolver.cc', 'compiler/test-graph-visualizer.cc', 'compiler/test-instruction.cc', @@ -128,7 +129,6 @@ 'test-bignum-dtoa.cc', 'test-bit-vector.cc', 'test-circular-queue.cc', - 'test-code-stub-assembler.cc', 'test-compiler.cc', 'test-constantpool.cc', 'test-conversions.cc', diff --git a/test/cctest/compiler/function-tester.h b/test/cctest/compiler/function-tester.h index 9246dfb79e..584ad49708 100644 --- a/test/cctest/compiler/function-tester.h +++ b/test/cctest/compiler/function-tester.h @@ -42,18 +42,16 @@ class FunctionTester : public InitializedHandleScope { CompileGraph(graph); } - FunctionTester(Handle code, int param_count) + FunctionTester(const CallInterfaceDescriptor& descriptor, Handle code) : isolate(main_isolate()), - function((FLAG_allow_natives_syntax = true, - NewFunction(BuildFunction(param_count).c_str()))), + function( + (FLAG_allow_natives_syntax = true, + NewFunction(BuildFunctionFromDescriptor(descriptor).c_str()))), flags_(0) { Compile(function); function->ReplaceCode(*code); } - FunctionTester(const CallInterfaceDescriptor& descriptor, Handle code) - : FunctionTester(code, descriptor.GetParameterCount()) {} - Isolate* isolate; Handle function; @@ -66,12 +64,6 @@ class FunctionTester : public InitializedHandleScope { return Execution::Call(isolate, function, undefined(), 2, args); } - MaybeHandle Call(Handle a, Handle b, - Handle c) { - Handle args[] = {a, b, c}; - return Execution::Call(isolate, function, undefined(), 3, args); - } - MaybeHandle Call(Handle a, Handle b, Handle c, Handle d) { Handle args[] = {a, b, c, d}; @@ -99,56 +91,41 @@ class FunctionTester : public InitializedHandleScope { return try_catch.Message(); } - void CheckCall(Handle expected, Handle a, Handle b, - Handle c, Handle d) { - Handle result = Call(a, b, c, d).ToHandleChecked(); - CHECK(expected->SameValue(*result)); - } - - void CheckCall(Handle expected, Handle a, Handle b, - Handle c) { - return CheckCall(expected, a, b, c, undefined()); - } - void CheckCall(Handle expected, Handle a, Handle b) { - return CheckCall(expected, a, b, undefined()); + Handle result = Call(a, b).ToHandleChecked(); + CHECK(expected->SameValue(*result)); } void CheckCall(Handle expected, Handle a) { CheckCall(expected, a, undefined()); } - void CheckCall(Handle expected) { CheckCall(expected, undefined()); } + void CheckCall(Handle expected) { + CheckCall(expected, undefined(), undefined()); + } void CheckCall(double expected, double a, double b) { CheckCall(Val(expected), Val(a), Val(b)); } - void CheckTrue(Handle a) { CheckCall(true_value(), a); } - void CheckTrue(Handle a, Handle b) { CheckCall(true_value(), a, b); } - void CheckTrue(Handle a, Handle b, Handle c) { - CheckCall(true_value(), a, b, c); - } - - void CheckTrue(Handle a, Handle b, Handle c, - Handle d) { - CheckCall(true_value(), a, b, c, d); - } + void CheckTrue(Handle a) { CheckCall(true_value(), a, undefined()); } void CheckTrue(double a, double b) { CheckCall(true_value(), Val(a), Val(b)); } - void CheckFalse(Handle a) { CheckCall(false_value(), a); } - void CheckFalse(Handle a, Handle b) { CheckCall(false_value(), a, b); } + void CheckFalse(Handle a) { + CheckCall(false_value(), a, undefined()); + } + void CheckFalse(double a, double b) { CheckCall(false_value(), Val(a), Val(b)); } @@ -240,6 +217,11 @@ class FunctionTester : public InitializedHandleScope { return function_string; } + std::string BuildFunctionFromDescriptor( + const CallInterfaceDescriptor& descriptor) { + return BuildFunction(descriptor.GetParameterCount()); + } + // Compile the given machine graph instead of the source of the function // and replace the JSFunction's code with the result. Handle CompileGraph(Graph* graph) { diff --git a/test/cctest/compiler/test-code-stub-assembler.cc b/test/cctest/compiler/test-code-stub-assembler.cc new file mode 100644 index 0000000000..37ba9e9904 --- /dev/null +++ b/test/cctest/compiler/test-code-stub-assembler.cc @@ -0,0 +1,394 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/interface-descriptors.h" +#include "src/isolate.h" +#include "test/cctest/compiler/function-tester.h" + +namespace v8 { +namespace internal { +namespace compiler { + + +class CodeStubAssemblerTester : public CodeStubAssembler { + public: + // Test generating code for a stub. + CodeStubAssemblerTester(Isolate* isolate, + const CallInterfaceDescriptor& descriptor) + : CodeStubAssembler(isolate, isolate->runtime_zone(), descriptor, + Code::ComputeFlags(Code::STUB), "test"), + scope_(isolate) {} + + // Test generating code for a JS function (e.g. builtins). + CodeStubAssemblerTester(Isolate* isolate, int parameter_count) + : CodeStubAssembler(isolate, isolate->runtime_zone(), parameter_count, + Code::ComputeFlags(Code::FUNCTION), "test"), + scope_(isolate) {} + + private: + HandleScope scope_; + LocalContext context_; +}; + + +TEST(SimpleSmiReturn) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + m.Return(m.SmiTag(m.Int32Constant(37))); + Handle code = m.GenerateCode(); + FunctionTester ft(descriptor, code); + MaybeHandle result = ft.Call(); + CHECK_EQ(37, Handle::cast(result.ToHandleChecked())->value()); +} + + +TEST(SimpleIntPtrReturn) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + int test; + m.Return(m.IntPtrConstant(reinterpret_cast(&test))); + Handle code = m.GenerateCode(); + FunctionTester ft(descriptor, code); + MaybeHandle result = ft.Call(); + CHECK_EQ(reinterpret_cast(&test), + reinterpret_cast(*result.ToHandleChecked())); +} + + +TEST(SimpleDoubleReturn) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + m.Return(m.NumberConstant(0.5)); + Handle code = m.GenerateCode(); + FunctionTester ft(descriptor, code); + MaybeHandle result = ft.Call(); + CHECK_EQ(0.5, Handle::cast(result.ToHandleChecked())->value()); +} + + +TEST(SimpleCallRuntime1Arg) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + Node* context = m.HeapConstant(Handle(isolate->native_context())); + Node* b = m.SmiTag(m.Int32Constant(0)); + m.Return(m.CallRuntime(Runtime::kNumberToSmi, context, b)); + Handle code = m.GenerateCode(); + FunctionTester ft(descriptor, code); + MaybeHandle result = ft.Call(); + CHECK_EQ(0, Handle::cast(result.ToHandleChecked())->value()); +} + + +TEST(SimpleTailCallRuntime1Arg) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + Node* context = m.HeapConstant(Handle(isolate->native_context())); + Node* b = m.SmiTag(m.Int32Constant(0)); + m.TailCallRuntime(Runtime::kNumberToSmi, context, b); + Handle code = m.GenerateCode(); + FunctionTester ft(descriptor, code); + MaybeHandle result = ft.Call(); + CHECK_EQ(0, Handle::cast(result.ToHandleChecked())->value()); +} + + +TEST(SimpleCallRuntime2Arg) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + Node* context = m.HeapConstant(Handle(isolate->native_context())); + Node* a = m.SmiTag(m.Int32Constant(2)); + Node* b = m.SmiTag(m.Int32Constant(4)); + m.Return(m.CallRuntime(Runtime::kMathPow, context, a, b)); + Handle code = m.GenerateCode(); + FunctionTester ft(descriptor, code); + MaybeHandle result = ft.Call(); + CHECK_EQ(16, Handle::cast(result.ToHandleChecked())->value()); +} + + +TEST(SimpleTailCallRuntime2Arg) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + Node* context = m.HeapConstant(Handle(isolate->native_context())); + Node* a = m.SmiTag(m.Int32Constant(2)); + Node* b = m.SmiTag(m.Int32Constant(4)); + m.TailCallRuntime(Runtime::kMathPow, context, a, b); + Handle code = m.GenerateCode(); + FunctionTester ft(descriptor, code); + MaybeHandle result = ft.Call(); + CHECK_EQ(16, Handle::cast(result.ToHandleChecked())->value()); +} + +TEST(VariableMerge1) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + CodeStubAssembler::Variable var1(&m, MachineRepresentation::kTagged); + CodeStubAssembler::Label l1(&m), l2(&m), merge(&m); + Node* temp = m.Int32Constant(0); + var1.Bind(temp); + m.Branch(m.Int32Constant(1), &l1, &l2); + m.Bind(&l1); + CHECK_EQ(var1.value(), temp); + m.Goto(&merge); + m.Bind(&l2); + CHECK_EQ(var1.value(), temp); + m.Goto(&merge); + m.Bind(&merge); + CHECK_EQ(var1.value(), temp); +} + +TEST(VariableMerge2) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + CodeStubAssembler::Variable var1(&m, MachineRepresentation::kTagged); + CodeStubAssembler::Label l1(&m), l2(&m), merge(&m); + Node* temp = m.Int32Constant(0); + var1.Bind(temp); + m.Branch(m.Int32Constant(1), &l1, &l2); + m.Bind(&l1); + CHECK_EQ(var1.value(), temp); + m.Goto(&merge); + m.Bind(&l2); + Node* temp2 = m.Int32Constant(2); + var1.Bind(temp2); + CHECK_EQ(var1.value(), temp2); + m.Goto(&merge); + m.Bind(&merge); + CHECK_NE(var1.value(), temp); +} + +TEST(VariableMerge3) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + CodeStubAssembler::Variable var1(&m, MachineRepresentation::kTagged); + CodeStubAssembler::Variable var2(&m, MachineRepresentation::kTagged); + CodeStubAssembler::Label l1(&m), l2(&m), merge(&m); + Node* temp = m.Int32Constant(0); + var1.Bind(temp); + var2.Bind(temp); + m.Branch(m.Int32Constant(1), &l1, &l2); + m.Bind(&l1); + CHECK_EQ(var1.value(), temp); + m.Goto(&merge); + m.Bind(&l2); + Node* temp2 = m.Int32Constant(2); + var1.Bind(temp2); + CHECK_EQ(var1.value(), temp2); + m.Goto(&merge); + m.Bind(&merge); + CHECK_NE(var1.value(), temp); + CHECK_NE(var1.value(), temp2); + CHECK_EQ(var2.value(), temp); +} + +TEST(VariableMergeBindFirst) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + CodeStubAssembler::Variable var1(&m, MachineRepresentation::kTagged); + CodeStubAssembler::Label l1(&m), l2(&m), merge(&m, &var1), end(&m); + Node* temp = m.Int32Constant(0); + var1.Bind(temp); + m.Branch(m.Int32Constant(1), &l1, &l2); + m.Bind(&l1); + CHECK_EQ(var1.value(), temp); + m.Goto(&merge); + m.Bind(&merge); + CHECK(var1.value() != temp); + CHECK(var1.value() != nullptr); + m.Goto(&end); + m.Bind(&l2); + Node* temp2 = m.Int32Constant(2); + var1.Bind(temp2); + CHECK_EQ(var1.value(), temp2); + m.Goto(&merge); + m.Bind(&end); + CHECK(var1.value() != temp); + CHECK(var1.value() != nullptr); +} + +TEST(VariableMergeSwitch) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + CodeStubAssembler::Variable var1(&m, MachineRepresentation::kTagged); + CodeStubAssembler::Label l1(&m), l2(&m), default_label(&m); + CodeStubAssembler::Label* labels[] = {&l1, &l2}; + int32_t values[] = {1, 2}; + Node* temp = m.Int32Constant(0); + var1.Bind(temp); + m.Switch(m.Int32Constant(2), &default_label, values, labels, 2); + m.Bind(&l1); + DCHECK_EQ(temp, var1.value()); + m.Return(temp); + m.Bind(&l2); + DCHECK_EQ(temp, var1.value()); + m.Return(temp); + m.Bind(&default_label); + DCHECK_EQ(temp, var1.value()); + m.Return(temp); +} + +TEST(FixedArrayAccessSmiIndex) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + Handle array = isolate->factory()->NewFixedArray(5); + array->set(4, Smi::FromInt(733)); + m.Return(m.LoadFixedArrayElement(m.HeapConstant(array), + m.SmiTag(m.Int32Constant(4)), 0, + CodeStubAssembler::SMI_PARAMETERS)); + Handle code = m.GenerateCode(); + FunctionTester ft(descriptor, code); + MaybeHandle result = ft.Call(); + CHECK_EQ(733, Handle::cast(result.ToHandleChecked())->value()); +} + +TEST(LoadHeapNumberValue) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + Handle number = isolate->factory()->NewHeapNumber(1234); + m.Return(m.SmiTag( + m.ChangeFloat64ToUint32(m.LoadHeapNumberValue(m.HeapConstant(number))))); + Handle code = m.GenerateCode(); + FunctionTester ft(descriptor, code); + MaybeHandle result = ft.Call(); + CHECK_EQ(1234, Handle::cast(result.ToHandleChecked())->value()); +} + +TEST(LoadInstanceType) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + Handle undefined = isolate->factory()->undefined_value(); + m.Return(m.SmiTag(m.LoadInstanceType(m.HeapConstant(undefined)))); + Handle code = m.GenerateCode(); + FunctionTester ft(descriptor, code); + MaybeHandle result = ft.Call(); + CHECK_EQ(InstanceType::ODDBALL_TYPE, + Handle::cast(result.ToHandleChecked())->value()); +} + +namespace { + +class TestBitField : public BitField {}; + +} // namespace + +TEST(BitFieldDecode) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + m.Return(m.SmiTag(m.BitFieldDecode(m.Int32Constant(0x2f)))); + Handle code = m.GenerateCode(); + FunctionTester ft(descriptor, code); + MaybeHandle result = ft.Call(); + // value = 00101111 + // mask = 00111000 + // result = 101 + CHECK_EQ(5, Handle::cast(result.ToHandleChecked())->value()); +} + +namespace { + +Handle CreateFunctionFromCode(int parameter_count_with_receiver, + Handle code) { + Isolate* isolate = code->GetIsolate(); + Handle name = isolate->factory()->InternalizeUtf8String("test"); + Handle function = + isolate->factory()->NewFunctionWithoutPrototype(name, code); + function->shared()->set_internal_formal_parameter_count( + parameter_count_with_receiver - 1); // Implicit undefined receiver. + return function; +} + +} // namespace + +TEST(JSFunction) { + const int kNumParams = 3; // Receiver, left, right. + Isolate* isolate(CcTest::InitIsolateOnce()); + CodeStubAssemblerTester m(isolate, kNumParams); + m.Return(m.SmiTag(m.Int32Add(m.SmiToWord32(m.Parameter(1)), + m.SmiToWord32(m.Parameter(2))))); + Handle code = m.GenerateCode(); + Handle function = CreateFunctionFromCode(kNumParams, code); + Handle args[] = {Handle(Smi::FromInt(23), isolate), + Handle(Smi::FromInt(34), isolate)}; + MaybeHandle result = + Execution::Call(isolate, function, isolate->factory()->undefined_value(), + arraysize(args), args); + CHECK_EQ(57, Handle::cast(result.ToHandleChecked())->value()); +} + +TEST(SplitEdgeBranchMerge) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + CodeStubAssembler::Label l1(&m), merge(&m); + m.Branch(m.Int32Constant(1), &l1, &merge); + m.Bind(&l1); + m.Goto(&merge); + m.Bind(&merge); + USE(m.GenerateCode()); +} + +TEST(SplitEdgeSwitchMerge) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + CodeStubAssembler::Label l1(&m), l2(&m), l3(&m), default_label(&m); + CodeStubAssembler::Label* labels[] = {&l1, &l2}; + int32_t values[] = {1, 2}; + m.Branch(m.Int32Constant(1), &l3, &l1); + m.Bind(&l3); + m.Switch(m.Int32Constant(2), &default_label, values, labels, 2); + m.Bind(&l1); + m.Goto(&l2); + m.Bind(&l2); + m.Goto(&default_label); + m.Bind(&default_label); + USE(m.GenerateCode()); +} + +TEST(TestToConstant) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + int32_t value32; + int64_t value64; + Node* a = m.Int32Constant(5); + CHECK(m.ToInt32Constant(a, value32)); + CHECK(m.ToInt64Constant(a, value64)); + + a = m.Int64Constant(static_cast(1) << 32); + CHECK(!m.ToInt32Constant(a, value32)); + CHECK(m.ToInt64Constant(a, value64)); + + a = m.Int64Constant(13); + CHECK(m.ToInt32Constant(a, value32)); + CHECK(m.ToInt64Constant(a, value64)); + + a = m.UndefinedConstant(); + CHECK(!m.ToInt32Constant(a, value32)); + CHECK(!m.ToInt64Constant(a, value64)); + + a = m.UndefinedConstant(); + CHECK(!m.ToInt32Constant(a, value32)); + CHECK(!m.ToInt64Constant(a, value64)); +} + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/test/cctest/test-code-stub-assembler.cc b/test/cctest/test-code-stub-assembler.cc deleted file mode 100644 index aa1c7ce252..0000000000 --- a/test/cctest/test-code-stub-assembler.cc +++ /dev/null @@ -1,1059 +0,0 @@ -// Copyright 2015 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "src/base/utils/random-number-generator.h" -#include "src/interface-descriptors.h" -#include "src/isolate.h" -#include "test/cctest/compiler/function-tester.h" - -namespace v8 { -namespace internal { - -using compiler::FunctionTester; -using compiler::Node; - -class CodeStubAssemblerTester : public CodeStubAssembler { - public: - // Test generating code for a stub. - CodeStubAssemblerTester(Isolate* isolate, - const CallInterfaceDescriptor& descriptor) - : CodeStubAssembler(isolate, isolate->runtime_zone(), descriptor, - Code::ComputeFlags(Code::STUB), "test"), - zone_scope_(isolate->runtime_zone()), - scope_(isolate) {} - - // Test generating code for a JS function (e.g. builtins). - CodeStubAssemblerTester(Isolate* isolate, int parameter_count) - : CodeStubAssembler(isolate, isolate->runtime_zone(), parameter_count, - Code::ComputeFlags(Code::FUNCTION), "test"), - zone_scope_(isolate->runtime_zone()), - scope_(isolate) {} - - private: - ZoneScope zone_scope_; - HandleScope scope_; - LocalContext context_; -}; - -TEST(SimpleSmiReturn) { - Isolate* isolate(CcTest::InitIsolateOnce()); - VoidDescriptor descriptor(isolate); - CodeStubAssemblerTester m(isolate, descriptor); - m.Return(m.SmiTag(m.Int32Constant(37))); - Handle code = m.GenerateCode(); - FunctionTester ft(descriptor, code); - MaybeHandle result = ft.Call(); - CHECK_EQ(37, Handle::cast(result.ToHandleChecked())->value()); -} - -TEST(SimpleIntPtrReturn) { - Isolate* isolate(CcTest::InitIsolateOnce()); - VoidDescriptor descriptor(isolate); - CodeStubAssemblerTester m(isolate, descriptor); - int test; - m.Return(m.IntPtrConstant(reinterpret_cast(&test))); - Handle code = m.GenerateCode(); - FunctionTester ft(descriptor, code); - MaybeHandle result = ft.Call(); - CHECK_EQ(reinterpret_cast(&test), - reinterpret_cast(*result.ToHandleChecked())); -} - -TEST(SimpleDoubleReturn) { - Isolate* isolate(CcTest::InitIsolateOnce()); - VoidDescriptor descriptor(isolate); - CodeStubAssemblerTester m(isolate, descriptor); - m.Return(m.NumberConstant(0.5)); - Handle code = m.GenerateCode(); - FunctionTester ft(descriptor, code); - MaybeHandle result = ft.Call(); - CHECK_EQ(0.5, Handle::cast(result.ToHandleChecked())->value()); -} - -TEST(SimpleCallRuntime1Arg) { - Isolate* isolate(CcTest::InitIsolateOnce()); - VoidDescriptor descriptor(isolate); - CodeStubAssemblerTester m(isolate, descriptor); - Node* context = m.HeapConstant(Handle(isolate->native_context())); - Node* b = m.SmiTag(m.Int32Constant(0)); - m.Return(m.CallRuntime(Runtime::kNumberToSmi, context, b)); - Handle code = m.GenerateCode(); - FunctionTester ft(descriptor, code); - MaybeHandle result = ft.Call(); - CHECK_EQ(0, Handle::cast(result.ToHandleChecked())->value()); -} - -TEST(SimpleTailCallRuntime1Arg) { - Isolate* isolate(CcTest::InitIsolateOnce()); - VoidDescriptor descriptor(isolate); - CodeStubAssemblerTester m(isolate, descriptor); - Node* context = m.HeapConstant(Handle(isolate->native_context())); - Node* b = m.SmiTag(m.Int32Constant(0)); - m.TailCallRuntime(Runtime::kNumberToSmi, context, b); - Handle code = m.GenerateCode(); - FunctionTester ft(descriptor, code); - MaybeHandle result = ft.Call(); - CHECK_EQ(0, Handle::cast(result.ToHandleChecked())->value()); -} - -TEST(SimpleCallRuntime2Arg) { - Isolate* isolate(CcTest::InitIsolateOnce()); - VoidDescriptor descriptor(isolate); - CodeStubAssemblerTester m(isolate, descriptor); - Node* context = m.HeapConstant(Handle(isolate->native_context())); - Node* a = m.SmiTag(m.Int32Constant(2)); - Node* b = m.SmiTag(m.Int32Constant(4)); - m.Return(m.CallRuntime(Runtime::kMathPow, context, a, b)); - Handle code = m.GenerateCode(); - FunctionTester ft(descriptor, code); - MaybeHandle result = ft.Call(); - CHECK_EQ(16, Handle::cast(result.ToHandleChecked())->value()); -} - -TEST(SimpleTailCallRuntime2Arg) { - Isolate* isolate(CcTest::InitIsolateOnce()); - VoidDescriptor descriptor(isolate); - CodeStubAssemblerTester m(isolate, descriptor); - Node* context = m.HeapConstant(Handle(isolate->native_context())); - Node* a = m.SmiTag(m.Int32Constant(2)); - Node* b = m.SmiTag(m.Int32Constant(4)); - m.TailCallRuntime(Runtime::kMathPow, context, a, b); - Handle code = m.GenerateCode(); - FunctionTester ft(descriptor, code); - MaybeHandle result = ft.Call(); - CHECK_EQ(16, Handle::cast(result.ToHandleChecked())->value()); -} - -TEST(VariableMerge1) { - Isolate* isolate(CcTest::InitIsolateOnce()); - VoidDescriptor descriptor(isolate); - CodeStubAssemblerTester m(isolate, descriptor); - CodeStubAssembler::Variable var1(&m, MachineRepresentation::kTagged); - CodeStubAssembler::Label l1(&m), l2(&m), merge(&m); - Node* temp = m.Int32Constant(0); - var1.Bind(temp); - m.Branch(m.Int32Constant(1), &l1, &l2); - m.Bind(&l1); - CHECK_EQ(var1.value(), temp); - m.Goto(&merge); - m.Bind(&l2); - CHECK_EQ(var1.value(), temp); - m.Goto(&merge); - m.Bind(&merge); - CHECK_EQ(var1.value(), temp); -} - -TEST(VariableMerge2) { - Isolate* isolate(CcTest::InitIsolateOnce()); - VoidDescriptor descriptor(isolate); - CodeStubAssemblerTester m(isolate, descriptor); - CodeStubAssembler::Variable var1(&m, MachineRepresentation::kTagged); - CodeStubAssembler::Label l1(&m), l2(&m), merge(&m); - Node* temp = m.Int32Constant(0); - var1.Bind(temp); - m.Branch(m.Int32Constant(1), &l1, &l2); - m.Bind(&l1); - CHECK_EQ(var1.value(), temp); - m.Goto(&merge); - m.Bind(&l2); - Node* temp2 = m.Int32Constant(2); - var1.Bind(temp2); - CHECK_EQ(var1.value(), temp2); - m.Goto(&merge); - m.Bind(&merge); - CHECK_NE(var1.value(), temp); -} - -TEST(VariableMerge3) { - Isolate* isolate(CcTest::InitIsolateOnce()); - VoidDescriptor descriptor(isolate); - CodeStubAssemblerTester m(isolate, descriptor); - CodeStubAssembler::Variable var1(&m, MachineRepresentation::kTagged); - CodeStubAssembler::Variable var2(&m, MachineRepresentation::kTagged); - CodeStubAssembler::Label l1(&m), l2(&m), merge(&m); - Node* temp = m.Int32Constant(0); - var1.Bind(temp); - var2.Bind(temp); - m.Branch(m.Int32Constant(1), &l1, &l2); - m.Bind(&l1); - CHECK_EQ(var1.value(), temp); - m.Goto(&merge); - m.Bind(&l2); - Node* temp2 = m.Int32Constant(2); - var1.Bind(temp2); - CHECK_EQ(var1.value(), temp2); - m.Goto(&merge); - m.Bind(&merge); - CHECK_NE(var1.value(), temp); - CHECK_NE(var1.value(), temp2); - CHECK_EQ(var2.value(), temp); -} - -TEST(VariableMergeBindFirst) { - Isolate* isolate(CcTest::InitIsolateOnce()); - VoidDescriptor descriptor(isolate); - CodeStubAssemblerTester m(isolate, descriptor); - CodeStubAssembler::Variable var1(&m, MachineRepresentation::kTagged); - CodeStubAssembler::Label l1(&m), l2(&m), merge(&m, &var1), end(&m); - Node* temp = m.Int32Constant(0); - var1.Bind(temp); - m.Branch(m.Int32Constant(1), &l1, &l2); - m.Bind(&l1); - CHECK_EQ(var1.value(), temp); - m.Goto(&merge); - m.Bind(&merge); - CHECK(var1.value() != temp); - CHECK(var1.value() != nullptr); - m.Goto(&end); - m.Bind(&l2); - Node* temp2 = m.Int32Constant(2); - var1.Bind(temp2); - CHECK_EQ(var1.value(), temp2); - m.Goto(&merge); - m.Bind(&end); - CHECK(var1.value() != temp); - CHECK(var1.value() != nullptr); -} - -TEST(VariableMergeSwitch) { - Isolate* isolate(CcTest::InitIsolateOnce()); - VoidDescriptor descriptor(isolate); - CodeStubAssemblerTester m(isolate, descriptor); - CodeStubAssembler::Variable var1(&m, MachineRepresentation::kTagged); - CodeStubAssembler::Label l1(&m), l2(&m), default_label(&m); - CodeStubAssembler::Label* labels[] = {&l1, &l2}; - int32_t values[] = {1, 2}; - Node* temp = m.Int32Constant(0); - var1.Bind(temp); - m.Switch(m.Int32Constant(2), &default_label, values, labels, 2); - m.Bind(&l1); - DCHECK_EQ(temp, var1.value()); - m.Return(temp); - m.Bind(&l2); - DCHECK_EQ(temp, var1.value()); - m.Return(temp); - m.Bind(&default_label); - DCHECK_EQ(temp, var1.value()); - m.Return(temp); -} - -TEST(FixedArrayAccessSmiIndex) { - Isolate* isolate(CcTest::InitIsolateOnce()); - VoidDescriptor descriptor(isolate); - CodeStubAssemblerTester m(isolate, descriptor); - Handle array = isolate->factory()->NewFixedArray(5); - array->set(4, Smi::FromInt(733)); - m.Return(m.LoadFixedArrayElement(m.HeapConstant(array), - m.SmiTag(m.Int32Constant(4)), 0, - CodeStubAssembler::SMI_PARAMETERS)); - Handle code = m.GenerateCode(); - FunctionTester ft(descriptor, code); - MaybeHandle result = ft.Call(); - CHECK_EQ(733, Handle::cast(result.ToHandleChecked())->value()); -} - -TEST(LoadHeapNumberValue) { - Isolate* isolate(CcTest::InitIsolateOnce()); - VoidDescriptor descriptor(isolate); - CodeStubAssemblerTester m(isolate, descriptor); - Handle number = isolate->factory()->NewHeapNumber(1234); - m.Return(m.SmiTag( - m.ChangeFloat64ToUint32(m.LoadHeapNumberValue(m.HeapConstant(number))))); - Handle code = m.GenerateCode(); - FunctionTester ft(descriptor, code); - MaybeHandle result = ft.Call(); - CHECK_EQ(1234, Handle::cast(result.ToHandleChecked())->value()); -} - -TEST(LoadInstanceType) { - Isolate* isolate(CcTest::InitIsolateOnce()); - VoidDescriptor descriptor(isolate); - CodeStubAssemblerTester m(isolate, descriptor); - Handle undefined = isolate->factory()->undefined_value(); - m.Return(m.SmiTag(m.LoadInstanceType(m.HeapConstant(undefined)))); - Handle code = m.GenerateCode(); - FunctionTester ft(descriptor, code); - MaybeHandle result = ft.Call(); - CHECK_EQ(InstanceType::ODDBALL_TYPE, - Handle::cast(result.ToHandleChecked())->value()); -} - -namespace { - -class TestBitField : public BitField {}; - -} // namespace - -TEST(BitFieldDecode) { - Isolate* isolate(CcTest::InitIsolateOnce()); - VoidDescriptor descriptor(isolate); - CodeStubAssemblerTester m(isolate, descriptor); - m.Return(m.SmiTag(m.BitFieldDecode(m.Int32Constant(0x2f)))); - Handle code = m.GenerateCode(); - FunctionTester ft(descriptor, code); - MaybeHandle result = ft.Call(); - // value = 00101111 - // mask = 00111000 - // result = 101 - CHECK_EQ(5, Handle::cast(result.ToHandleChecked())->value()); -} - -namespace { - -Handle CreateFunctionFromCode(int parameter_count_with_receiver, - Handle code) { - Isolate* isolate = code->GetIsolate(); - Handle name = isolate->factory()->InternalizeUtf8String("test"); - Handle function = - isolate->factory()->NewFunctionWithoutPrototype(name, code); - function->shared()->set_internal_formal_parameter_count( - parameter_count_with_receiver - 1); // Implicit undefined receiver. - return function; -} - -} // namespace - -TEST(JSFunction) { - const int kNumParams = 3; // Receiver, left, right. - Isolate* isolate(CcTest::InitIsolateOnce()); - CodeStubAssemblerTester m(isolate, kNumParams); - m.Return(m.SmiTag(m.Int32Add(m.SmiToWord32(m.Parameter(1)), - m.SmiToWord32(m.Parameter(2))))); - Handle code = m.GenerateCode(); - Handle function = CreateFunctionFromCode(kNumParams, code); - Handle args[] = {Handle(Smi::FromInt(23), isolate), - Handle(Smi::FromInt(34), isolate)}; - MaybeHandle result = - Execution::Call(isolate, function, isolate->factory()->undefined_value(), - arraysize(args), args); - CHECK_EQ(57, Handle::cast(result.ToHandleChecked())->value()); -} - -TEST(SplitEdgeBranchMerge) { - Isolate* isolate(CcTest::InitIsolateOnce()); - VoidDescriptor descriptor(isolate); - CodeStubAssemblerTester m(isolate, descriptor); - CodeStubAssembler::Label l1(&m), merge(&m); - m.Branch(m.Int32Constant(1), &l1, &merge); - m.Bind(&l1); - m.Goto(&merge); - m.Bind(&merge); - USE(m.GenerateCode()); -} - -TEST(SplitEdgeSwitchMerge) { - Isolate* isolate(CcTest::InitIsolateOnce()); - VoidDescriptor descriptor(isolate); - CodeStubAssemblerTester m(isolate, descriptor); - CodeStubAssembler::Label l1(&m), l2(&m), l3(&m), default_label(&m); - CodeStubAssembler::Label* labels[] = {&l1, &l2}; - int32_t values[] = {1, 2}; - m.Branch(m.Int32Constant(1), &l3, &l1); - m.Bind(&l3); - m.Switch(m.Int32Constant(2), &default_label, values, labels, 2); - m.Bind(&l1); - m.Goto(&l2); - m.Bind(&l2); - m.Goto(&default_label); - m.Bind(&default_label); - USE(m.GenerateCode()); -} - -TEST(TestToConstant) { - Isolate* isolate(CcTest::InitIsolateOnce()); - VoidDescriptor descriptor(isolate); - CodeStubAssemblerTester m(isolate, descriptor); - int32_t value32; - int64_t value64; - Node* a = m.Int32Constant(5); - CHECK(m.ToInt32Constant(a, value32)); - CHECK(m.ToInt64Constant(a, value64)); - - a = m.Int64Constant(static_cast(1) << 32); - CHECK(!m.ToInt32Constant(a, value32)); - CHECK(m.ToInt64Constant(a, value64)); - - a = m.Int64Constant(13); - CHECK(m.ToInt32Constant(a, value32)); - CHECK(m.ToInt64Constant(a, value64)); - - a = m.UndefinedConstant(); - CHECK(!m.ToInt32Constant(a, value32)); - CHECK(!m.ToInt64Constant(a, value64)); - - a = m.UndefinedConstant(); - CHECK(!m.ToInt32Constant(a, value32)); - CHECK(!m.ToInt64Constant(a, value64)); -} - -TEST(ComputeIntegerHash) { - Isolate* isolate(CcTest::InitIsolateOnce()); - const int param_count = 2; - CodeStubAssemblerTester m(isolate, param_count); - m.Return(m.SmiFromWord32(m.ComputeIntegerHash( - m.SmiToWord32(m.Parameter(0)), m.SmiToWord32(m.Parameter(1))))); - - Handle code = m.GenerateCode(); - FunctionTester ft(code, param_count); - - Handle hash_seed = isolate->factory()->hash_seed(); - - base::RandomNumberGenerator rand_gen(FLAG_random_seed); - - for (int i = 0; i < 1024; i++) { - int k = rand_gen.NextInt(Smi::kMaxValue); - - Handle key(Smi::FromInt(k), isolate); - Handle result = ft.Call(key, hash_seed).ToHandleChecked(); - - uint32_t hash = ComputeIntegerHash(k, hash_seed->value()); - Smi* expected = Smi::FromInt(hash & Smi::kMaxValue); - CHECK_EQ(expected, Smi::cast(*result)); - } -} - -TEST(TryToName) { - typedef CodeStubAssembler::Label Label; - typedef CodeStubAssembler::Variable Variable; - Isolate* isolate(CcTest::InitIsolateOnce()); - - const int param_count = 3; - CodeStubAssemblerTester m(isolate, param_count); - - enum Result { kKeyIsIndex, kKeyIsUnique, kBailout }; - { - Node* key = m.Parameter(0); - Node* expected_result = m.Parameter(1); - Node* expected_arg = m.Parameter(2); - - Label passed(&m), failed(&m); - Label if_keyisindex(&m), if_keyisunique(&m), if_bailout(&m); - Variable var_index(&m, MachineRepresentation::kWord32); - - m.TryToName(key, &if_keyisindex, &var_index, &if_keyisunique, &if_bailout); - - m.Bind(&if_keyisindex); - m.GotoUnless( - m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kKeyIsIndex))), - &failed); - m.Branch(m.Word32Equal(m.SmiToWord32(expected_arg), var_index.value()), - &passed, &failed); - - m.Bind(&if_keyisunique); - m.GotoUnless( - m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kKeyIsUnique))), - &failed); - m.Branch(m.WordEqual(expected_arg, key), &passed, &failed); - - m.Bind(&if_bailout); - m.Branch( - m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))), - &passed, &failed); - - m.Bind(&passed); - m.Return(m.BooleanConstant(true)); - - m.Bind(&failed); - m.Return(m.BooleanConstant(false)); - } - - Handle code = m.GenerateCode(); - FunctionTester ft(code, param_count); - - Handle expect_index(Smi::FromInt(kKeyIsIndex), isolate); - Handle expect_unique(Smi::FromInt(kKeyIsUnique), isolate); - Handle expect_bailout(Smi::FromInt(kBailout), isolate); - - { - // TryToName() => if_keyisindex: smi value. - Handle key(Smi::FromInt(0), isolate); - ft.CheckTrue(key, expect_index, key); - } - - { - // TryToName() => if_keyisindex: smi value. - Handle key(Smi::FromInt(153), isolate); - ft.CheckTrue(key, expect_index, key); - } - - { - // TryToName() => bailout. - Handle key(Smi::FromInt(-1), isolate); - ft.CheckTrue(key, expect_bailout); - } - - { - // TryToName() => if_keyisunique: . - Handle key = isolate->factory()->NewSymbol(); - ft.CheckTrue(key, expect_unique, key); - } - - { - // TryToName() => if_keyisunique: - Handle key = isolate->factory()->InternalizeUtf8String("test"); - ft.CheckTrue(key, expect_unique, key); - } - - { - // TryToName() => if_keyisindex: number. - Handle key = isolate->factory()->InternalizeUtf8String("153"); - Handle index(Smi::FromInt(153), isolate); - ft.CheckTrue(key, expect_index, index); - } - - { - // TryToName() => bailout. - Handle key = isolate->factory()->NewStringFromAsciiChecked("test"); - ft.CheckTrue(key, expect_bailout); - } -} - -namespace { - -template -void TestNameDictionaryLookup() { - typedef CodeStubAssembler::Label Label; - typedef CodeStubAssembler::Variable Variable; - Isolate* isolate(CcTest::InitIsolateOnce()); - - const int param_count = 4; - CodeStubAssemblerTester m(isolate, param_count); - - enum Result { kFound, kNotFound }; - { - Node* dictionary = m.Parameter(0); - Node* unique_name = m.Parameter(1); - Node* expected_result = m.Parameter(2); - Node* expected_arg = m.Parameter(3); - - Label passed(&m), failed(&m); - Label if_found(&m), if_not_found(&m); - Variable var_entry(&m, MachineRepresentation::kWord32); - - m.NameDictionaryLookup(dictionary, unique_name, &if_found, - &var_entry, &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()), - &passed, &failed); - - m.Bind(&if_not_found); - m.Branch( - m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))), - &passed, &failed); - - m.Bind(&passed); - m.Return(m.BooleanConstant(true)); - - m.Bind(&failed); - m.Return(m.BooleanConstant(false)); - } - - Handle code = m.GenerateCode(); - FunctionTester ft(code, param_count); - - Handle expect_found(Smi::FromInt(kFound), isolate); - Handle expect_not_found(Smi::FromInt(kNotFound), isolate); - - Handle dictionary = Dictionary::New(isolate, 40); - PropertyDetails fake_details = PropertyDetails::Empty(); - - Factory* factory = isolate->factory(); - Handle keys[] = { - factory->InternalizeUtf8String("0"), - factory->InternalizeUtf8String("42"), - factory->InternalizeUtf8String("-153"), - factory->InternalizeUtf8String("0.0"), - factory->InternalizeUtf8String("4.2"), - factory->InternalizeUtf8String(""), - factory->InternalizeUtf8String("name"), - factory->NewSymbol(), - factory->NewPrivateSymbol(), - }; - - for (size_t i = 0; i < arraysize(keys); i++) { - Handle value = factory->NewPropertyCell(); - dictionary = Dictionary::Add(dictionary, keys[i], value, fake_details); - } - - for (size_t i = 0; i < arraysize(keys); i++) { - int entry = dictionary->FindEntry(keys[i]); - CHECK_NE(Dictionary::kNotFound, entry); - - Handle expected_entry(Smi::FromInt(entry), isolate); - ft.CheckTrue(dictionary, keys[i], expect_found, expected_entry); - } - - Handle non_existing_keys[] = { - factory->InternalizeUtf8String("1"), - factory->InternalizeUtf8String("-42"), - factory->InternalizeUtf8String("153"), - factory->InternalizeUtf8String("-1.0"), - factory->InternalizeUtf8String("1.3"), - factory->InternalizeUtf8String("a"), - factory->InternalizeUtf8String("boom"), - factory->NewSymbol(), - factory->NewPrivateSymbol(), - }; - - for (size_t i = 0; i < arraysize(non_existing_keys); i++) { - int entry = dictionary->FindEntry(non_existing_keys[i]); - CHECK_EQ(Dictionary::kNotFound, entry); - - ft.CheckTrue(dictionary, non_existing_keys[i], expect_not_found); - } -} - -} // namespace - -TEST(NameDictionaryLookup) { TestNameDictionaryLookup(); } - -TEST(GlobalDictionaryLookup) { TestNameDictionaryLookup(); } - -namespace { - -template -void TestNumberDictionaryLookup() { - typedef CodeStubAssembler::Label Label; - typedef CodeStubAssembler::Variable Variable; - Isolate* isolate(CcTest::InitIsolateOnce()); - - const int param_count = 4; - CodeStubAssemblerTester m(isolate, param_count); - - enum Result { kFound, kNotFound }; - { - Node* dictionary = m.Parameter(0); - Node* key = m.SmiToWord32(m.Parameter(1)); - Node* expected_result = m.Parameter(2); - Node* expected_arg = m.Parameter(3); - - Label passed(&m), failed(&m); - Label if_found(&m), if_not_found(&m); - Variable var_entry(&m, MachineRepresentation::kWord32); - - m.NumberDictionaryLookup(dictionary, key, &if_found, &var_entry, - &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()), - &passed, &failed); - - m.Bind(&if_not_found); - m.Branch( - m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))), - &passed, &failed); - - m.Bind(&passed); - m.Return(m.BooleanConstant(true)); - - m.Bind(&failed); - m.Return(m.BooleanConstant(false)); - } - - Handle code = m.GenerateCode(); - FunctionTester ft(code, param_count); - - Handle expect_found(Smi::FromInt(kFound), isolate); - Handle expect_not_found(Smi::FromInt(kNotFound), isolate); - - const int kKeysCount = 1000; - Handle dictionary = Dictionary::New(isolate, kKeysCount); - uint32_t keys[kKeysCount]; - - Handle fake_value(Smi::FromInt(42), isolate); - PropertyDetails fake_details = PropertyDetails::Empty(); - - base::RandomNumberGenerator rand_gen(FLAG_random_seed); - - for (int i = 0; i < kKeysCount; i++) { - int random_key = rand_gen.NextInt(Smi::kMaxValue); - keys[i] = static_cast(random_key); - - dictionary = Dictionary::Add(dictionary, keys[i], fake_value, fake_details); - } - - // Now try querying existing keys. - for (int i = 0; i < kKeysCount; i++) { - int entry = dictionary->FindEntry(keys[i]); - CHECK_NE(Dictionary::kNotFound, entry); - - Handle key(Smi::FromInt(keys[i]), isolate); - Handle expected_entry(Smi::FromInt(entry), isolate); - ft.CheckTrue(dictionary, key, expect_found, expected_entry); - } - - // Now try querying random keys which do not exist in the dictionary. - for (int i = 0; i < kKeysCount;) { - int random_key = rand_gen.NextInt(Smi::kMaxValue); - int entry = dictionary->FindEntry(random_key); - if (entry != Dictionary::kNotFound) continue; - i++; - - Handle key(Smi::FromInt(random_key), isolate); - ft.CheckTrue(dictionary, key, expect_not_found); - } -} - -} // namespace - -TEST(SeededNumberDictionaryLookup) { - TestNumberDictionaryLookup(); -} - -TEST(UnseededNumberDictionaryLookup) { - TestNumberDictionaryLookup(); -} - -namespace { - -void AddProperties(Handle object, Handle names[], - size_t count) { - Handle value(Smi::FromInt(42), object->GetIsolate()); - for (size_t i = 0; i < count; i++) { - JSObject::AddProperty(object, names[i], value, NONE); - } -} - -} // namespace - -TEST(TryLookupProperty) { - typedef CodeStubAssembler::Label Label; - Isolate* isolate(CcTest::InitIsolateOnce()); - - const int param_count = 4; - CodeStubAssemblerTester m(isolate, param_count); - - enum Result { kFound, kNotFound, kBailout }; - { - Node* object = m.Parameter(0); - Node* unique_name = m.Parameter(1); - Node* expected_result = m.Parameter(2); - - Label passed(&m), failed(&m); - Label if_found(&m), if_not_found(&m), if_bailout(&m); - - Node* map = m.LoadMap(object); - Node* instance_type = m.LoadMapInstanceType(map); - - m.TryLookupProperty(object, map, instance_type, unique_name, &if_found, - &if_not_found, &if_bailout); - - m.Bind(&if_found); - m.Branch(m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))), - &passed, &failed); - - m.Bind(&if_not_found); - m.Branch( - m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))), - &passed, &failed); - - m.Bind(&if_bailout); - m.Branch( - m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))), - &passed, &failed); - - m.Bind(&passed); - m.Return(m.BooleanConstant(true)); - - m.Bind(&failed); - m.Return(m.BooleanConstant(false)); - } - - Handle code = m.GenerateCode(); - FunctionTester ft(code, param_count); - - Handle expect_found(Smi::FromInt(kFound), isolate); - Handle expect_not_found(Smi::FromInt(kNotFound), isolate); - Handle expect_bailout(Smi::FromInt(kBailout), isolate); - - Factory* factory = isolate->factory(); - Handle names[] = { - factory->InternalizeUtf8String("a"), - factory->InternalizeUtf8String("bb"), - factory->InternalizeUtf8String("ccc"), - factory->InternalizeUtf8String("dddd"), - factory->InternalizeUtf8String("eeeee"), - factory->InternalizeUtf8String(""), - factory->InternalizeUtf8String("name"), - factory->NewSymbol(), - factory->NewPrivateSymbol(), - }; - - std::vector> objects; - - { - Handle function = factory->NewFunction(factory->empty_string()); - Handle object = factory->NewJSObject(function); - AddProperties(object, names, arraysize(names)); - CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type()); - CHECK(!object->map()->is_dictionary_map()); - objects.push_back(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"); - CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type()); - CHECK(object->map()->is_dictionary_map()); - objects.push_back(object); - } - - { - Handle function = factory->NewFunction(factory->empty_string()); - JSFunction::EnsureHasInitialMap(function); - function->initial_map()->set_instance_type(JS_GLOBAL_OBJECT_TYPE); - function->initial_map()->set_is_prototype_map(true); - function->initial_map()->set_dictionary_map(true); - Handle object = factory->NewJSGlobalObject(function); - AddProperties(object, names, arraysize(names)); - CHECK_EQ(JS_GLOBAL_OBJECT_TYPE, object->map()->instance_type()); - CHECK(object->map()->is_dictionary_map()); - objects.push_back(object); - } - - { - for (Handle object : objects) { - for (size_t name_index = 0; name_index < arraysize(names); name_index++) { - Handle name = names[name_index]; - CHECK(JSReceiver::HasProperty(object, name).FromJust()); - ft.CheckTrue(object, name, expect_found); - } - } - } - - { - Handle non_existing_names[] = { - factory->InternalizeUtf8String("ne_a"), - factory->InternalizeUtf8String("ne_bb"), - factory->InternalizeUtf8String("ne_ccc"), - factory->InternalizeUtf8String("ne_dddd"), - }; - 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 function = factory->NewFunction(factory->empty_string()); - Handle object = factory->NewJSProxy(function, objects[0]); - CHECK_EQ(JS_PROXY_TYPE, object->map()->instance_type()); - ft.CheckTrue(object, names[0], expect_bailout); - } - - { - Handle object = isolate->global_proxy(); - CHECK_EQ(JS_GLOBAL_PROXY_TYPE, object->map()->instance_type()); - ft.CheckTrue(object, names[0], expect_bailout); - } -} - -namespace { - -void AddElement(Handle object, uint32_t index, Handle value, - PropertyAttributes attributes = NONE) { - JSObject::AddDataElement(object, index, value, attributes).ToHandleChecked(); -} - -} // namespace - -TEST(TryLookupElement) { - typedef CodeStubAssembler::Label Label; - Isolate* isolate(CcTest::InitIsolateOnce()); - - const int param_count = 4; - CodeStubAssemblerTester m(isolate, param_count); - - enum Result { kFound, kNotFound, kBailout }; - { - Node* object = m.Parameter(0); - Node* index = m.SmiToWord32(m.Parameter(1)); - Node* expected_result = m.Parameter(2); - - Label passed(&m), failed(&m); - Label if_found(&m), if_not_found(&m), if_bailout(&m); - - Node* map = m.LoadMap(object); - Node* instance_type = m.LoadMapInstanceType(map); - - m.TryLookupElement(object, map, instance_type, index, &if_found, - &if_not_found, &if_bailout); - - m.Bind(&if_found); - m.Branch(m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))), - &passed, &failed); - - m.Bind(&if_not_found); - m.Branch( - m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))), - &passed, &failed); - - m.Bind(&if_bailout); - m.Branch( - m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))), - &passed, &failed); - - m.Bind(&passed); - m.Return(m.BooleanConstant(true)); - - m.Bind(&failed); - m.Return(m.BooleanConstant(false)); - } - - Handle code = m.GenerateCode(); - FunctionTester ft(code, param_count); - - Factory* factory = isolate->factory(); - Handle smi0(Smi::FromInt(0), isolate); - Handle smi1(Smi::FromInt(1), isolate); - Handle smi7(Smi::FromInt(7), isolate); - Handle smi13(Smi::FromInt(13), isolate); - Handle smi42(Smi::FromInt(42), isolate); - - Handle expect_found(Smi::FromInt(kFound), isolate); - Handle expect_not_found(Smi::FromInt(kNotFound), isolate); - Handle expect_bailout(Smi::FromInt(kBailout), isolate); - -#define CHECK_FOUND(object, index) \ - CHECK(JSReceiver::HasElement(object, index).FromJust()); \ - ft.CheckTrue(object, smi##index, expect_found); - -#define CHECK_NOT_FOUND(object, index) \ - CHECK(!JSReceiver::HasElement(object, index).FromJust()); \ - ft.CheckTrue(object, smi##index, expect_not_found); - - { - Handle object = factory->NewJSArray(0, FAST_SMI_ELEMENTS); - AddElement(object, 0, smi0); - AddElement(object, 1, smi0); - CHECK_EQ(FAST_SMI_ELEMENTS, object->map()->elements_kind()); - - CHECK_FOUND(object, 0); - CHECK_FOUND(object, 1); - CHECK_NOT_FOUND(object, 7); - CHECK_NOT_FOUND(object, 13); - CHECK_NOT_FOUND(object, 42); - } - - { - Handle object = factory->NewJSArray(0, FAST_HOLEY_SMI_ELEMENTS); - AddElement(object, 0, smi0); - AddElement(object, 13, smi0); - CHECK_EQ(FAST_HOLEY_SMI_ELEMENTS, object->map()->elements_kind()); - - CHECK_FOUND(object, 0); - CHECK_NOT_FOUND(object, 1); - CHECK_NOT_FOUND(object, 7); - CHECK_FOUND(object, 13); - CHECK_NOT_FOUND(object, 42); - } - - { - Handle object = factory->NewJSArray(0, FAST_ELEMENTS); - AddElement(object, 0, smi0); - AddElement(object, 1, smi0); - CHECK_EQ(FAST_ELEMENTS, object->map()->elements_kind()); - - CHECK_FOUND(object, 0); - CHECK_FOUND(object, 1); - CHECK_NOT_FOUND(object, 7); - CHECK_NOT_FOUND(object, 13); - CHECK_NOT_FOUND(object, 42); - } - - { - Handle object = factory->NewJSArray(0, FAST_HOLEY_ELEMENTS); - AddElement(object, 0, smi0); - AddElement(object, 13, smi0); - CHECK_EQ(FAST_HOLEY_ELEMENTS, object->map()->elements_kind()); - - CHECK_FOUND(object, 0); - CHECK_NOT_FOUND(object, 1); - CHECK_NOT_FOUND(object, 7); - CHECK_FOUND(object, 13); - CHECK_NOT_FOUND(object, 42); - } - - { - Handle constructor = isolate->string_function(); - Handle object = factory->NewJSObject(constructor); - Handle str = factory->InternalizeUtf8String("ab"); - Handle::cast(object)->set_value(*str); - AddElement(object, 13, smi0); - CHECK_EQ(FAST_STRING_WRAPPER_ELEMENTS, object->map()->elements_kind()); - - CHECK_FOUND(object, 0); - CHECK_FOUND(object, 1); - CHECK_NOT_FOUND(object, 7); - CHECK_FOUND(object, 13); - CHECK_NOT_FOUND(object, 42); - } - - { - Handle constructor = isolate->string_function(); - Handle object = factory->NewJSObject(constructor); - Handle str = factory->InternalizeUtf8String("ab"); - Handle::cast(object)->set_value(*str); - AddElement(object, 13, smi0); - JSObject::NormalizeElements(object); - CHECK_EQ(SLOW_STRING_WRAPPER_ELEMENTS, object->map()->elements_kind()); - - CHECK_FOUND(object, 0); - CHECK_FOUND(object, 1); - CHECK_NOT_FOUND(object, 7); - CHECK_FOUND(object, 13); - CHECK_NOT_FOUND(object, 42); - } - -// TODO(ishell): uncomment once NO_ELEMENTS kind is supported. -// { -// Handle map = Map::Create(isolate, 0); -// map->set_elements_kind(NO_ELEMENTS); -// Handle object = factory->NewJSObjectFromMap(map); -// CHECK_EQ(NO_ELEMENTS, object->map()->elements_kind()); -// -// CHECK_NOT_FOUND(object, 0); -// CHECK_NOT_FOUND(object, 1); -// CHECK_NOT_FOUND(object, 7); -// CHECK_NOT_FOUND(object, 13); -// CHECK_NOT_FOUND(object, 42); -// } - -#undef CHECK_FOUND -#undef CHECK_NOT_FOUND - - { - Handle handler = factory->NewJSArray(0); - Handle function = factory->NewFunction(factory->empty_string()); - Handle object = factory->NewJSProxy(function, handler); - CHECK_EQ(JS_PROXY_TYPE, object->map()->instance_type()); - ft.CheckTrue(object, smi0, expect_bailout); - } - - { - Handle object = isolate->global_object(); - CHECK_EQ(JS_GLOBAL_OBJECT_TYPE, object->map()->instance_type()); - ft.CheckTrue(object, smi0, expect_bailout); - } - - { - Handle object = isolate->global_proxy(); - CHECK_EQ(JS_GLOBAL_PROXY_TYPE, object->map()->instance_type()); - ft.CheckTrue(object, smi0, expect_bailout); - } -} - -} // namespace internal -} // namespace v8