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

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: rebased 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/code-stubs.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/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);
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::HandleLoadICHandlerCase(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 Label inobject_double(this), out_of_object(this),
2998 out_of_object_double(this);
2999 Node* inobject_bit = WordAnd(
3000 handler_word, IntPtrConstant(FieldIndex::FieldOffsetIsInobject::kMask));
3001 Node* double_bit = WordAnd(
3002 handler_word, IntPtrConstant(FieldIndex::FieldOffsetIsDouble::kMask));
3003 Node* offset = WordSar(
3004 handler_word, IntPtrConstant(FieldIndex::FieldOffsetOffset::kShift));
3005
3006 GotoIf(WordEqual(inobject_bit, IntPtrConstant(0)), &out_of_object);
3007
3008 GotoUnless(WordEqual(double_bit, IntPtrConstant(0)), &inobject_double);
3009 Return(LoadObjectField(p->receiver, offset));
3010
3011 Bind(&inobject_double);
3012 if (FLAG_unbox_double_fields) {
3013 var_double_value.Bind(
3014 LoadObjectField(p->receiver, offset, MachineType::Float64()));
3015 } else {
3016 Node* mutable_heap_number = LoadObjectField(p->receiver, offset);
3017 var_double_value.Bind(LoadHeapNumberValue(mutable_heap_number));
3018 }
3019 Goto(&rebox_double);
3020
3021 Bind(&out_of_object);
3022 Node* properties = LoadProperties(p->receiver);
3023 Node* value = LoadObjectField(properties, offset);
3024 GotoUnless(WordEqual(double_bit, IntPtrConstant(0)), &out_of_object_double);
3025 Return(value);
3026
3027 Bind(&out_of_object_double);
3028 var_double_value.Bind(LoadHeapNumberValue(value));
3029 Goto(&rebox_double);
3030
3031 Bind(&rebox_double);
3032 Return(AllocateHeapNumberWithValue(var_double_value.value()));
3033 }
3034
3035 // |handler| is a heap object. Must be code, call it.
3036 Bind(&call_handler);
3037 typedef LoadWithVectorDescriptor Descriptor;
3038 TailCallStub(Descriptor(isolate()), handler, p->context,
3039 Arg(Descriptor::kReceiver, p->receiver),
3040 Arg(Descriptor::kName, p->name),
3041 Arg(Descriptor::kSlot, p->slot),
3042 Arg(Descriptor::kVector, p->vector));
3043 }
3044
2980 void CodeStubAssembler::LoadIC(const LoadICParameters* p) { 3045 void CodeStubAssembler::LoadIC(const LoadICParameters* p) {
2981 Variable var_handler(this, MachineRepresentation::kTagged); 3046 Variable var_handler(this, MachineRepresentation::kTagged);
2982 // TODO(ishell): defer blocks when it works. 3047 // TODO(ishell): defer blocks when it works.
2983 Label if_handler(this, &var_handler), try_polymorphic(this), 3048 Label if_handler(this, &var_handler), try_polymorphic(this),
2984 try_megamorphic(this /*, Label::kDeferred*/), 3049 try_megamorphic(this /*, Label::kDeferred*/),
2985 miss(this /*, Label::kDeferred*/); 3050 miss(this /*, Label::kDeferred*/);
2986 3051
2987 Node* receiver_map = LoadReceiverMap(p->receiver); 3052 Node* receiver_map = LoadReceiverMap(p->receiver);
2988 3053
2989 // Check monomorphic case. 3054 // Check monomorphic case.
2990 Node* feedback = TryMonomorphicCase(p, receiver_map, &if_handler, 3055 Node* feedback = TryMonomorphicCase(p, receiver_map, &if_handler,
2991 &var_handler, &try_polymorphic); 3056 &var_handler, &try_polymorphic);
2992 Bind(&if_handler); 3057 Bind(&if_handler);
2993 { 3058 {
2994 Comment("LoadIC_if_handler"); 3059 HandleLoadICHandlerCase(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 typedef LoadWithVectorDescriptor Descriptor;
3049 TailCallStub(Descriptor(isolate()), var_handler.value(), p->context,
3050 Arg(Descriptor::kReceiver, p->receiver),
3051 Arg(Descriptor::kName, p->name),
3052 Arg(Descriptor::kSlot, p->slot),
3053 Arg(Descriptor::kVector, p->vector));
3054 } 3060 }
3055 3061
3056 Bind(&try_polymorphic); 3062 Bind(&try_polymorphic);
3057 { 3063 {
3058 // Check polymorphic case. 3064 // Check polymorphic case.
3059 Comment("LoadIC_try_polymorphic"); 3065 Comment("LoadIC_try_polymorphic");
3060 GotoUnless( 3066 GotoUnless(
3061 WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)), 3067 WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
3062 &try_megamorphic); 3068 &try_megamorphic);
3063 HandlePolymorphicCase(p, receiver_map, feedback, &if_handler, &var_handler, 3069 HandlePolymorphicCase(p, receiver_map, feedback, &if_handler, &var_handler,
(...skipping 10 matching lines...) Expand all
3074 TryProbeStubCache(isolate()->load_stub_cache(), p->receiver, p->name, 3080 TryProbeStubCache(isolate()->load_stub_cache(), p->receiver, p->name,
3075 &if_handler, &var_handler, &miss); 3081 &if_handler, &var_handler, &miss);
3076 } 3082 }
3077 Bind(&miss); 3083 Bind(&miss);
3078 { 3084 {
3079 TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name, 3085 TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name,
3080 p->slot, p->vector); 3086 p->slot, p->vector);
3081 } 3087 }
3082 } 3088 }
3083 3089
3090 void CodeStubAssembler::KeyedLoadIC(const LoadICParameters* p) {
3091 Variable var_handler(this, MachineRepresentation::kTagged);
3092 // TODO(ishell): defer blocks when it works.
3093 Label if_handler(this, &var_handler), try_polymorphic(this),
3094 try_megamorphic(this /*, Label::kDeferred*/),
3095 try_polymorphic_name(this /*, Label::kDeferred*/),
3096 miss(this /*, Label::kDeferred*/);
3097
3098 Node* receiver_map = LoadReceiverMap(p->receiver);
3099
3100 // Check monomorphic case.
3101 Node* feedback = TryMonomorphicCase(p, receiver_map, &if_handler,
3102 &var_handler, &try_polymorphic);
3103 Bind(&if_handler);
3104 {
3105 HandleLoadICHandlerCase(p, var_handler.value(), &miss);
3106 }
3107
3108 Bind(&try_polymorphic);
3109 {
3110 // Check polymorphic case.
3111 Comment("KeyedLoadIC_try_polymorphic");
3112 GotoUnless(
3113 WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
3114 &try_megamorphic);
3115 HandlePolymorphicCase(p, receiver_map, feedback, &if_handler, &var_handler,
3116 &miss, 2);
3117 }
3118
3119 Bind(&try_megamorphic);
3120 {
3121 // Check megamorphic case.
3122 Comment("KeyedLoadIC_try_megamorphic");
3123 GotoUnless(
3124 WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
3125 &try_polymorphic_name);
3126 // TODO(jkummerow): Inline this? Or some of it?
3127 TailCallStub(CodeFactory::KeyedLoadIC_Megamorphic(isolate()), p->context,
3128 p->receiver, p->name, p->slot, p->vector);
3129 }
3130 Bind(&try_polymorphic_name);
3131 {
3132 // We might have a name in feedback, and a fixed array in the next slot.
3133 Comment("KeyedLoadIC_try_polymorphic_name");
3134 GotoUnless(WordEqual(feedback, p->name), &miss);
3135 // If the name comparison succeeded, we know we have a fixed array with
3136 // at least one map/handler pair.
3137 Node* offset = ElementOffsetFromIndex(
3138 p->slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS,
3139 FixedArray::kHeaderSize + kPointerSize - kHeapObjectTag);
3140 Node* array = Load(MachineType::AnyTagged(), p->vector, offset);
3141 HandlePolymorphicCase(p, receiver_map, array, &if_handler, &var_handler,
3142 &miss, 1);
3143 }
3144 Bind(&miss);
3145 {
3146 Comment("KeyedLoadIC_miss");
3147 TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver,
3148 p->name, p->slot, p->vector);
3149 }
3150 }
3151
3084 void CodeStubAssembler::LoadGlobalIC(const LoadICParameters* p) { 3152 void CodeStubAssembler::LoadGlobalIC(const LoadICParameters* p) {
3085 Label try_handler(this), miss(this); 3153 Label try_handler(this), miss(this);
3086 Node* weak_cell = 3154 Node* weak_cell =
3087 LoadFixedArrayElement(p->vector, p->slot, 0, SMI_PARAMETERS); 3155 LoadFixedArrayElement(p->vector, p->slot, 0, SMI_PARAMETERS);
3088 AssertInstanceType(weak_cell, WEAK_CELL_TYPE); 3156 AssertInstanceType(weak_cell, WEAK_CELL_TYPE);
3089 3157
3090 // Load value or try handler case if the {weak_cell} is cleared. 3158 // Load value or try handler case if the {weak_cell} is cleared.
3091 Node* property_cell = LoadWeakCellValue(weak_cell, &try_handler); 3159 Node* property_cell = LoadWeakCellValue(weak_cell, &try_handler);
3092 AssertInstanceType(property_cell, PROPERTY_CELL_TYPE); 3160 AssertInstanceType(property_cell, PROPERTY_CELL_TYPE);
3093 3161
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
3181 // For all objects but the receiver, check that the cache is empty. 3249 // For all objects but the receiver, check that the cache is empty.
3182 current_map.Bind(LoadMap(current_js_object.value())); 3250 current_map.Bind(LoadMap(current_js_object.value()));
3183 Node* enum_length = EnumLength(current_map.value()); 3251 Node* enum_length = EnumLength(current_map.value());
3184 Node* zero_constant = SmiConstant(Smi::FromInt(0)); 3252 Node* zero_constant = SmiConstant(Smi::FromInt(0));
3185 BranchIf(WordEqual(enum_length, zero_constant), &loop, use_runtime); 3253 BranchIf(WordEqual(enum_length, zero_constant), &loop, use_runtime);
3186 } 3254 }
3187 } 3255 }
3188 3256
3189 } // namespace internal 3257 } // namespace internal
3190 } // namespace v8 3258 } // namespace v8
OLDNEW
« no previous file with comments | « src/code-stub-assembler.h ('k') | src/code-stubs.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698