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/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 // |is_jsarray| should be non-zero for JSArrays. |
| 2981 Node* handler, Label* miss) { | 2982 void CodeStubAssembler::EmitBoundsCheck(Node* object, Node* elements, |
| 2983 Node* int32_key, Node* is_jsarray, | |
|
Igor Sheludko
2016/08/04 12:03:09
int32_key -> int_ptr_key?
Jakob Kummerow
2016/08/05 11:36:03
Done.
| |
| 2984 Label* miss) { | |
| 2985 Variable var_length(this, MachineRepresentation::kTagged); | |
| 2986 Label if_array(this), length_loaded(this, &var_length); | |
| 2987 GotoUnless(WordEqual(is_jsarray, IntPtrConstant(0)), &if_array); | |
| 2988 { | |
| 2989 var_length.Bind(SmiUntag(LoadFixedArrayBaseLength(elements))); | |
| 2990 Goto(&length_loaded); | |
| 2991 } | |
| 2992 Bind(&if_array); | |
| 2993 { | |
| 2994 var_length.Bind(SmiUntag(LoadObjectField(object, JSArray::kLengthOffset))); | |
| 2995 Goto(&length_loaded); | |
| 2996 } | |
| 2997 Bind(&length_loaded); | |
| 2998 GotoUnless(UintPtrLessThan(int32_key, var_length.value()), miss); | |
| 2999 } | |
| 3000 | |
| 3001 // |key| should be untagged (int32). | |
| 3002 void CodeStubAssembler::EmitElementLoad(Node* object, Node* elements, | |
| 3003 Node* elements_kind, Node* key, | |
| 3004 Label* if_hole, Label* rebox_double, | |
| 3005 Variable* var_double_value, | |
| 3006 Label* miss) { | |
| 3007 Label if_typed_array(this), if_fast_packed(this), if_fast_holey(this), | |
| 3008 if_fast_double(this), if_fast_holey_double(this), | |
| 3009 unimplemented_elements_kind(this); | |
| 3010 STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND); | |
| 3011 GotoIf( | |
| 3012 IntPtrGreaterThanOrEqual( | |
| 3013 elements_kind, IntPtrConstant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)), | |
| 3014 &if_typed_array); | |
| 3015 | |
| 3016 int32_t kinds[] = {// Handled by if_fast_packed. | |
| 3017 FAST_SMI_ELEMENTS, FAST_ELEMENTS, | |
| 3018 // Handled by if_fast_holey. | |
| 3019 FAST_HOLEY_SMI_ELEMENTS, FAST_HOLEY_ELEMENTS, | |
| 3020 // Handled by if_fast_double. | |
| 3021 FAST_DOUBLE_ELEMENTS, | |
| 3022 // Handled by if_fast_holey_double. | |
| 3023 FAST_HOLEY_DOUBLE_ELEMENTS}; | |
| 3024 Label* labels[] = {// FAST_{SMI,}_ELEMENTS | |
| 3025 &if_fast_packed, &if_fast_packed, | |
| 3026 // FAST_HOLEY_{SMI,}_ELEMENTS | |
| 3027 &if_fast_holey, &if_fast_holey, | |
| 3028 // FAST_DOUBLE_ELEMENTS | |
| 3029 &if_fast_double, | |
| 3030 // FAST_HOLEY_DOUBLE_ELEMENTS | |
| 3031 &if_fast_holey_double}; | |
| 3032 Switch(elements_kind, &unimplemented_elements_kind, kinds, labels, | |
| 3033 arraysize(kinds)); | |
| 3034 Bind(&unimplemented_elements_kind); | |
| 3035 { | |
| 3036 // Crash if we get here. | |
| 3037 DebugBreak(); | |
| 3038 Goto(miss); | |
| 3039 } | |
| 3040 | |
| 3041 Bind(&if_fast_packed); | |
| 3042 { | |
| 3043 Comment("fast packed elements"); | |
| 3044 // TODO(jkummerow): The Load*Element helpers add movsxlq instructions | |
| 3045 // on x64 which we don't need here, because |key| is an IntPtr already. | |
| 3046 // Do something about that. | |
| 3047 Return(LoadFixedArrayElement(elements, key)); | |
| 3048 } | |
| 3049 | |
| 3050 Bind(&if_fast_holey); | |
| 3051 { | |
| 3052 Comment("fast holey elements"); | |
| 3053 Node* element = LoadFixedArrayElement(elements, key); | |
| 3054 GotoIf(WordEqual(element, TheHoleConstant()), if_hole); | |
| 3055 Return(element); | |
| 3056 } | |
| 3057 | |
| 3058 Bind(&if_fast_double); | |
| 3059 { | |
| 3060 Comment("packed double elements"); | |
| 3061 var_double_value->Bind( | |
| 3062 LoadFixedDoubleArrayElement(elements, key, MachineType::Float64())); | |
| 3063 Goto(rebox_double); | |
| 3064 } | |
| 3065 | |
| 3066 Bind(&if_fast_holey_double); | |
| 3067 { | |
| 3068 Comment("holey double elements"); | |
| 3069 if (kPointerSize == kDoubleSize) { | |
| 3070 Node* raw_element = | |
| 3071 LoadFixedDoubleArrayElement(elements, key, MachineType::Uint64()); | |
| 3072 Node* the_hole = Int64Constant(kHoleNanInt64); | |
| 3073 GotoIf(Word64Equal(raw_element, the_hole), if_hole); | |
| 3074 } else { | |
| 3075 Node* element_upper = LoadFixedDoubleArrayElement( | |
| 3076 elements, key, MachineType::Uint32(), kIeeeDoubleExponentWordOffset); | |
| 3077 GotoIf(Word32Equal(element_upper, Int32Constant(kHoleNanUpper32)), | |
| 3078 if_hole); | |
| 3079 } | |
| 3080 var_double_value->Bind( | |
| 3081 LoadFixedDoubleArrayElement(elements, key, MachineType::Float64())); | |
| 3082 Goto(rebox_double); | |
| 3083 } | |
| 3084 | |
| 3085 Bind(&if_typed_array); | |
| 3086 { | |
| 3087 Comment("typed elements"); | |
| 3088 // Check if buffer has been neutered. | |
| 3089 Node* buffer = LoadObjectField(object, JSArrayBufferView::kBufferOffset); | |
| 3090 Node* bitfield = LoadObjectField(buffer, JSArrayBuffer::kBitFieldOffset, | |
| 3091 MachineType::Uint32()); | |
| 3092 Node* neutered_bit = | |
| 3093 Word32And(bitfield, Int32Constant(JSArrayBuffer::WasNeutered::kMask)); | |
| 3094 GotoUnless(Word32Equal(neutered_bit, Int32Constant(0)), miss); | |
| 3095 // Backing store = external_pointer + base_pointer. | |
| 3096 Node* external_pointer = | |
| 3097 LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, | |
| 3098 MachineType::Pointer()); | |
| 3099 Node* base_pointer = | |
| 3100 LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset); | |
| 3101 Node* backing_store = IntPtrAdd(external_pointer, base_pointer); | |
| 3102 | |
| 3103 const int kTypedElementsKindCount = LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND - | |
| 3104 FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND + | |
| 3105 1; | |
| 3106 Label* elements_kind_labels[kTypedElementsKindCount]; | |
| 3107 int32_t elements_kinds[kTypedElementsKindCount]; | |
| 3108 for (int i = 0; i < kTypedElementsKindCount; i++) { | |
| 3109 elements_kinds[i] = i + FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND; | |
| 3110 elements_kind_labels[i] = new Label(this); | |
| 3111 } | |
| 3112 Switch(elements_kind, miss, elements_kinds, elements_kind_labels, | |
|
Igor Sheludko
2016/08/04 12:03:09
miss -> unimplemented_elements_kind?
Jakob Kummerow
2016/08/05 11:36:03
Done (doesn't make a difference here; as long as S
| |
| 3113 static_cast<size_t>(kTypedElementsKindCount)); | |
| 3114 | |
| 3115 for (int i = 0; i < kTypedElementsKindCount; i++) { | |
| 3116 ElementsKind kind = static_cast<ElementsKind>(elements_kinds[i]); | |
| 3117 Bind(elements_kind_labels[i]); | |
| 3118 Comment(ElementsKindToString(kind)); | |
| 3119 switch (kind) { | |
| 3120 case UINT8_ELEMENTS: | |
| 3121 case UINT8_CLAMPED_ELEMENTS: | |
| 3122 Return(SmiTag(Load(MachineType::Uint8(), backing_store, key))); | |
| 3123 break; | |
| 3124 case INT8_ELEMENTS: | |
| 3125 Return(SmiTag(Load(MachineType::Int8(), backing_store, key))); | |
| 3126 break; | |
| 3127 case UINT16_ELEMENTS: { | |
| 3128 Node* index = WordShl(key, IntPtrConstant(1)); | |
| 3129 Return(SmiTag(Load(MachineType::Uint16(), backing_store, index))); | |
| 3130 break; | |
| 3131 } | |
| 3132 case INT16_ELEMENTS: { | |
| 3133 Node* index = WordShl(key, IntPtrConstant(1)); | |
| 3134 Return(SmiTag(Load(MachineType::Int16(), backing_store, index))); | |
| 3135 break; | |
| 3136 } | |
| 3137 case UINT32_ELEMENTS: { | |
| 3138 Node* index = WordShl(key, IntPtrConstant(2)); | |
| 3139 Node* element = Load(MachineType::Uint32(), backing_store, index); | |
| 3140 Return(ChangeUint32ToTagged(element)); | |
| 3141 break; | |
| 3142 } | |
| 3143 case INT32_ELEMENTS: { | |
| 3144 Node* index = WordShl(key, IntPtrConstant(2)); | |
| 3145 Node* element = Load(MachineType::Int32(), backing_store, index); | |
| 3146 Return(ChangeInt32ToTagged(element)); | |
| 3147 break; | |
| 3148 } | |
| 3149 case FLOAT32_ELEMENTS: { | |
| 3150 Node* index = WordShl(key, IntPtrConstant(2)); | |
| 3151 Node* element = Load(MachineType::Float32(), backing_store, index); | |
| 3152 var_double_value->Bind(ChangeFloat32ToFloat64(element)); | |
| 3153 Goto(rebox_double); | |
| 3154 break; | |
| 3155 } | |
| 3156 case FLOAT64_ELEMENTS: { | |
| 3157 Node* index = WordShl(key, IntPtrConstant(3)); | |
| 3158 Node* element = Load(MachineType::Float64(), backing_store, index); | |
| 3159 var_double_value->Bind(element); | |
| 3160 Goto(rebox_double); | |
| 3161 break; | |
| 3162 } | |
| 3163 default: | |
| 3164 UNREACHABLE(); | |
| 3165 } | |
| 3166 // Don't forget to clean up. | |
| 3167 delete elements_kind_labels[i]; | |
| 3168 } | |
| 3169 } | |
| 3170 } | |
| 3171 | |
| 3172 void CodeStubAssembler::HandleLoadICHandlerCase( | |
| 3173 const LoadICParameters* p, Node* handler, Label* miss, | |
| 3174 ElementSupport support_elements) { | |
| 2982 Comment("have_handler"); | 3175 Comment("have_handler"); |
| 2983 Label call_handler(this); | 3176 Label call_handler(this); |
| 2984 GotoUnless(WordIsSmi(handler), &call_handler); | 3177 GotoUnless(WordIsSmi(handler), &call_handler); |
| 2985 | 3178 |
| 2986 // |handler| is a Smi. It encodes a field index as obtained by | 3179 // |handler| is a Smi, encoding what to do. See handler-configuration.h |
| 2987 // FieldIndex.GetLoadByFieldOffset(). | 3180 // for the encoding format. |
| 2988 // TODO(jkummerow): For KeyedLoadICs, extend this scheme to encode | |
| 2989 // fast *element* loads. | |
| 2990 { | 3181 { |
| 2991 Variable var_double_value(this, MachineRepresentation::kFloat64); | 3182 Variable var_double_value(this, MachineRepresentation::kFloat64); |
| 2992 Label rebox_double(this, &var_double_value); | 3183 Label rebox_double(this, &var_double_value); |
| 2993 | 3184 |
| 2994 Node* handler_word = SmiUntag(handler); | 3185 Node* handler_word = SmiUntag(handler); |
| 3186 if (support_elements == kSupportElements) { | |
| 3187 Label property(this); | |
| 3188 Node* is_element_bit = | |
|
Igor Sheludko
2016/08/04 12:03:09
handler_type
Jakob Kummerow
2016/08/05 11:36:03
Done.
| |
| 3189 WordAnd(handler_word, IntPtrConstant(LoadHandlerTypeBit::kMask)); | |
| 3190 GotoUnless( | |
| 3191 WordEqual(is_element_bit, IntPtrConstant(kLoadICHandlerForElements)), | |
| 3192 &property); | |
| 3193 | |
| 3194 Comment("element_load"); | |
| 3195 GotoUnless(WordIsSmi(p->name), miss); | |
| 3196 Node* key = SmiUntag(p->name); | |
| 3197 Node* elements = LoadElements(p->receiver); | |
| 3198 Node* is_jsarray = | |
| 3199 WordAnd(handler_word, IntPtrConstant(KeyedLoadIsJsArray::kMask)); | |
| 3200 EmitBoundsCheck(p->receiver, elements, key, is_jsarray, miss); | |
| 3201 Label if_hole(this); | |
| 3202 | |
| 3203 Node* elements_kind = | |
| 3204 WordShr(handler_word, IntPtrConstant(KeyedLoadElementsKind::kShift)); | |
|
Igor Sheludko
2016/08/04 12:03:09
"BitFieldDecode<KeyedLoadElementsKind>" in order n
Jakob Kummerow
2016/08/05 11:36:03
Done.
| |
| 3205 | |
| 3206 EmitElementLoad(p->receiver, elements, elements_kind, key, &if_hole, | |
| 3207 &rebox_double, &var_double_value, miss); | |
| 3208 | |
| 3209 Bind(&if_hole); | |
| 3210 { | |
| 3211 Comment("convert hole"); | |
| 3212 Node* convert_hole = | |
| 3213 WordAnd(handler_word, IntPtrConstant(KeyedLoadConvertHole::kMask)); | |
| 3214 GotoIf(WordEqual(convert_hole, IntPtrConstant(0)), miss); | |
| 3215 Node* protector_cell = LoadRoot(Heap::kArrayProtectorRootIndex); | |
| 3216 GotoUnless( | |
| 3217 WordEqual(LoadObjectField(protector_cell, Cell::kValueOffset), | |
| 3218 SmiConstant(Smi::FromInt(Isolate::kArrayProtectorValid))), | |
| 3219 miss); | |
| 3220 Return(UndefinedConstant()); | |
| 3221 } | |
| 3222 | |
| 3223 Bind(&property); | |
| 3224 Comment("property_load"); | |
| 3225 } | |
| 3226 | |
| 2995 // |handler_word| is a field index as obtained by | 3227 // |handler_word| is a field index as obtained by |
| 2996 // FieldIndex.GetLoadByFieldOffset(): | 3228 // FieldIndex.GetLoadByFieldOffset(): |
| 2997 Label inobject_double(this), out_of_object(this), | 3229 Label inobject_double(this), out_of_object(this), |
| 2998 out_of_object_double(this); | 3230 out_of_object_double(this); |
| 2999 Node* inobject_bit = WordAnd( | 3231 Node* inobject_bit = |
| 3000 handler_word, IntPtrConstant(FieldIndex::FieldOffsetIsInobject::kMask)); | 3232 WordAnd(handler_word, IntPtrConstant(FieldOffsetIsInobject::kMask)); |
| 3001 Node* double_bit = WordAnd( | 3233 Node* double_bit = |
| 3002 handler_word, IntPtrConstant(FieldIndex::FieldOffsetIsDouble::kMask)); | 3234 WordAnd(handler_word, IntPtrConstant(FieldOffsetIsDouble::kMask)); |
| 3003 Node* offset = WordSar( | 3235 Node* offset = |
| 3004 handler_word, IntPtrConstant(FieldIndex::FieldOffsetOffset::kShift)); | 3236 WordSar(handler_word, IntPtrConstant(FieldOffsetOffset::kShift)); |
| 3005 | 3237 |
| 3006 GotoIf(WordEqual(inobject_bit, IntPtrConstant(0)), &out_of_object); | 3238 GotoIf(WordEqual(inobject_bit, IntPtrConstant(0)), &out_of_object); |
| 3007 | 3239 |
| 3008 GotoUnless(WordEqual(double_bit, IntPtrConstant(0)), &inobject_double); | 3240 GotoUnless(WordEqual(double_bit, IntPtrConstant(0)), &inobject_double); |
| 3009 Return(LoadObjectField(p->receiver, offset)); | 3241 Return(LoadObjectField(p->receiver, offset)); |
| 3010 | 3242 |
| 3011 Bind(&inobject_double); | 3243 Bind(&inobject_double); |
| 3012 if (FLAG_unbox_double_fields) { | 3244 if (FLAG_unbox_double_fields) { |
| 3013 var_double_value.Bind( | 3245 var_double_value.Bind( |
| 3014 LoadObjectField(p->receiver, offset, MachineType::Float64())); | 3246 LoadObjectField(p->receiver, offset, MachineType::Float64())); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3095 try_polymorphic_name(this /*, Label::kDeferred*/), | 3327 try_polymorphic_name(this /*, Label::kDeferred*/), |
| 3096 miss(this /*, Label::kDeferred*/); | 3328 miss(this /*, Label::kDeferred*/); |
| 3097 | 3329 |
| 3098 Node* receiver_map = LoadReceiverMap(p->receiver); | 3330 Node* receiver_map = LoadReceiverMap(p->receiver); |
| 3099 | 3331 |
| 3100 // Check monomorphic case. | 3332 // Check monomorphic case. |
| 3101 Node* feedback = TryMonomorphicCase(p, receiver_map, &if_handler, | 3333 Node* feedback = TryMonomorphicCase(p, receiver_map, &if_handler, |
| 3102 &var_handler, &try_polymorphic); | 3334 &var_handler, &try_polymorphic); |
| 3103 Bind(&if_handler); | 3335 Bind(&if_handler); |
| 3104 { | 3336 { |
| 3105 HandleLoadICHandlerCase(p, var_handler.value(), &miss); | 3337 HandleLoadICHandlerCase(p, var_handler.value(), &miss, kSupportElements); |
| 3106 } | 3338 } |
| 3107 | 3339 |
| 3108 Bind(&try_polymorphic); | 3340 Bind(&try_polymorphic); |
| 3109 { | 3341 { |
| 3110 // Check polymorphic case. | 3342 // Check polymorphic case. |
| 3111 Comment("KeyedLoadIC_try_polymorphic"); | 3343 Comment("KeyedLoadIC_try_polymorphic"); |
| 3112 GotoUnless( | 3344 GotoUnless( |
| 3113 WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)), | 3345 WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)), |
| 3114 &try_megamorphic); | 3346 &try_megamorphic); |
| 3115 HandlePolymorphicCase(p, receiver_map, feedback, &if_handler, &var_handler, | 3347 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. | 3481 // For all objects but the receiver, check that the cache is empty. |
| 3250 current_map.Bind(LoadMap(current_js_object.value())); | 3482 current_map.Bind(LoadMap(current_js_object.value())); |
| 3251 Node* enum_length = EnumLength(current_map.value()); | 3483 Node* enum_length = EnumLength(current_map.value()); |
| 3252 Node* zero_constant = SmiConstant(Smi::FromInt(0)); | 3484 Node* zero_constant = SmiConstant(Smi::FromInt(0)); |
| 3253 BranchIf(WordEqual(enum_length, zero_constant), &loop, use_runtime); | 3485 BranchIf(WordEqual(enum_length, zero_constant), &loop, use_runtime); |
| 3254 } | 3486 } |
| 3255 } | 3487 } |
| 3256 | 3488 |
| 3257 } // namespace internal | 3489 } // namespace internal |
| 3258 } // namespace v8 | 3490 } // namespace v8 |
| OLD | NEW |