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-compiler.h" | |
9 #include "src/ic/stub-cache.h" | 10 #include "src/ic/stub-cache.h" |
10 | 11 |
11 namespace v8 { | 12 namespace v8 { |
12 namespace internal { | 13 namespace internal { |
13 | 14 |
14 using compiler::Node; | 15 using compiler::Node; |
15 | 16 |
16 CodeStubAssembler::CodeStubAssembler(Isolate* isolate, Zone* zone, | 17 CodeStubAssembler::CodeStubAssembler(Isolate* isolate, Zone* zone, |
17 const CallInterfaceDescriptor& descriptor, | 18 const CallInterfaceDescriptor& descriptor, |
18 Code::Flags flags, const char* name, | 19 Code::Flags flags, const char* name, |
(...skipping 2951 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2970 receiver_map, if_handler, var_handler, &miss); | 2971 receiver_map, if_handler, var_handler, &miss); |
2971 } | 2972 } |
2972 | 2973 |
2973 Bind(&miss); | 2974 Bind(&miss); |
2974 { | 2975 { |
2975 IncrementCounter(counters->megamorphic_stub_cache_misses(), 1); | 2976 IncrementCounter(counters->megamorphic_stub_cache_misses(), 1); |
2976 Goto(if_miss); | 2977 Goto(if_miss); |
2977 } | 2978 } |
2978 } | 2979 } |
2979 | 2980 |
2980 void CodeStubAssembler::HandleLoadICHandlerCase(const LoadICParameters* p, | 2981 void CodeStubAssembler::HandleLoadICHandlerCase( |
2981 Node* handler, Label* miss) { | 2982 const LoadICParameters* p, Node* handler, Label* miss, |
2983 ElementSupport support_elements) { | |
2982 Comment("have_handler"); | 2984 Comment("have_handler"); |
2983 Label call_handler(this); | 2985 Label call_handler(this); |
2984 GotoUnless(WordIsSmi(handler), &call_handler); | 2986 GotoUnless(WordIsSmi(handler), &call_handler); |
2985 | 2987 |
2986 // |handler| is a Smi. It encodes a field index as obtained by | 2988 // |handler| is a Smi, encoding what to do. The last bit distinguishes |
2987 // FieldIndex.GetLoadByFieldOffset(). | 2989 // element and property loads. |
2988 // TODO(jkummerow): For KeyedLoadICs, extend this scheme to encode | |
2989 // fast *element* loads. | |
2990 { | 2990 { |
2991 Variable var_double_value(this, MachineRepresentation::kFloat64); | 2991 Variable var_double_value(this, MachineRepresentation::kFloat64); |
2992 Label rebox_double(this, &var_double_value); | 2992 Label rebox_double(this, &var_double_value); |
2993 | 2993 |
2994 Node* handler_word = SmiUntag(handler); | 2994 Node* handler_word = SmiUntag(handler); |
2995 if (support_elements == kSupportElements) { | |
Igor Sheludko
2016/07/28 10:01:11
I think this new code (and maybe the property case
Jakob Kummerow
2016/08/03 11:44:11
Done (did some splitting, though not exactly here)
| |
2996 Variable var_length(this, MachineRepresentation::kTagged); | |
2997 Label property(this), is_array(this), length_loaded(this, &var_length); | |
2998 Node* is_element_bit = WordAnd(handler_word, IntPtrConstant(1)); | |
Igor Sheludko
2016/07/28 10:01:11
It would be nice to have such a SmiHandlerIsProper
Jakob Kummerow
2016/08/03 11:44:09
Done.
| |
2999 GotoUnless(WordEqual(is_element_bit, IntPtrConstant(0)), &property); | |
3000 | |
3001 Comment("element_load"); | |
3002 GotoUnless(WordIsSmi(p->name), miss); | |
Igor Sheludko
2016/07/28 10:01:11
Future improvement: support "123"-like unique stri
Jakob Kummerow
2016/08/03 11:44:09
Possibly, yes. That change would have to be made i
| |
3003 Node* key = SmiUntag(p->name); | |
3004 Node* elements = LoadElements(p->receiver); | |
3005 Node* is_jsarray = WordAnd( | |
3006 handler_word, | |
3007 IntPtrConstant(ElementHandlerCompiler::KeyedLoadIsJsarray::kMask)); | |
3008 GotoUnless(WordEqual(is_jsarray, IntPtrConstant(0)), &is_array); | |
3009 var_length.Bind(SmiUntag(LoadFixedArrayBaseLength(elements))); | |
3010 Goto(&length_loaded); | |
3011 Bind(&is_array); | |
Igor Sheludko
2016/07/28 10:01:11
Consider wrapping blocks in {} for readability.
Jakob Kummerow
2016/08/03 11:44:09
Done.
| |
3012 var_length.Bind( | |
3013 SmiUntag(LoadObjectField(p->receiver, JSArray::kLengthOffset))); | |
3014 Goto(&length_loaded); | |
3015 | |
3016 Bind(&length_loaded); | |
Igor Sheludko
2016/07/28 10:01:11
Same here.
Jakob Kummerow
2016/08/03 11:44:12
Done.
| |
3017 // Bounds check. | |
3018 GotoUnless(UintPtrLessThan(key, var_length.value()), miss); | |
3019 Node* convert_hole = WordAnd( | |
Igor Sheludko
2016/07/28 10:01:11
You can probably move this to if_hole block althou
Jakob Kummerow
2016/08/03 11:44:11
Done.
| |
3020 handler_word, | |
3021 IntPtrConstant(ElementHandlerCompiler::KeyedLoadConvertHole::kMask)); | |
3022 Node* elements_kind = | |
3023 WordShr(handler_word, | |
3024 IntPtrConstant( | |
3025 ElementHandlerCompiler::KeyedLoadElementsKind::kShift)); | |
3026 | |
3027 Label typed_array(this), fast_packed(this), fast_holey(this), | |
Igor Sheludko
2016/07/28 10:01:10
As far as I understand we have a kind of naming co
Jakob Kummerow
2016/08/03 11:44:11
Done.
| |
3028 fast_double(this), fast_holey_double(this), hole(this); | |
Igor Sheludko
2016/07/28 10:01:11
STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYP
Jakob Kummerow
2016/08/03 11:44:11
Done.
| |
3029 GotoIf(IntPtrGreaterThanOrEqual( | |
3030 elements_kind, | |
3031 IntPtrConstant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)), | |
3032 &typed_array); | |
3033 #define JUMP_IF_KIND(kind, label) \ | |
3034 GotoIf(WordEqual(elements_kind, IntPtrConstant(kind)), label); | |
Igor Sheludko
2016/07/28 10:01:10
It looks like a switch construct will fit better h
Jakob Kummerow
2016/08/03 11:44:09
Done.
| |
3035 | |
3036 JUMP_IF_KIND(FAST_SMI_ELEMENTS, &fast_packed); | |
3037 JUMP_IF_KIND(FAST_ELEMENTS, &fast_packed); | |
3038 JUMP_IF_KIND(FAST_HOLEY_SMI_ELEMENTS, &fast_holey); | |
3039 JUMP_IF_KIND(FAST_HOLEY_ELEMENTS, &fast_holey); | |
3040 JUMP_IF_KIND(FAST_DOUBLE_ELEMENTS, &fast_double); | |
3041 JUMP_IF_KIND(FAST_HOLEY_DOUBLE_ELEMENTS, &fast_holey_double); | |
3042 // All other kinds are unimplemented. | |
3043 DebugBreak(); | |
Igor Sheludko
2016/07/28 10:01:11
?
Jakob Kummerow
2016/08/03 11:44:11
I want to crash if we get here. Think "UNREACHABLE
| |
3044 Goto(miss); | |
3045 #undef JUMP_IF_KIND | |
3046 | |
3047 Bind(&fast_packed); | |
3048 Comment("fast packed elements"); | |
Igor Sheludko
2016/07/28 10:01:11
Consider wrapping blocks in {} for readability.
Jakob Kummerow
2016/08/03 11:44:11
Done.
| |
3049 // TODO(jkummerow): The Load*Element helpers add movsxlq instructions | |
3050 // on x64 which we don't need here, because |key| is an IntPtr already. | |
3051 // Do something about that. | |
Igor Sheludko
2016/07/28 10:01:10
We just need to introduce INTPTR_PARAMETERS mode.
Jakob Kummerow
2016/08/03 11:44:09
Yes, that's what I was thinking too. Follow-up CL.
| |
3052 Return(LoadFixedArrayElement(elements, key)); | |
3053 | |
3054 Bind(&fast_holey); | |
3055 { | |
3056 Comment("fast holey elements"); | |
3057 Node* element = LoadFixedArrayElement(elements, key); | |
3058 GotoIf(WordEqual(element, TheHoleConstant()), &hole); | |
3059 Return(element); | |
3060 } | |
3061 | |
3062 Bind(&fast_double); | |
3063 Comment("packed double elements"); | |
Igor Sheludko
2016/07/28 10:01:11
Same here.
Jakob Kummerow
2016/08/03 11:44:09
Done.
| |
3064 var_double_value.Bind( | |
3065 LoadFixedDoubleArrayElement(elements, key, MachineType::Float64())); | |
3066 Goto(&rebox_double); | |
3067 | |
3068 Bind(&fast_holey_double); | |
3069 { | |
3070 Comment("holey double elements"); | |
3071 if (kPointerSize == kDoubleSize) { | |
3072 Node* raw_element = | |
3073 LoadFixedDoubleArrayElement(elements, key, MachineType::Uint64()); | |
3074 Node* the_hole = Int64Constant(kHoleNanInt64); | |
3075 GotoIf(Word64Equal(raw_element, the_hole), &hole); | |
3076 } else { | |
3077 Node* element_upper = | |
3078 LoadFixedDoubleArrayElement(elements, key, MachineType::Uint32(), | |
3079 kIeeeDoubleExponentWordOffset); | |
3080 GotoIf(Word32Equal(element_upper, Int32Constant(kHoleNanUpper32)), | |
3081 &hole); | |
3082 } | |
3083 var_double_value.Bind( | |
3084 LoadFixedDoubleArrayElement(elements, key, MachineType::Float64())); | |
3085 Goto(&rebox_double); | |
3086 } | |
3087 | |
3088 Bind(&hole); | |
3089 { | |
3090 Comment("convert hole"); | |
3091 GotoIf(WordEqual(convert_hole, IntPtrConstant(0)), miss); | |
3092 Node* protector_cell = LoadRoot(Heap::kArrayProtectorRootIndex); | |
3093 GotoUnless( | |
3094 WordEqual(LoadObjectField(protector_cell, Cell::kValueOffset), | |
3095 SmiConstant(Smi::FromInt(Isolate::kArrayProtectorValid))), | |
3096 miss); | |
3097 Return(UndefinedConstant()); | |
3098 } | |
3099 | |
3100 Bind(&typed_array); | |
Igor Sheludko
2016/07/28 10:01:11
And here.
Jakob Kummerow
2016/08/03 11:44:09
Done.
| |
3101 Comment("typed elements"); | |
3102 // Check if buffer has been neutered. | |
3103 Node* buffer = | |
3104 LoadObjectField(p->receiver, JSArrayBufferView::kBufferOffset); | |
3105 Node* bitfield = LoadObjectField(buffer, JSArrayBuffer::kBitFieldOffset, | |
3106 MachineType::Uint32()); | |
3107 Node* neutered_bit = Word32And( | |
3108 bitfield, Int32Constant(1 << JSArrayBuffer::WasNeutered::kShift)); | |
Igor Sheludko
2016/07/28 10:01:11
JSArrayBuffer::WasNeutered::kMask?
Jakob Kummerow
2016/08/03 11:44:09
Done.
| |
3109 GotoUnless(Word32Equal(neutered_bit, Int32Constant(0)), miss); | |
3110 // Backing store = external_pointer + base_pointer. | |
3111 Node* external_pointer = | |
3112 LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, | |
3113 MachineType::Pointer()); | |
3114 Node* base_pointer = | |
3115 LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset); | |
3116 Node* backing_store = IntPtrAdd(external_pointer, base_pointer); | |
3117 | |
3118 const int kTypedElementsKindCount = | |
3119 LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND - | |
3120 FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND + 1; | |
3121 Label* elements_kind_labels[kTypedElementsKindCount]; | |
3122 int32_t elements_kinds[kTypedElementsKindCount]; | |
3123 for (int i = 0; i < kTypedElementsKindCount; i++) { | |
3124 elements_kinds[i] = i + FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND; | |
3125 elements_kind_labels[i] = new Label(this); | |
3126 } | |
3127 Switch(elements_kind, miss, elements_kinds, elements_kind_labels, | |
3128 static_cast<size_t>(kTypedElementsKindCount)); | |
3129 | |
3130 for (int i = 0; i < kTypedElementsKindCount; i++) { | |
3131 ElementsKind kind = static_cast<ElementsKind>(elements_kinds[i]); | |
3132 Bind(elements_kind_labels[i]); | |
3133 Comment(ElementsKindToString(kind)); | |
3134 switch (kind) { | |
3135 case UINT8_ELEMENTS: | |
3136 case UINT8_CLAMPED_ELEMENTS: | |
3137 Return(SmiTag(Load(MachineType::Uint8(), backing_store, key))); | |
3138 break; | |
3139 case INT8_ELEMENTS: | |
3140 Return(SmiTag(Load(MachineType::Int8(), backing_store, key))); | |
3141 break; | |
3142 case UINT16_ELEMENTS: { | |
3143 Node* index = WordShl(key, IntPtrConstant(1)); | |
3144 Return(SmiTag(Load(MachineType::Uint16(), backing_store, index))); | |
3145 break; | |
3146 } | |
3147 case INT16_ELEMENTS: { | |
3148 Node* index = WordShl(key, IntPtrConstant(1)); | |
3149 Return(SmiTag(Load(MachineType::Int16(), backing_store, index))); | |
3150 break; | |
3151 } | |
3152 case UINT32_ELEMENTS: { | |
3153 Node* index = WordShl(key, IntPtrConstant(2)); | |
3154 Node* element = Load(MachineType::Uint32(), backing_store, index); | |
3155 Return(ChangeUint32ToTagged(element)); | |
3156 break; | |
3157 } | |
3158 case INT32_ELEMENTS: { | |
3159 Node* index = WordShl(key, IntPtrConstant(2)); | |
3160 Node* element = Load(MachineType::Int32(), backing_store, index); | |
3161 Return(ChangeInt32ToTagged(element)); | |
3162 break; | |
3163 } | |
3164 case FLOAT32_ELEMENTS: { | |
3165 Node* index = WordShl(key, IntPtrConstant(2)); | |
3166 Node* element = Load(MachineType::Float32(), backing_store, index); | |
3167 var_double_value.Bind(ChangeFloat32ToFloat64(element)); | |
3168 Goto(&rebox_double); | |
3169 break; | |
3170 } | |
3171 case FLOAT64_ELEMENTS: { | |
3172 Node* index = WordShl(key, IntPtrConstant(3)); | |
3173 Node* element = Load(MachineType::Float64(), backing_store, index); | |
3174 var_double_value.Bind(element); | |
3175 Goto(&rebox_double); | |
3176 break; | |
3177 } | |
3178 default: | |
3179 UNREACHABLE(); | |
3180 } | |
3181 // Don't forget to clean up. | |
3182 delete elements_kind_labels[i]; | |
3183 } | |
3184 | |
3185 Bind(&property); | |
3186 Comment("property_load"); | |
3187 } | |
3188 | |
2995 // |handler_word| is a field index as obtained by | 3189 // |handler_word| is a field index as obtained by |
2996 // FieldIndex.GetLoadByFieldOffset(): | 3190 // FieldIndex.GetLoadByFieldOffset(): |
2997 Label inobject_double(this), out_of_object(this), | 3191 Label inobject_double(this), out_of_object(this), |
2998 out_of_object_double(this); | 3192 out_of_object_double(this); |
2999 Node* inobject_bit = WordAnd( | 3193 Node* inobject_bit = WordAnd( |
3000 handler_word, IntPtrConstant(FieldIndex::FieldOffsetIsInobject::kMask)); | 3194 handler_word, IntPtrConstant(FieldIndex::FieldOffsetIsInobject::kMask)); |
3001 Node* double_bit = WordAnd( | 3195 Node* double_bit = WordAnd( |
3002 handler_word, IntPtrConstant(FieldIndex::FieldOffsetIsDouble::kMask)); | 3196 handler_word, IntPtrConstant(FieldIndex::FieldOffsetIsDouble::kMask)); |
3003 Node* offset = WordSar( | 3197 Node* offset = WordSar( |
3004 handler_word, IntPtrConstant(FieldIndex::FieldOffsetOffset::kShift)); | 3198 handler_word, IntPtrConstant(FieldIndex::FieldOffsetOffset::kShift)); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3095 try_polymorphic_name(this /*, Label::kDeferred*/), | 3289 try_polymorphic_name(this /*, Label::kDeferred*/), |
3096 miss(this /*, Label::kDeferred*/); | 3290 miss(this /*, Label::kDeferred*/); |
3097 | 3291 |
3098 Node* receiver_map = LoadReceiverMap(p->receiver); | 3292 Node* receiver_map = LoadReceiverMap(p->receiver); |
3099 | 3293 |
3100 // Check monomorphic case. | 3294 // Check monomorphic case. |
3101 Node* feedback = TryMonomorphicCase(p, receiver_map, &if_handler, | 3295 Node* feedback = TryMonomorphicCase(p, receiver_map, &if_handler, |
3102 &var_handler, &try_polymorphic); | 3296 &var_handler, &try_polymorphic); |
3103 Bind(&if_handler); | 3297 Bind(&if_handler); |
3104 { | 3298 { |
3105 HandleLoadICHandlerCase(p, var_handler.value(), &miss); | 3299 HandleLoadICHandlerCase(p, var_handler.value(), &miss, kSupportElements); |
3106 } | 3300 } |
3107 | 3301 |
3108 Bind(&try_polymorphic); | 3302 Bind(&try_polymorphic); |
3109 { | 3303 { |
3110 // Check polymorphic case. | 3304 // Check polymorphic case. |
3111 Comment("KeyedLoadIC_try_polymorphic"); | 3305 Comment("KeyedLoadIC_try_polymorphic"); |
3112 GotoUnless( | 3306 GotoUnless( |
3113 WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)), | 3307 WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)), |
3114 &try_megamorphic); | 3308 &try_megamorphic); |
3115 HandlePolymorphicCase(p, receiver_map, feedback, &if_handler, &var_handler, | 3309 HandlePolymorphicCase(p, receiver_map, feedback, &if_handler, &var_handler, |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3249 // For all objects but the receiver, check that the cache is empty. | 3443 // For all objects but the receiver, check that the cache is empty. |
3250 current_map.Bind(LoadMap(current_js_object.value())); | 3444 current_map.Bind(LoadMap(current_js_object.value())); |
3251 Node* enum_length = EnumLength(current_map.value()); | 3445 Node* enum_length = EnumLength(current_map.value()); |
3252 Node* zero_constant = SmiConstant(Smi::FromInt(0)); | 3446 Node* zero_constant = SmiConstant(Smi::FromInt(0)); |
3253 BranchIf(WordEqual(enum_length, zero_constant), &loop, use_runtime); | 3447 BranchIf(WordEqual(enum_length, zero_constant), &loop, use_runtime); |
3254 } | 3448 } |
3255 } | 3449 } |
3256 | 3450 |
3257 } // namespace internal | 3451 } // namespace internal |
3258 } // namespace v8 | 3452 } // namespace v8 |
OLD | NEW |