| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 #if V8_TARGET_ARCH_ARM64 | 5 #if V8_TARGET_ARCH_ARM64 |
| 6 | 6 |
| 7 #include "src/code-stubs.h" | 7 #include "src/code-stubs.h" |
| 8 #include "src/api-arguments.h" | 8 #include "src/api-arguments.h" |
| 9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
| 10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
| (...skipping 2962 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2973 // Return to IC Miss stub, continuation still on stack. | 2973 // Return to IC Miss stub, continuation still on stack. |
| 2974 __ Ret(); | 2974 __ Ret(); |
| 2975 } | 2975 } |
| 2976 | 2976 |
| 2977 void CallICTrampolineStub::Generate(MacroAssembler* masm) { | 2977 void CallICTrampolineStub::Generate(MacroAssembler* masm) { |
| 2978 __ EmitLoadTypeFeedbackVector(x2); | 2978 __ EmitLoadTypeFeedbackVector(x2); |
| 2979 CallICStub stub(isolate(), state()); | 2979 CallICStub stub(isolate(), state()); |
| 2980 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); | 2980 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); |
| 2981 } | 2981 } |
| 2982 | 2982 |
| 2983 | |
| 2984 static void HandleArrayCases(MacroAssembler* masm, Register feedback, | |
| 2985 Register receiver_map, Register scratch1, | |
| 2986 Register scratch2, bool is_polymorphic, | |
| 2987 Label* miss) { | |
| 2988 // feedback initially contains the feedback array | |
| 2989 Label next_loop, prepare_next; | |
| 2990 Label load_smi_map, compare_map; | |
| 2991 Label start_polymorphic; | |
| 2992 | |
| 2993 Register cached_map = scratch1; | |
| 2994 | |
| 2995 __ Ldr(cached_map, | |
| 2996 FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(0))); | |
| 2997 __ Ldr(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset)); | |
| 2998 __ Cmp(receiver_map, cached_map); | |
| 2999 __ B(ne, &start_polymorphic); | |
| 3000 // found, now call handler. | |
| 3001 Register handler = feedback; | |
| 3002 __ Ldr(handler, FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(1))); | |
| 3003 __ Add(handler, handler, Code::kHeaderSize - kHeapObjectTag); | |
| 3004 __ Jump(feedback); | |
| 3005 | |
| 3006 Register length = scratch2; | |
| 3007 __ Bind(&start_polymorphic); | |
| 3008 __ Ldr(length, FieldMemOperand(feedback, FixedArray::kLengthOffset)); | |
| 3009 if (!is_polymorphic) { | |
| 3010 __ Cmp(length, Operand(Smi::FromInt(2))); | |
| 3011 __ B(eq, miss); | |
| 3012 } | |
| 3013 | |
| 3014 Register too_far = length; | |
| 3015 Register pointer_reg = feedback; | |
| 3016 | |
| 3017 // +-----+------+------+-----+-----+ ... ----+ | |
| 3018 // | map | len | wm0 | h0 | wm1 | hN | | |
| 3019 // +-----+------+------+-----+-----+ ... ----+ | |
| 3020 // 0 1 2 len-1 | |
| 3021 // ^ ^ | |
| 3022 // | | | |
| 3023 // pointer_reg too_far | |
| 3024 // aka feedback scratch2 | |
| 3025 // also need receiver_map | |
| 3026 // use cached_map (scratch1) to look in the weak map values. | |
| 3027 __ Add(too_far, feedback, | |
| 3028 Operand::UntagSmiAndScale(length, kPointerSizeLog2)); | |
| 3029 __ Add(too_far, too_far, FixedArray::kHeaderSize - kHeapObjectTag); | |
| 3030 __ Add(pointer_reg, feedback, | |
| 3031 FixedArray::OffsetOfElementAt(2) - kHeapObjectTag); | |
| 3032 | |
| 3033 __ Bind(&next_loop); | |
| 3034 __ Ldr(cached_map, MemOperand(pointer_reg)); | |
| 3035 __ Ldr(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset)); | |
| 3036 __ Cmp(receiver_map, cached_map); | |
| 3037 __ B(ne, &prepare_next); | |
| 3038 __ Ldr(handler, MemOperand(pointer_reg, kPointerSize)); | |
| 3039 __ Add(handler, handler, Code::kHeaderSize - kHeapObjectTag); | |
| 3040 __ Jump(handler); | |
| 3041 | |
| 3042 __ Bind(&prepare_next); | |
| 3043 __ Add(pointer_reg, pointer_reg, kPointerSize * 2); | |
| 3044 __ Cmp(pointer_reg, too_far); | |
| 3045 __ B(lt, &next_loop); | |
| 3046 | |
| 3047 // We exhausted our array of map handler pairs. | |
| 3048 __ jmp(miss); | |
| 3049 } | |
| 3050 | |
| 3051 | |
| 3052 static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver, | |
| 3053 Register receiver_map, Register feedback, | |
| 3054 Register vector, Register slot, | |
| 3055 Register scratch, Label* compare_map, | |
| 3056 Label* load_smi_map, Label* try_array) { | |
| 3057 __ JumpIfSmi(receiver, load_smi_map); | |
| 3058 __ Ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
| 3059 __ bind(compare_map); | |
| 3060 Register cached_map = scratch; | |
| 3061 // Move the weak map into the weak_cell register. | |
| 3062 __ Ldr(cached_map, FieldMemOperand(feedback, WeakCell::kValueOffset)); | |
| 3063 __ Cmp(cached_map, receiver_map); | |
| 3064 __ B(ne, try_array); | |
| 3065 | |
| 3066 Register handler = feedback; | |
| 3067 __ Add(handler, vector, Operand::UntagSmiAndScale(slot, kPointerSizeLog2)); | |
| 3068 __ Ldr(handler, | |
| 3069 FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize)); | |
| 3070 __ Add(handler, handler, Code::kHeaderSize - kHeapObjectTag); | |
| 3071 __ Jump(handler); | |
| 3072 } | |
| 3073 | |
| 3074 void KeyedStoreICTrampolineStub::Generate(MacroAssembler* masm) { | |
| 3075 __ EmitLoadTypeFeedbackVector(StoreWithVectorDescriptor::VectorRegister()); | |
| 3076 KeyedStoreICStub stub(isolate(), state()); | |
| 3077 stub.GenerateForTrampoline(masm); | |
| 3078 } | |
| 3079 | |
| 3080 void KeyedStoreICStub::Generate(MacroAssembler* masm) { | |
| 3081 GenerateImpl(masm, false); | |
| 3082 } | |
| 3083 | |
| 3084 void KeyedStoreICStub::GenerateForTrampoline(MacroAssembler* masm) { | |
| 3085 GenerateImpl(masm, true); | |
| 3086 } | |
| 3087 | |
| 3088 | |
| 3089 static void HandlePolymorphicStoreCase(MacroAssembler* masm, Register feedback, | |
| 3090 Register receiver_map, Register scratch1, | |
| 3091 Register scratch2, Label* miss) { | |
| 3092 // feedback initially contains the feedback array | |
| 3093 Label next_loop, prepare_next; | |
| 3094 Label start_polymorphic; | |
| 3095 Label transition_call; | |
| 3096 | |
| 3097 Register cached_map = scratch1; | |
| 3098 Register too_far = scratch2; | |
| 3099 Register pointer_reg = feedback; | |
| 3100 | |
| 3101 __ Ldr(too_far, FieldMemOperand(feedback, FixedArray::kLengthOffset)); | |
| 3102 | |
| 3103 // +-----+------+------+-----+-----+-----+ ... ----+ | |
| 3104 // | map | len | wm0 | wt0 | h0 | wm1 | hN | | |
| 3105 // +-----+------+------+-----+-----+ ----+ ... ----+ | |
| 3106 // 0 1 2 len-1 | |
| 3107 // ^ ^ | |
| 3108 // | | | |
| 3109 // pointer_reg too_far | |
| 3110 // aka feedback scratch2 | |
| 3111 // also need receiver_map | |
| 3112 // use cached_map (scratch1) to look in the weak map values. | |
| 3113 __ Add(too_far, feedback, | |
| 3114 Operand::UntagSmiAndScale(too_far, kPointerSizeLog2)); | |
| 3115 __ Add(too_far, too_far, FixedArray::kHeaderSize - kHeapObjectTag); | |
| 3116 __ Add(pointer_reg, feedback, | |
| 3117 FixedArray::OffsetOfElementAt(0) - kHeapObjectTag); | |
| 3118 | |
| 3119 __ Bind(&next_loop); | |
| 3120 __ Ldr(cached_map, MemOperand(pointer_reg)); | |
| 3121 __ Ldr(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset)); | |
| 3122 __ Cmp(receiver_map, cached_map); | |
| 3123 __ B(ne, &prepare_next); | |
| 3124 // Is it a transitioning store? | |
| 3125 __ Ldr(too_far, MemOperand(pointer_reg, kPointerSize)); | |
| 3126 __ CompareRoot(too_far, Heap::kUndefinedValueRootIndex); | |
| 3127 __ B(ne, &transition_call); | |
| 3128 | |
| 3129 __ Ldr(pointer_reg, MemOperand(pointer_reg, kPointerSize * 2)); | |
| 3130 __ Add(pointer_reg, pointer_reg, Code::kHeaderSize - kHeapObjectTag); | |
| 3131 __ Jump(pointer_reg); | |
| 3132 | |
| 3133 __ Bind(&transition_call); | |
| 3134 __ Ldr(too_far, FieldMemOperand(too_far, WeakCell::kValueOffset)); | |
| 3135 __ JumpIfSmi(too_far, miss); | |
| 3136 | |
| 3137 __ Ldr(receiver_map, MemOperand(pointer_reg, kPointerSize * 2)); | |
| 3138 // Load the map into the correct register. | |
| 3139 DCHECK(feedback.is(StoreTransitionDescriptor::MapRegister())); | |
| 3140 __ mov(feedback, too_far); | |
| 3141 __ Add(receiver_map, receiver_map, Code::kHeaderSize - kHeapObjectTag); | |
| 3142 __ Jump(receiver_map); | |
| 3143 | |
| 3144 __ Bind(&prepare_next); | |
| 3145 __ Add(pointer_reg, pointer_reg, kPointerSize * 3); | |
| 3146 __ Cmp(pointer_reg, too_far); | |
| 3147 __ B(lt, &next_loop); | |
| 3148 | |
| 3149 // We exhausted our array of map handler pairs. | |
| 3150 __ jmp(miss); | |
| 3151 } | |
| 3152 | |
| 3153 void KeyedStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { | |
| 3154 Register receiver = StoreWithVectorDescriptor::ReceiverRegister(); // x1 | |
| 3155 Register key = StoreWithVectorDescriptor::NameRegister(); // x2 | |
| 3156 Register vector = StoreWithVectorDescriptor::VectorRegister(); // x3 | |
| 3157 Register slot = StoreWithVectorDescriptor::SlotRegister(); // x4 | |
| 3158 DCHECK(StoreWithVectorDescriptor::ValueRegister().is(x0)); // x0 | |
| 3159 Register feedback = x5; | |
| 3160 Register receiver_map = x6; | |
| 3161 Register scratch1 = x7; | |
| 3162 | |
| 3163 __ Add(feedback, vector, Operand::UntagSmiAndScale(slot, kPointerSizeLog2)); | |
| 3164 __ Ldr(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize)); | |
| 3165 | |
| 3166 // Try to quickly handle the monomorphic case without knowing for sure | |
| 3167 // if we have a weak cell in feedback. We do know it's safe to look | |
| 3168 // at WeakCell::kValueOffset. | |
| 3169 Label try_array, load_smi_map, compare_map; | |
| 3170 Label not_array, miss; | |
| 3171 HandleMonomorphicCase(masm, receiver, receiver_map, feedback, vector, slot, | |
| 3172 scratch1, &compare_map, &load_smi_map, &try_array); | |
| 3173 | |
| 3174 __ Bind(&try_array); | |
| 3175 // Is it a fixed array? | |
| 3176 __ Ldr(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset)); | |
| 3177 __ JumpIfNotRoot(scratch1, Heap::kFixedArrayMapRootIndex, ¬_array); | |
| 3178 | |
| 3179 // We have a polymorphic element handler. | |
| 3180 Label try_poly_name; | |
| 3181 HandlePolymorphicStoreCase(masm, feedback, receiver_map, scratch1, x8, &miss); | |
| 3182 | |
| 3183 __ Bind(¬_array); | |
| 3184 // Is it generic? | |
| 3185 __ JumpIfNotRoot(feedback, Heap::kmegamorphic_symbolRootIndex, | |
| 3186 &try_poly_name); | |
| 3187 Handle<Code> megamorphic_stub = | |
| 3188 KeyedStoreIC::ChooseMegamorphicStub(masm->isolate(), GetExtraICState()); | |
| 3189 __ Jump(megamorphic_stub, RelocInfo::CODE_TARGET); | |
| 3190 | |
| 3191 __ Bind(&try_poly_name); | |
| 3192 // We might have a name in feedback, and a fixed array in the next slot. | |
| 3193 __ Cmp(key, feedback); | |
| 3194 __ B(ne, &miss); | |
| 3195 // If the name comparison succeeded, we know we have a fixed array with | |
| 3196 // at least one map/handler pair. | |
| 3197 __ Add(feedback, vector, Operand::UntagSmiAndScale(slot, kPointerSizeLog2)); | |
| 3198 __ Ldr(feedback, | |
| 3199 FieldMemOperand(feedback, FixedArray::kHeaderSize + kPointerSize)); | |
| 3200 HandleArrayCases(masm, feedback, receiver_map, scratch1, x8, false, &miss); | |
| 3201 | |
| 3202 __ Bind(&miss); | |
| 3203 KeyedStoreIC::GenerateMiss(masm); | |
| 3204 | |
| 3205 __ Bind(&load_smi_map); | |
| 3206 __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex); | |
| 3207 __ jmp(&compare_map); | |
| 3208 } | |
| 3209 | |
| 3210 | |
| 3211 // The entry hook is a "BumpSystemStackPointer" instruction (sub), followed by | 2983 // The entry hook is a "BumpSystemStackPointer" instruction (sub), followed by |
| 3212 // a "Push lr" instruction, followed by a call. | 2984 // a "Push lr" instruction, followed by a call. |
| 3213 static const unsigned int kProfileEntryHookCallSize = | 2985 static const unsigned int kProfileEntryHookCallSize = |
| 3214 Assembler::kCallSizeWithRelocation + (2 * kInstructionSize); | 2986 Assembler::kCallSizeWithRelocation + (2 * kInstructionSize); |
| 3215 | 2987 |
| 3216 | 2988 |
| 3217 void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) { | 2989 void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) { |
| 3218 if (masm->isolate()->function_entry_hook() != NULL) { | 2990 if (masm->isolate()->function_entry_hook() != NULL) { |
| 3219 ProfileEntryHookStub stub(masm->isolate()); | 2991 ProfileEntryHookStub stub(masm->isolate()); |
| 3220 Assembler::BlockConstPoolScope no_const_pools(masm); | 2992 Assembler::BlockConstPoolScope no_const_pools(masm); |
| (...skipping 1691 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4912 kStackUnwindSpace, NULL, spill_offset, | 4684 kStackUnwindSpace, NULL, spill_offset, |
| 4913 return_value_operand, NULL); | 4685 return_value_operand, NULL); |
| 4914 } | 4686 } |
| 4915 | 4687 |
| 4916 #undef __ | 4688 #undef __ |
| 4917 | 4689 |
| 4918 } // namespace internal | 4690 } // namespace internal |
| 4919 } // namespace v8 | 4691 } // namespace v8 |
| 4920 | 4692 |
| 4921 #endif // V8_TARGET_ARCH_ARM64 | 4693 #endif // V8_TARGET_ARCH_ARM64 |
| OLD | NEW |