Chromium Code Reviews| 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 |