Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(381)

Side by Side Diff: src/code-stub-assembler.cc

Issue 2180273002: [KeyedLoadIC] Support Smi "handlers" for element loads (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@keyed-load-ic-fieldindex
Patch Set: refactor according to review comments Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/code-stub-assembler.h ('k') | src/field-index.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « src/code-stub-assembler.h ('k') | src/field-index.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698