OLD | NEW |
---|---|
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/code-stub-assembler.h" | 5 #include "src/code-stub-assembler.h" |
6 #include "src/code-factory.h" | 6 #include "src/code-factory.h" |
7 #include "src/frames-inl.h" | 7 #include "src/frames-inl.h" |
8 #include "src/frames.h" | 8 #include "src/frames.h" |
9 #include "src/ic/handler-configuration.h" | 9 #include "src/ic/handler-configuration.h" |
10 #include "src/ic/stub-cache.h" | 10 #include "src/ic/stub-cache.h" |
(...skipping 742 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
753 // The {value} is a HeapObject, load its map. | 753 // The {value} is a HeapObject, load its map. |
754 Node* value_map = LoadMap(value); | 754 Node* value_map = LoadMap(value); |
755 | 755 |
756 // Load the {value}s instance type. | 756 // Load the {value}s instance type. |
757 Node* value_instance_type = LoadMapInstanceType(value_map); | 757 Node* value_instance_type = LoadMapInstanceType(value_map); |
758 | 758 |
759 // Dispatch based on the instance type; we distinguish all String instance | 759 // Dispatch based on the instance type; we distinguish all String instance |
760 // types, the HeapNumber type and everything else. | 760 // types, the HeapNumber type and everything else. |
761 GotoIf(Word32Equal(value_instance_type, Int32Constant(HEAP_NUMBER_TYPE)), | 761 GotoIf(Word32Equal(value_instance_type, Int32Constant(HEAP_NUMBER_TYPE)), |
762 &if_valueisheapnumber); | 762 &if_valueisheapnumber); |
763 Branch( | 763 Branch(IsStringInstanceType(value_instance_type), &if_valueisstring, |
764 Int32LessThan(value_instance_type, Int32Constant(FIRST_NONSTRING_TYPE)), | 764 &if_valueisother); |
765 &if_valueisstring, &if_valueisother); | |
766 | 765 |
767 Bind(&if_valueisstring); | 766 Bind(&if_valueisstring); |
768 { | 767 { |
769 // Load the string length field of the {value}. | 768 // Load the string length field of the {value}. |
770 Node* value_length = LoadObjectField(value, String::kLengthOffset); | 769 Node* value_length = LoadObjectField(value, String::kLengthOffset); |
771 | 770 |
772 // Check if the {value} is the empty string. | 771 // Check if the {value} is the empty string. |
773 BranchIfSmiEqual(value_length, SmiConstant(0), if_false, if_true); | 772 BranchIfSmiEqual(value_length, SmiConstant(0), if_false, if_true); |
774 } | 773 } |
775 | 774 |
(...skipping 1300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2076 Label if_valueissmi(this, Label::kDeferred), if_valueisnotsmi(this), | 2075 Label if_valueissmi(this, Label::kDeferred), if_valueisnotsmi(this), |
2077 if_valueisstring(this); | 2076 if_valueisstring(this); |
2078 Branch(WordIsSmi(value), &if_valueissmi, &if_valueisnotsmi); | 2077 Branch(WordIsSmi(value), &if_valueissmi, &if_valueisnotsmi); |
2079 Bind(&if_valueisnotsmi); | 2078 Bind(&if_valueisnotsmi); |
2080 { | 2079 { |
2081 // Load the instance type of the {value}. | 2080 // Load the instance type of the {value}. |
2082 Node* value_instance_type = LoadInstanceType(value); | 2081 Node* value_instance_type = LoadInstanceType(value); |
2083 | 2082 |
2084 // Check if the {value} is already String. | 2083 // Check if the {value} is already String. |
2085 Label if_valueisnotstring(this, Label::kDeferred); | 2084 Label if_valueisnotstring(this, Label::kDeferred); |
2086 Branch( | 2085 Branch(IsStringInstanceType(value_instance_type), &if_valueisstring, |
2087 Int32LessThan(value_instance_type, Int32Constant(FIRST_NONSTRING_TYPE)), | 2086 &if_valueisnotstring); |
2088 &if_valueisstring, &if_valueisnotstring); | |
2089 Bind(&if_valueisnotstring); | 2087 Bind(&if_valueisnotstring); |
2090 { | 2088 { |
2091 // Check if the {value} is null. | 2089 // Check if the {value} is null. |
2092 Label if_valueisnullorundefined(this, Label::kDeferred), | 2090 Label if_valueisnullorundefined(this, Label::kDeferred), |
2093 if_valueisnotnullorundefined(this, Label::kDeferred), | 2091 if_valueisnotnullorundefined(this, Label::kDeferred), |
2094 if_valueisnotnull(this, Label::kDeferred); | 2092 if_valueisnotnull(this, Label::kDeferred); |
2095 Branch(WordEqual(value, NullConstant()), &if_valueisnullorundefined, | 2093 Branch(WordEqual(value, NullConstant()), &if_valueisnullorundefined, |
2096 &if_valueisnotnull); | 2094 &if_valueisnotnull); |
2097 Bind(&if_valueisnotnull); | 2095 Bind(&if_valueisnotnull); |
2098 { | 2096 { |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2171 switch (primitive_type) { | 2169 switch (primitive_type) { |
2172 case PrimitiveType::kBoolean: | 2170 case PrimitiveType::kBoolean: |
2173 GotoIf(WordEqual(value_map, BooleanMapConstant()), &done_loop); | 2171 GotoIf(WordEqual(value_map, BooleanMapConstant()), &done_loop); |
2174 break; | 2172 break; |
2175 case PrimitiveType::kNumber: | 2173 case PrimitiveType::kNumber: |
2176 GotoIf( | 2174 GotoIf( |
2177 Word32Equal(value_instance_type, Int32Constant(HEAP_NUMBER_TYPE)), | 2175 Word32Equal(value_instance_type, Int32Constant(HEAP_NUMBER_TYPE)), |
2178 &done_loop); | 2176 &done_loop); |
2179 break; | 2177 break; |
2180 case PrimitiveType::kString: | 2178 case PrimitiveType::kString: |
2181 GotoIf(Int32LessThan(value_instance_type, | 2179 GotoIf(IsStringInstanceType(value_instance_type), &done_loop); |
2182 Int32Constant(FIRST_NONSTRING_TYPE)), | |
2183 &done_loop); | |
2184 break; | 2180 break; |
2185 case PrimitiveType::kSymbol: | 2181 case PrimitiveType::kSymbol: |
2186 GotoIf(Word32Equal(value_instance_type, Int32Constant(SYMBOL_TYPE)), | 2182 GotoIf(Word32Equal(value_instance_type, Int32Constant(SYMBOL_TYPE)), |
2187 &done_loop); | 2183 &done_loop); |
2188 break; | 2184 break; |
2189 } | 2185 } |
2190 Goto(&done_throw); | 2186 Goto(&done_throw); |
2191 } | 2187 } |
2192 } | 2188 } |
2193 | 2189 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2225 Runtime::kThrowIncompatibleMethodReceiver, context, | 2221 Runtime::kThrowIncompatibleMethodReceiver, context, |
2226 HeapConstant(factory()->NewStringFromAsciiChecked(method_name, TENURED)), | 2222 HeapConstant(factory()->NewStringFromAsciiChecked(method_name, TENURED)), |
2227 value); | 2223 value); |
2228 var_value_map.Bind(UndefinedConstant()); | 2224 var_value_map.Bind(UndefinedConstant()); |
2229 Goto(&out); // Never reached. | 2225 Goto(&out); // Never reached. |
2230 | 2226 |
2231 Bind(&out); | 2227 Bind(&out); |
2232 return var_value_map.value(); | 2228 return var_value_map.value(); |
2233 } | 2229 } |
2234 | 2230 |
2231 Node* CodeStubAssembler::IsStringInstanceType(Node* instance_type) { | |
2232 STATIC_ASSERT(INTERNALIZED_STRING_TYPE == FIRST_TYPE); | |
2233 return Int32LessThan(instance_type, Int32Constant(FIRST_NONSTRING_TYPE)); | |
2234 } | |
2235 | |
2236 Node* CodeStubAssembler::IsJSReceiverInstanceType(Node* instance_type) { | |
2237 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); | |
2238 return Int32GreaterThanOrEqual(instance_type, | |
2239 Int32Constant(FIRST_JS_RECEIVER_TYPE)); | |
2240 } | |
2241 | |
2235 Node* CodeStubAssembler::StringCharCodeAt(Node* string, Node* index) { | 2242 Node* CodeStubAssembler::StringCharCodeAt(Node* string, Node* index) { |
2236 // Translate the {index} into a Word. | 2243 // Translate the {index} into a Word. |
2237 index = SmiToWord(index); | 2244 index = SmiToWord(index); |
2238 | 2245 |
2239 // We may need to loop in case of cons or sliced strings. | 2246 // We may need to loop in case of cons or sliced strings. |
2240 Variable var_index(this, MachineType::PointerRepresentation()); | 2247 Variable var_index(this, MachineType::PointerRepresentation()); |
2241 Variable var_result(this, MachineRepresentation::kWord32); | 2248 Variable var_result(this, MachineRepresentation::kWord32); |
2242 Variable var_string(this, MachineRepresentation::kTagged); | 2249 Variable var_string(this, MachineRepresentation::kTagged); |
2243 Variable* loop_vars[] = {&var_index, &var_string}; | 2250 Variable* loop_vars[] = {&var_index, &var_string}; |
2244 Label done_loop(this, &var_result), loop(this, 2, loop_vars); | 2251 Label done_loop(this, &var_result), loop(this, 2, loop_vars); |
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2530 // Make sure first argument is a string. | 2537 // Make sure first argument is a string. |
2531 | 2538 |
2532 // Bailout if receiver is a Smi. | 2539 // Bailout if receiver is a Smi. |
2533 GotoIf(WordIsSmi(string), &runtime); | 2540 GotoIf(WordIsSmi(string), &runtime); |
2534 | 2541 |
2535 // Load the instance type of the {string}. | 2542 // Load the instance type of the {string}. |
2536 Node* const instance_type = LoadInstanceType(string); | 2543 Node* const instance_type = LoadInstanceType(string); |
2537 var_instance_type.Bind(instance_type); | 2544 var_instance_type.Bind(instance_type); |
2538 | 2545 |
2539 // Check if {string} is a String. | 2546 // Check if {string} is a String. |
2540 GotoIf(Int32GreaterThanOrEqual(instance_type, | 2547 GotoUnless(IsStringInstanceType(instance_type), &runtime); |
2541 Int32Constant(FIRST_NONSTRING_TYPE)), | |
2542 &runtime); | |
2543 | 2548 |
2544 // Make sure that both from and to are non-negative smis. | 2549 // Make sure that both from and to are non-negative smis. |
2545 | 2550 |
2546 GotoUnless(WordIsPositiveSmi(from), &runtime); | 2551 GotoUnless(WordIsPositiveSmi(from), &runtime); |
2547 GotoUnless(WordIsPositiveSmi(to), &runtime); | 2552 GotoUnless(WordIsPositiveSmi(to), &runtime); |
2548 | 2553 |
2549 Node* const substr_length = SmiSub(to, from); | 2554 Node* const substr_length = SmiSub(to, from); |
2550 Node* const string_length = LoadStringLength(string); | 2555 Node* const string_length = LoadStringLength(string); |
2551 | 2556 |
2552 // Begin dispatching based on substring length. | 2557 // Begin dispatching based on substring length. |
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2878 Bind(&loop); | 2883 Bind(&loop); |
2879 { | 2884 { |
2880 // Load the current {input} value (known to be a HeapObject). | 2885 // Load the current {input} value (known to be a HeapObject). |
2881 Node* input = var_input.value(); | 2886 Node* input = var_input.value(); |
2882 | 2887 |
2883 // Dispatch on the {input} instance type. | 2888 // Dispatch on the {input} instance type. |
2884 Node* input_instance_type = LoadInstanceType(input); | 2889 Node* input_instance_type = LoadInstanceType(input); |
2885 Label if_inputisstring(this), if_inputisoddball(this), | 2890 Label if_inputisstring(this), if_inputisoddball(this), |
2886 if_inputisreceiver(this, Label::kDeferred), | 2891 if_inputisreceiver(this, Label::kDeferred), |
2887 if_inputisother(this, Label::kDeferred); | 2892 if_inputisother(this, Label::kDeferred); |
2888 GotoIf( | 2893 GotoIf(IsStringInstanceType(input_instance_type), &if_inputisstring); |
2889 Int32LessThan(input_instance_type, Int32Constant(FIRST_NONSTRING_TYPE)), | |
2890 &if_inputisstring); | |
2891 GotoIf(Word32Equal(input_instance_type, Int32Constant(ODDBALL_TYPE)), | 2894 GotoIf(Word32Equal(input_instance_type, Int32Constant(ODDBALL_TYPE)), |
2892 &if_inputisoddball); | 2895 &if_inputisoddball); |
2893 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); | 2896 Branch(IsJSReceiverInstanceType(input_instance_type), &if_inputisreceiver, |
2894 Branch(Int32GreaterThanOrEqual(input_instance_type, | 2897 &if_inputisother); |
2895 Int32Constant(FIRST_JS_RECEIVER_TYPE)), | |
2896 &if_inputisreceiver, &if_inputisother); | |
2897 | 2898 |
2898 Bind(&if_inputisstring); | 2899 Bind(&if_inputisstring); |
2899 { | 2900 { |
2900 // The {input} is a String, use the fast stub to convert it to a Number. | 2901 // The {input} is a String, use the fast stub to convert it to a Number. |
2901 var_result.Bind(StringToNumber(context, input)); | 2902 var_result.Bind(StringToNumber(context, input)); |
2902 Goto(&end); | 2903 Goto(&end); |
2903 } | 2904 } |
2904 | 2905 |
2905 Bind(&if_inputisoddball); | 2906 Bind(&if_inputisoddball); |
2906 { | 2907 { |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3095 // Handle Smi and HeapNumber keys. | 3096 // Handle Smi and HeapNumber keys. |
3096 var_index->Bind(TryToIntptr(key, &if_keyisnotindex)); | 3097 var_index->Bind(TryToIntptr(key, &if_keyisnotindex)); |
3097 Goto(if_keyisindex); | 3098 Goto(if_keyisindex); |
3098 | 3099 |
3099 Bind(&if_keyisnotindex); | 3100 Bind(&if_keyisnotindex); |
3100 Node* key_instance_type = LoadInstanceType(key); | 3101 Node* key_instance_type = LoadInstanceType(key); |
3101 // Symbols are unique. | 3102 // Symbols are unique. |
3102 GotoIf(Word32Equal(key_instance_type, Int32Constant(SYMBOL_TYPE)), | 3103 GotoIf(Word32Equal(key_instance_type, Int32Constant(SYMBOL_TYPE)), |
3103 if_keyisunique); | 3104 if_keyisunique); |
3104 // Miss if |key| is not a String. | 3105 // Miss if |key| is not a String. |
3105 STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE); | 3106 STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE); |
Igor Sheludko
2016/10/05 08:02:27
You can now remove this assert from here.
| |
3106 GotoIf( | 3107 GotoUnless(IsStringInstanceType(key_instance_type), if_bailout); |
jgruber
2016/10/04 13:35:54
Igor: I'm assuming the original code was bugged (s
Igor Sheludko
2016/10/05 08:02:27
FIRST_NONSTRING_TYPE is actually a SYMBOL_TYPE whi
| |
3107 Int32GreaterThan(key_instance_type, Int32Constant(FIRST_NONSTRING_TYPE)), | |
3108 if_bailout); | |
3109 // |key| is a String. Check if it has a cached array index. | 3108 // |key| is a String. Check if it has a cached array index. |
3110 Node* hash = LoadNameHashField(key); | 3109 Node* hash = LoadNameHashField(key); |
3111 Node* contains_index = | 3110 Node* contains_index = |
3112 Word32And(hash, Int32Constant(Name::kContainsCachedArrayIndexMask)); | 3111 Word32And(hash, Int32Constant(Name::kContainsCachedArrayIndexMask)); |
3113 GotoIf(Word32Equal(contains_index, Int32Constant(0)), &if_hascachedindex); | 3112 GotoIf(Word32Equal(contains_index, Int32Constant(0)), &if_hascachedindex); |
3114 // No cached array index. If the string knows that it contains an index, | 3113 // No cached array index. If the string knows that it contains an index, |
3115 // then it must be an uncacheable index. Handle this case in the runtime. | 3114 // then it must be an uncacheable index. Handle this case in the runtime. |
3116 Node* not_an_index = | 3115 Node* not_an_index = |
3117 Word32And(hash, Int32Constant(Name::kIsNotArrayIndexMask)); | 3116 Word32And(hash, Int32Constant(Name::kIsNotArrayIndexMask)); |
3118 GotoIf(Word32Equal(not_an_index, Int32Constant(0)), if_bailout); | 3117 GotoIf(Word32Equal(not_an_index, Int32Constant(0)), if_bailout); |
(...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3745 { | 3744 { |
3746 Variable var_entry(this, MachineType::PointerRepresentation()); | 3745 Variable var_entry(this, MachineType::PointerRepresentation()); |
3747 Node* elements = LoadElements(object); | 3746 Node* elements = LoadElements(object); |
3748 NumberDictionaryLookup<SeededNumberDictionary>( | 3747 NumberDictionaryLookup<SeededNumberDictionary>( |
3749 elements, intptr_index, if_found, &var_entry, if_not_found); | 3748 elements, intptr_index, if_found, &var_entry, if_not_found); |
3750 } | 3749 } |
3751 Bind(&if_isfaststringwrapper); | 3750 Bind(&if_isfaststringwrapper); |
3752 { | 3751 { |
3753 AssertInstanceType(object, JS_VALUE_TYPE); | 3752 AssertInstanceType(object, JS_VALUE_TYPE); |
3754 Node* string = LoadJSValueValue(object); | 3753 Node* string = LoadJSValueValue(object); |
3755 Assert(Int32LessThan(LoadInstanceType(string), | 3754 Assert(IsStringInstanceType(LoadInstanceType(string))); |
3756 Int32Constant(FIRST_NONSTRING_TYPE))); | |
3757 Node* length = LoadStringLength(string); | 3755 Node* length = LoadStringLength(string); |
3758 GotoIf(UintPtrLessThan(intptr_index, SmiUntag(length)), if_found); | 3756 GotoIf(UintPtrLessThan(intptr_index, SmiUntag(length)), if_found); |
3759 Goto(&if_isobjectorsmi); | 3757 Goto(&if_isobjectorsmi); |
3760 } | 3758 } |
3761 Bind(&if_isslowstringwrapper); | 3759 Bind(&if_isslowstringwrapper); |
3762 { | 3760 { |
3763 AssertInstanceType(object, JS_VALUE_TYPE); | 3761 AssertInstanceType(object, JS_VALUE_TYPE); |
3764 Node* string = LoadJSValueValue(object); | 3762 Node* string = LoadJSValueValue(object); |
3765 Assert(Int32LessThan(LoadInstanceType(string), | 3763 Assert(IsStringInstanceType(LoadInstanceType(string))); |
3766 Int32Constant(FIRST_NONSTRING_TYPE))); | |
3767 Node* length = LoadStringLength(string); | 3764 Node* length = LoadStringLength(string); |
3768 GotoIf(UintPtrLessThan(intptr_index, SmiUntag(length)), if_found); | 3765 GotoIf(UintPtrLessThan(intptr_index, SmiUntag(length)), if_found); |
3769 Goto(&if_isdictionary); | 3766 Goto(&if_isdictionary); |
3770 } | 3767 } |
3771 Bind(&if_oob); | 3768 Bind(&if_oob); |
3772 { | 3769 { |
3773 // Positive OOB indices mean "not found", negative indices must be | 3770 // Positive OOB indices mean "not found", negative indices must be |
3774 // converted to property names. | 3771 // converted to property names. |
3775 GotoIf(IntPtrLessThan(intptr_index, IntPtrConstant(0)), if_bailout); | 3772 GotoIf(IntPtrLessThan(intptr_index, IntPtrConstant(0)), if_bailout); |
3776 Goto(if_not_found); | 3773 Goto(if_not_found); |
(...skipping 1918 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5695 Heap::kTheHoleValueRootIndex); | 5692 Heap::kTheHoleValueRootIndex); |
5696 | 5693 |
5697 // Store the WeakCell in the feedback vector. | 5694 // Store the WeakCell in the feedback vector. |
5698 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, | 5695 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, |
5699 CodeStubAssembler::SMI_PARAMETERS); | 5696 CodeStubAssembler::SMI_PARAMETERS); |
5700 return cell; | 5697 return cell; |
5701 } | 5698 } |
5702 | 5699 |
5703 } // namespace internal | 5700 } // namespace internal |
5704 } // namespace v8 | 5701 } // namespace v8 |
OLD | NEW |