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

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

Issue 2182103002: [KeyedLoadIC] Support Smi "handlers" for simple field loads (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: implement KeyedLoadIC stub in CodeStubAssembler 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
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/stub-cache.h" 9 #include "src/ic/stub-cache.h"
10 10
(...skipping 2398 matching lines...) Expand 10 before | Expand all | Expand 10 after
2409 }; 2409 };
2410 // clang-format on 2410 // clang-format on
2411 STATIC_ASSERT(arraysize(values) == arraysize(labels)); 2411 STATIC_ASSERT(arraysize(values) == arraysize(labels));
2412 Switch(elements_kind, if_bailout, values, labels, arraysize(values)); 2412 Switch(elements_kind, if_bailout, values, labels, arraysize(values));
2413 2413
2414 Bind(&if_isobjectorsmi); 2414 Bind(&if_isobjectorsmi);
2415 { 2415 {
2416 Node* elements = LoadElements(object); 2416 Node* elements = LoadElements(object);
2417 Node* length = LoadFixedArrayBaseLength(elements); 2417 Node* length = LoadFixedArrayBaseLength(elements);
2418 2418
2419 GotoIf(Int32GreaterThanOrEqual(index, SmiToWord32(length)), if_not_found); 2419 GotoUnless(Uint32LessThan(index, SmiToWord32(length)), if_not_found);
Jakob Kummerow 2016/07/26 14:43:28 Drive-by fix: bounds checks should use unsigned co
Igor Sheludko 2016/07/26 16:25:11 Acknowledged.
2420 2420
2421 Node* element = LoadFixedArrayElement(elements, index); 2421 Node* element = LoadFixedArrayElement(elements, index);
2422 Node* the_hole = TheHoleConstant(); 2422 Node* the_hole = TheHoleConstant();
2423 Branch(WordEqual(element, the_hole), if_not_found, if_found); 2423 Branch(WordEqual(element, the_hole), if_not_found, if_found);
2424 } 2424 }
2425 Bind(&if_isdouble); 2425 Bind(&if_isdouble);
2426 { 2426 {
2427 Node* elements = LoadElements(object); 2427 Node* elements = LoadElements(object);
2428 Node* length = LoadFixedArrayBaseLength(elements); 2428 Node* length = LoadFixedArrayBaseLength(elements);
2429 2429
2430 GotoIf(Int32GreaterThanOrEqual(index, SmiToWord32(length)), if_not_found); 2430 GotoUnless(Uint32LessThan(index, SmiToWord32(length)), if_not_found);
2431 2431
2432 if (kPointerSize == kDoubleSize) { 2432 if (kPointerSize == kDoubleSize) {
2433 Node* element = 2433 Node* element =
2434 LoadFixedDoubleArrayElement(elements, index, MachineType::Uint64()); 2434 LoadFixedDoubleArrayElement(elements, index, MachineType::Uint64());
2435 Node* the_hole = Int64Constant(kHoleNanInt64); 2435 Node* the_hole = Int64Constant(kHoleNanInt64);
2436 Branch(Word64Equal(element, the_hole), if_not_found, if_found); 2436 Branch(Word64Equal(element, the_hole), if_not_found, if_found);
2437 } else { 2437 } else {
2438 Node* element_upper = 2438 Node* element_upper =
2439 LoadFixedDoubleArrayElement(elements, index, MachineType::Uint32(), 2439 LoadFixedDoubleArrayElement(elements, index, MachineType::Uint32(),
2440 kIeeeDoubleExponentWordOffset); 2440 kIeeeDoubleExponentWordOffset);
2441 Branch(Word32Equal(element_upper, Int32Constant(kHoleNanUpper32)), 2441 Branch(Word32Equal(element_upper, Int32Constant(kHoleNanUpper32)),
2442 if_not_found, if_found); 2442 if_not_found, if_found);
2443 } 2443 }
2444 } 2444 }
2445 Bind(&if_isdictionary); 2445 Bind(&if_isdictionary);
2446 { 2446 {
2447 Variable var_entry(this, MachineRepresentation::kWord32); 2447 Variable var_entry(this, MachineRepresentation::kWord32);
2448 Node* elements = LoadElements(object); 2448 Node* elements = LoadElements(object);
2449 NumberDictionaryLookup<SeededNumberDictionary>(elements, index, if_found, 2449 NumberDictionaryLookup<SeededNumberDictionary>(elements, index, if_found,
2450 &var_entry, if_not_found); 2450 &var_entry, if_not_found);
2451 } 2451 }
2452 Bind(&if_isfaststringwrapper); 2452 Bind(&if_isfaststringwrapper);
2453 { 2453 {
2454 AssertInstanceType(object, JS_VALUE_TYPE); 2454 AssertInstanceType(object, JS_VALUE_TYPE);
2455 Node* string = LoadJSValueValue(object); 2455 Node* string = LoadJSValueValue(object);
2456 Assert(Int32LessThan(LoadInstanceType(string), 2456 Assert(Int32LessThan(LoadInstanceType(string),
2457 Int32Constant(FIRST_NONSTRING_TYPE))); 2457 Int32Constant(FIRST_NONSTRING_TYPE)));
2458 Node* length = LoadStringLength(string); 2458 Node* length = LoadStringLength(string);
2459 GotoIf(Int32LessThan(index, SmiToWord32(length)), if_found); 2459 GotoIf(Uint32LessThan(index, SmiToWord32(length)), if_found);
2460 Goto(&if_isobjectorsmi); 2460 Goto(&if_isobjectorsmi);
2461 } 2461 }
2462 Bind(&if_isslowstringwrapper); 2462 Bind(&if_isslowstringwrapper);
2463 { 2463 {
2464 AssertInstanceType(object, JS_VALUE_TYPE); 2464 AssertInstanceType(object, JS_VALUE_TYPE);
2465 Node* string = LoadJSValueValue(object); 2465 Node* string = LoadJSValueValue(object);
2466 Assert(Int32LessThan(LoadInstanceType(string), 2466 Assert(Int32LessThan(LoadInstanceType(string),
2467 Int32Constant(FIRST_NONSTRING_TYPE))); 2467 Int32Constant(FIRST_NONSTRING_TYPE)));
2468 Node* length = LoadStringLength(string); 2468 Node* length = LoadStringLength(string);
2469 GotoIf(Int32LessThan(index, SmiToWord32(length)), if_found); 2469 GotoIf(Uint32LessThan(index, SmiToWord32(length)), if_found);
2470 Goto(&if_isdictionary); 2470 Goto(&if_isdictionary);
2471 } 2471 }
2472 } 2472 }
2473 2473
2474 // Instantiate template methods to workaround GCC compilation issue. 2474 // Instantiate template methods to workaround GCC compilation issue.
2475 template void CodeStubAssembler::NumberDictionaryLookup<SeededNumberDictionary>( 2475 template void CodeStubAssembler::NumberDictionaryLookup<SeededNumberDictionary>(
2476 Node*, Node*, Label*, Variable*, Label*); 2476 Node*, Node*, Label*, Variable*, Label*);
2477 template void CodeStubAssembler::NumberDictionaryLookup< 2477 template void CodeStubAssembler::NumberDictionaryLookup<
2478 UnseededNumberDictionary>(Node*, Node*, Label*, Variable*, Label*); 2478 UnseededNumberDictionary>(Node*, Node*, Label*, Variable*, Label*);
2479 2479
(...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after
2970 receiver_map, if_handler, var_handler, &miss); 2970 receiver_map, if_handler, var_handler, &miss);
2971 } 2971 }
2972 2972
2973 Bind(&miss); 2973 Bind(&miss);
2974 { 2974 {
2975 IncrementCounter(counters->megamorphic_stub_cache_misses(), 1); 2975 IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
2976 Goto(if_miss); 2976 Goto(if_miss);
2977 } 2977 }
2978 } 2978 }
2979 2979
2980 void CodeStubAssembler::HaveLoadICHandler(const LoadICParameters* p,
2981 Node* handler, Label* miss) {
2982 Comment("have_handler");
2983 Label call_handler(this);
2984 GotoUnless(WordIsSmi(handler), &call_handler);
2985
2986 // |handler| is a Smi. It encodes a field index as obtained by
2987 // FieldIndex.GetLoadByFieldOffset().
2988 // TODO(jkummerow): For KeyedLoadICs, extend this scheme to encode
2989 // fast *element* loads.
2990 {
2991 Variable var_double_value(this, MachineRepresentation::kFloat64);
2992 Label rebox_double(this, &var_double_value);
2993
2994 Node* handler_word = SmiUntag(handler);
2995 // |handler_word| is a field index as obtained by
2996 // FieldIndex.GetLoadByFieldOffset():
2997 // (offset << 3) | (is_double << 2) | (is_inobject << 1) | 1.
2998 Label inobject_double(this), out_of_object(this),
2999 out_of_object_double(this);
3000 Node* inobject_bit = WordAnd(handler_word, IntPtrConstant(1 << 1));
3001 Node* double_bit = WordAnd(handler_word, IntPtrConstant(1 << 2));
3002 Node* offset = WordSar(handler_word, IntPtrConstant(3));
3003
3004 GotoIf(WordEqual(inobject_bit, IntPtrConstant(0)), &out_of_object);
3005
3006 GotoUnless(WordEqual(double_bit, IntPtrConstant(0)), &inobject_double);
3007 Return(LoadObjectField(p->receiver, offset));
3008
3009 Bind(&inobject_double);
3010 if (FLAG_unbox_double_fields) {
3011 var_double_value.Bind(
3012 LoadObjectField(p->receiver, offset, MachineType::Float64()));
3013 } else {
3014 Node* mutable_heap_number = LoadObjectField(p->receiver, offset);
3015 var_double_value.Bind(LoadHeapNumberValue(mutable_heap_number));
3016 }
3017 Goto(&rebox_double);
3018
3019 Bind(&out_of_object);
3020 Node* properties = LoadProperties(p->receiver);
3021 Node* value = LoadObjectField(properties, offset);
3022 GotoUnless(WordEqual(double_bit, IntPtrConstant(0)), &out_of_object_double);
3023 Return(value);
3024
3025 Bind(&out_of_object_double);
3026 var_double_value.Bind(LoadHeapNumberValue(value));
3027 Goto(&rebox_double);
3028
3029 Bind(&rebox_double);
3030 Return(AllocateHeapNumberWithValue(var_double_value.value()));
3031 }
3032
3033 // |handler| is a heap object. Must be code, call it.
3034 Bind(&call_handler);
3035 LoadWithVectorDescriptor descriptor(isolate());
3036 TailCallStub(descriptor, handler, p->context, p->receiver, p->name, p->slot,
3037 p->vector);
3038 }
3039
2980 void CodeStubAssembler::LoadIC(const LoadICParameters* p) { 3040 void CodeStubAssembler::LoadIC(const LoadICParameters* p) {
2981 Variable var_handler(this, MachineRepresentation::kTagged); 3041 Variable var_handler(this, MachineRepresentation::kTagged);
2982 // TODO(ishell): defer blocks when it works. 3042 // TODO(ishell): defer blocks when it works.
2983 Label if_handler(this, &var_handler), try_polymorphic(this), 3043 Label if_handler(this, &var_handler), try_polymorphic(this),
2984 try_megamorphic(this /*, Label::kDeferred*/), 3044 try_megamorphic(this /*, Label::kDeferred*/),
2985 miss(this /*, Label::kDeferred*/); 3045 miss(this /*, Label::kDeferred*/);
2986 3046
2987 Node* receiver_map = LoadReceiverMap(p->receiver); 3047 Node* receiver_map = LoadReceiverMap(p->receiver);
2988 3048
2989 // Check monomorphic case. 3049 // Check monomorphic case.
2990 Node* feedback = TryMonomorphicCase(p, receiver_map, &if_handler, 3050 Node* feedback = TryMonomorphicCase(p, receiver_map, &if_handler,
2991 &var_handler, &try_polymorphic); 3051 &var_handler, &try_polymorphic);
2992 Bind(&if_handler); 3052 Bind(&if_handler);
2993 { 3053 {
2994 Comment("LoadIC_if_handler"); 3054 HaveLoadICHandler(p, var_handler.value(), &miss);
2995 Label call_handler(this);
2996 Node* handler = var_handler.value();
2997 GotoUnless(WordIsSmi(handler), &call_handler);
2998
2999 // |handler| is a Smi. It encodes a field index as obtained by
3000 // FieldIndex.GetLoadByFieldOffset().
3001 {
3002 Label inobject_double(this), out_of_object(this),
3003 out_of_object_double(this);
3004 Variable var_double_value(this, MachineRepresentation::kFloat64);
3005 Label rebox_double(this, &var_double_value);
3006
3007 Node* handler_word = SmiToWord32(handler);
3008 // handler == (offset << 1) | is_double.
3009 Node* double_bit = Word32And(handler_word, Int32Constant(1));
3010 Node* offset = Word32Sar(handler_word, Int32Constant(1));
3011
3012 // Negative index -> out of object.
3013 GotoIf(Int32LessThan(offset, Int32Constant(0)), &out_of_object);
3014
3015 Node* offset_ptr = ChangeInt32ToIntPtr(offset);
3016 GotoUnless(Word32Equal(double_bit, Int32Constant(0)), &inobject_double);
3017 Return(LoadObjectField(p->receiver, offset_ptr));
3018
3019 Bind(&inobject_double);
3020 if (FLAG_unbox_double_fields) {
3021 var_double_value.Bind(
3022 LoadObjectField(p->receiver, offset_ptr, MachineType::Float64()));
3023 } else {
3024 Node* mutable_heap_number = LoadObjectField(p->receiver, offset_ptr);
3025 var_double_value.Bind(LoadHeapNumberValue(mutable_heap_number));
3026 }
3027 Goto(&rebox_double);
3028
3029 Bind(&out_of_object);
3030 // |offset| == -actual_offset
3031 offset_ptr = ChangeInt32ToIntPtr(Int32Sub(Int32Constant(0), offset));
3032 Node* properties = LoadProperties(p->receiver);
3033 Node* value = LoadObjectField(properties, offset_ptr);
3034 GotoUnless(Word32Equal(double_bit, Int32Constant(0)),
3035 &out_of_object_double);
3036 Return(value);
3037
3038 Bind(&out_of_object_double);
3039 var_double_value.Bind(LoadHeapNumberValue(value));
3040 Goto(&rebox_double);
3041
3042 Bind(&rebox_double);
3043 Return(AllocateHeapNumberWithValue(var_double_value.value()));
3044 }
3045
3046 // |handler| is a heap object. Must be code, call it.
3047 Bind(&call_handler);
3048 LoadWithVectorDescriptor descriptor(isolate());
3049 TailCallStub(descriptor, handler, p->context, p->receiver, p->name, p->slot,
3050 p->vector);
3051 } 3055 }
3052 3056
3053 Bind(&try_polymorphic); 3057 Bind(&try_polymorphic);
3054 { 3058 {
3055 // Check polymorphic case. 3059 // Check polymorphic case.
3056 Comment("LoadIC_try_polymorphic"); 3060 Comment("LoadIC_try_polymorphic");
3057 GotoUnless( 3061 GotoUnless(
3058 WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)), 3062 WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
3059 &try_megamorphic); 3063 &try_megamorphic);
3060 HandlePolymorphicCase(p, receiver_map, feedback, &if_handler, &var_handler, 3064 HandlePolymorphicCase(p, receiver_map, feedback, &if_handler, &var_handler,
(...skipping 10 matching lines...) Expand all
3071 TryProbeStubCache(isolate()->load_stub_cache(), p->receiver, p->name, 3075 TryProbeStubCache(isolate()->load_stub_cache(), p->receiver, p->name,
3072 &if_handler, &var_handler, &miss); 3076 &if_handler, &var_handler, &miss);
3073 } 3077 }
3074 Bind(&miss); 3078 Bind(&miss);
3075 { 3079 {
3076 TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name, 3080 TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name,
3077 p->slot, p->vector); 3081 p->slot, p->vector);
3078 } 3082 }
3079 } 3083 }
3080 3084
3085 void CodeStubAssembler::KeyedLoadIC(const LoadICParameters* p) {
3086 Variable var_handler(this, MachineRepresentation::kTagged);
3087 // TODO(ishell): defer blocks when it works.
3088 Label if_handler(this, &var_handler), try_polymorphic(this),
3089 try_megamorphic(this /*, Label::kDeferred*/),
3090 try_polymorphic_name(this /*, Label::kDeferred*/),
3091 miss(this /*, Label::kDeferred*/);
3092
3093 Node* receiver_map = LoadReceiverMap(p->receiver);
3094
3095 // Check monomorphic case.
3096 Node* feedback = TryMonomorphicCase(p, receiver_map, &if_handler,
3097 &var_handler, &try_polymorphic);
3098 Bind(&if_handler);
3099 {
3100 HaveLoadICHandler(p, var_handler.value(), &miss);
3101 }
3102
3103 Bind(&try_polymorphic);
3104 {
3105 // Check polymorphic case.
3106 Comment("KeyedLoadIC_try_polymorphic");
3107 GotoUnless(
3108 WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
3109 &try_megamorphic);
3110 HandlePolymorphicCase(p, receiver_map, feedback, &if_handler, &var_handler,
3111 &miss, 2);
3112 }
3113
3114 Bind(&try_megamorphic);
3115 {
3116 // Check megamorphic case.
3117 Comment("KeyedLoadIC_try_megamorphic");
3118 GotoUnless(
3119 WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
3120 &try_polymorphic_name);
3121 // TODO(jkummerow): Inline this? Or some of it?
3122 TailCallStub(CodeFactory::KeyedLoadIC_Megamorphic(isolate()), p->context,
3123 p->receiver, p->name, p->slot, p->vector);
3124 }
3125 Bind(&try_polymorphic_name);
3126 {
3127 // We might have a name in feedback, and a fixed array in the next slot.
3128 Comment("KeyedLoadIC_try_polymorphic_name");
3129 GotoUnless(WordEqual(feedback, p->name), &miss);
3130 // If the name comparison succeeded, we know we have a fixed array with
3131 // at least one map/handler pair.
3132 Node* offset = ElementOffsetFromIndex(
3133 p->slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS,
3134 FixedArray::kHeaderSize + kPointerSize - kHeapObjectTag);
3135 Node* array = Load(MachineType::AnyTagged(), p->vector, offset);
3136 HandlePolymorphicCase(p, receiver_map, array, &if_handler, &var_handler,
3137 &miss, 1);
3138 }
3139 Bind(&miss);
3140 {
3141 Comment("KeyedLoadIC_miss");
3142 TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver,
3143 p->name, p->slot, p->vector);
3144 }
3145 }
3146
3081 void CodeStubAssembler::LoadGlobalIC(const LoadICParameters* p) { 3147 void CodeStubAssembler::LoadGlobalIC(const LoadICParameters* p) {
3082 Label try_handler(this), miss(this); 3148 Label try_handler(this), miss(this);
3083 Node* weak_cell = 3149 Node* weak_cell =
3084 LoadFixedArrayElement(p->vector, p->slot, 0, SMI_PARAMETERS); 3150 LoadFixedArrayElement(p->vector, p->slot, 0, SMI_PARAMETERS);
3085 AssertInstanceType(weak_cell, WEAK_CELL_TYPE); 3151 AssertInstanceType(weak_cell, WEAK_CELL_TYPE);
3086 3152
3087 // Load value or try handler case if the {weak_cell} is cleared. 3153 // Load value or try handler case if the {weak_cell} is cleared.
3088 Node* property_cell = LoadWeakCellValue(weak_cell, &try_handler); 3154 Node* property_cell = LoadWeakCellValue(weak_cell, &try_handler);
3089 AssertInstanceType(property_cell, PROPERTY_CELL_TYPE); 3155 AssertInstanceType(property_cell, PROPERTY_CELL_TYPE);
3090 3156
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
3178 // For all objects but the receiver, check that the cache is empty. 3244 // For all objects but the receiver, check that the cache is empty.
3179 current_map.Bind(LoadMap(current_js_object.value())); 3245 current_map.Bind(LoadMap(current_js_object.value()));
3180 Node* enum_length = EnumLength(current_map.value()); 3246 Node* enum_length = EnumLength(current_map.value());
3181 Node* zero_constant = SmiConstant(Smi::FromInt(0)); 3247 Node* zero_constant = SmiConstant(Smi::FromInt(0));
3182 BranchIf(WordEqual(enum_length, zero_constant), &loop, use_runtime); 3248 BranchIf(WordEqual(enum_length, zero_constant), &loop, use_runtime);
3183 } 3249 }
3184 } 3250 }
3185 3251
3186 } // namespace internal 3252 } // namespace internal
3187 } // namespace v8 3253 } // namespace v8
OLDNEW
« no previous file with comments | « src/code-stub-assembler.h ('k') | src/code-stubs.h » ('j') | src/code-stubs.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698