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/stub-cache.h" | 9 #include "src/ic/stub-cache.h" |
10 | 10 |
(...skipping 2398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |