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); |
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 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::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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |