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/base/bits.h" | 7 #include "src/base/bits.h" |
8 #include "src/base/division-by-constant.h" | 8 #include "src/base/division-by-constant.h" |
9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
(...skipping 3055 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3066 // Check relative positions of allocation top and limit addresses. | 3066 // Check relative positions of allocation top and limit addresses. |
3067 // The values must be adjacent in memory to allow the use of LDP. | 3067 // The values must be adjacent in memory to allow the use of LDP. |
3068 ExternalReference heap_allocation_top = | 3068 ExternalReference heap_allocation_top = |
3069 AllocationUtils::GetAllocationTopReference(isolate(), flags); | 3069 AllocationUtils::GetAllocationTopReference(isolate(), flags); |
3070 ExternalReference heap_allocation_limit = | 3070 ExternalReference heap_allocation_limit = |
3071 AllocationUtils::GetAllocationLimitReference(isolate(), flags); | 3071 AllocationUtils::GetAllocationLimitReference(isolate(), flags); |
3072 intptr_t top = reinterpret_cast<intptr_t>(heap_allocation_top.address()); | 3072 intptr_t top = reinterpret_cast<intptr_t>(heap_allocation_top.address()); |
3073 intptr_t limit = reinterpret_cast<intptr_t>(heap_allocation_limit.address()); | 3073 intptr_t limit = reinterpret_cast<intptr_t>(heap_allocation_limit.address()); |
3074 DCHECK((limit - top) == kPointerSize); | 3074 DCHECK((limit - top) == kPointerSize); |
3075 | 3075 |
3076 // Set up allocation top address and object size registers. | 3076 // Set up allocation top address and allocation limit registers. |
3077 Register top_address = scratch1; | 3077 Register top_address = scratch1; |
3078 Register allocation_limit = scratch2; | 3078 Register alloc_limit = scratch2; |
| 3079 Register result_end = scratch3; |
3079 Mov(top_address, Operand(heap_allocation_top)); | 3080 Mov(top_address, Operand(heap_allocation_top)); |
3080 | 3081 |
3081 if ((flags & RESULT_CONTAINS_TOP) == 0) { | 3082 if ((flags & RESULT_CONTAINS_TOP) == 0) { |
3082 // Load allocation top into result and the allocation limit. | 3083 // Load allocation top into result and allocation limit into alloc_limit. |
3083 Ldp(result, allocation_limit, MemOperand(top_address)); | 3084 Ldp(result, alloc_limit, MemOperand(top_address)); |
3084 } else { | 3085 } else { |
3085 if (emit_debug_code()) { | 3086 if (emit_debug_code()) { |
3086 // Assert that result actually contains top on entry. | 3087 // Assert that result actually contains top on entry. |
3087 Ldr(scratch3, MemOperand(top_address)); | 3088 Ldr(alloc_limit, MemOperand(top_address)); |
3088 Cmp(result, scratch3); | 3089 Cmp(result, alloc_limit); |
3089 Check(eq, kUnexpectedAllocationTop); | 3090 Check(eq, kUnexpectedAllocationTop); |
3090 } | 3091 } |
3091 // Load the allocation limit. 'result' already contains the allocation top. | 3092 // Load allocation limit. Result already contains allocation top. |
3092 Ldr(allocation_limit, MemOperand(top_address, limit - top)); | 3093 Ldr(alloc_limit, MemOperand(top_address, limit - top)); |
3093 } | 3094 } |
3094 | 3095 |
3095 // We can ignore DOUBLE_ALIGNMENT flags here because doubles and pointers have | 3096 // We can ignore DOUBLE_ALIGNMENT flags here because doubles and pointers have |
3096 // the same alignment on ARM64. | 3097 // the same alignment on ARM64. |
3097 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment); | 3098 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment); |
3098 | 3099 |
3099 // Calculate new top and bail out if new space is exhausted. | 3100 // Calculate new top and bail out if new space is exhausted. |
3100 Adds(scratch3, result, object_size); | 3101 Adds(result_end, result, object_size); |
3101 Ccmp(scratch3, allocation_limit, CFlag, cc); | 3102 Ccmp(result_end, alloc_limit, CFlag, cc); |
3102 B(hi, gc_required); | 3103 B(hi, gc_required); |
3103 Str(scratch3, MemOperand(top_address)); | 3104 Str(result_end, MemOperand(top_address)); |
3104 | 3105 |
3105 // Tag the object if requested. | 3106 // Tag the object if requested. |
3106 if ((flags & TAG_OBJECT) != 0) { | 3107 if ((flags & TAG_OBJECT) != 0) { |
3107 ObjectTag(result, result); | 3108 ObjectTag(result, result); |
3108 } | 3109 } |
3109 } | 3110 } |
3110 | 3111 |
3111 | 3112 |
3112 void MacroAssembler::Allocate(Register object_size, Register result, | 3113 void MacroAssembler::Allocate(Register object_size, Register result, |
3113 Register result_end, Register scratch, | 3114 Register result_end, Register scratch, |
3114 Label* gc_required, AllocationFlags flags) { | 3115 Label* gc_required, AllocationFlags flags) { |
3115 if (!FLAG_inline_new) { | 3116 if (!FLAG_inline_new) { |
3116 if (emit_debug_code()) { | 3117 if (emit_debug_code()) { |
3117 // Trash the registers to simulate an allocation failure. | 3118 // Trash the registers to simulate an allocation failure. |
3118 // We apply salt to the original zap value to easily spot the values. | 3119 // We apply salt to the original zap value to easily spot the values. |
3119 Mov(result, (kDebugZapValue & ~0xffL) | 0x11L); | 3120 Mov(result, (kDebugZapValue & ~0xffL) | 0x11L); |
3120 Mov(scratch, (kDebugZapValue & ~0xffL) | 0x21L); | 3121 Mov(scratch, (kDebugZapValue & ~0xffL) | 0x21L); |
3121 Mov(result_end, (kDebugZapValue & ~0xffL) | 0x21L); | 3122 Mov(result_end, (kDebugZapValue & ~0xffL) | 0x21L); |
3122 } | 3123 } |
3123 B(gc_required); | 3124 B(gc_required); |
3124 return; | 3125 return; |
3125 } | 3126 } |
3126 | 3127 |
3127 UseScratchRegisterScope temps(this); | 3128 UseScratchRegisterScope temps(this); |
3128 Register scratch2 = temps.AcquireX(); | 3129 Register scratch2 = temps.AcquireX(); |
3129 | 3130 |
3130 DCHECK(!AreAliased(object_size, result, scratch, scratch2, result_end)); | 3131 // |object_size| and |result_end| may overlap, other registers must not. |
| 3132 DCHECK(!AreAliased(object_size, result, scratch, scratch2)); |
| 3133 DCHECK(!AreAliased(result_end, result, scratch, scratch2)); |
3131 DCHECK(object_size.Is64Bits() && result.Is64Bits() && scratch.Is64Bits() && | 3134 DCHECK(object_size.Is64Bits() && result.Is64Bits() && scratch.Is64Bits() && |
3132 result_end.Is64Bits()); | 3135 result_end.Is64Bits()); |
3133 | 3136 |
3134 // Check relative positions of allocation top and limit addresses. | 3137 // Check relative positions of allocation top and limit addresses. |
3135 // The values must be adjacent in memory to allow the use of LDP. | 3138 // The values must be adjacent in memory to allow the use of LDP. |
3136 ExternalReference heap_allocation_top = | 3139 ExternalReference heap_allocation_top = |
3137 AllocationUtils::GetAllocationTopReference(isolate(), flags); | 3140 AllocationUtils::GetAllocationTopReference(isolate(), flags); |
3138 ExternalReference heap_allocation_limit = | 3141 ExternalReference heap_allocation_limit = |
3139 AllocationUtils::GetAllocationLimitReference(isolate(), flags); | 3142 AllocationUtils::GetAllocationLimitReference(isolate(), flags); |
3140 intptr_t top = reinterpret_cast<intptr_t>(heap_allocation_top.address()); | 3143 intptr_t top = reinterpret_cast<intptr_t>(heap_allocation_top.address()); |
3141 intptr_t limit = reinterpret_cast<intptr_t>(heap_allocation_limit.address()); | 3144 intptr_t limit = reinterpret_cast<intptr_t>(heap_allocation_limit.address()); |
3142 DCHECK((limit - top) == kPointerSize); | 3145 DCHECK((limit - top) == kPointerSize); |
3143 | 3146 |
3144 // Set up allocation top address and object size registers. | 3147 // Set up allocation top address and allocation limit registers. |
3145 Register top_address = scratch; | 3148 Register top_address = scratch; |
3146 Register allocation_limit = scratch2; | 3149 Register alloc_limit = scratch2; |
3147 Mov(top_address, heap_allocation_top); | 3150 Mov(top_address, heap_allocation_top); |
3148 | 3151 |
3149 if ((flags & RESULT_CONTAINS_TOP) == 0) { | 3152 if ((flags & RESULT_CONTAINS_TOP) == 0) { |
3150 // Load allocation top into result and the allocation limit. | 3153 // Load allocation top into result and allocation limit into alloc_limit. |
3151 Ldp(result, allocation_limit, MemOperand(top_address)); | 3154 Ldp(result, alloc_limit, MemOperand(top_address)); |
3152 } else { | 3155 } else { |
3153 if (emit_debug_code()) { | 3156 if (emit_debug_code()) { |
3154 // Assert that result actually contains top on entry. | 3157 // Assert that result actually contains top on entry. |
3155 Ldr(result_end, MemOperand(top_address)); | 3158 Ldr(alloc_limit, MemOperand(top_address)); |
3156 Cmp(result, result_end); | 3159 Cmp(result, alloc_limit); |
3157 Check(eq, kUnexpectedAllocationTop); | 3160 Check(eq, kUnexpectedAllocationTop); |
3158 } | 3161 } |
3159 // Load the allocation limit. 'result' already contains the allocation top. | 3162 // Load allocation limit. Result already contains allocation top. |
3160 Ldr(allocation_limit, MemOperand(top_address, limit - top)); | 3163 Ldr(alloc_limit, MemOperand(top_address, limit - top)); |
3161 } | 3164 } |
3162 | 3165 |
3163 // We can ignore DOUBLE_ALIGNMENT flags here because doubles and pointers have | 3166 // We can ignore DOUBLE_ALIGNMENT flags here because doubles and pointers have |
3164 // the same alignment on ARM64. | 3167 // the same alignment on ARM64. |
3165 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment); | 3168 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment); |
3166 | 3169 |
3167 // Calculate new top and bail out if new space is exhausted | 3170 // Calculate new top and bail out if new space is exhausted |
3168 if ((flags & SIZE_IN_WORDS) != 0) { | 3171 if ((flags & SIZE_IN_WORDS) != 0) { |
3169 Adds(result_end, result, Operand(object_size, LSL, kPointerSizeLog2)); | 3172 Adds(result_end, result, Operand(object_size, LSL, kPointerSizeLog2)); |
3170 } else { | 3173 } else { |
3171 Adds(result_end, result, object_size); | 3174 Adds(result_end, result, object_size); |
3172 } | 3175 } |
3173 | 3176 |
3174 if (emit_debug_code()) { | 3177 if (emit_debug_code()) { |
3175 Tst(result_end, kObjectAlignmentMask); | 3178 Tst(result_end, kObjectAlignmentMask); |
3176 Check(eq, kUnalignedAllocationInNewSpace); | 3179 Check(eq, kUnalignedAllocationInNewSpace); |
3177 } | 3180 } |
3178 | 3181 |
3179 Ccmp(result_end, allocation_limit, CFlag, cc); | 3182 Ccmp(result_end, alloc_limit, CFlag, cc); |
3180 B(hi, gc_required); | 3183 B(hi, gc_required); |
3181 Str(result_end, MemOperand(top_address)); | 3184 Str(result_end, MemOperand(top_address)); |
3182 | 3185 |
3183 // Tag the object if requested. | 3186 // Tag the object if requested. |
3184 if ((flags & TAG_OBJECT) != 0) { | 3187 if ((flags & TAG_OBJECT) != 0) { |
3185 ObjectTag(result, result); | 3188 ObjectTag(result, result); |
3186 } | 3189 } |
3187 } | 3190 } |
3188 | 3191 |
3189 | 3192 |
(...skipping 1873 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5063 } | 5066 } |
5064 | 5067 |
5065 | 5068 |
5066 #undef __ | 5069 #undef __ |
5067 | 5070 |
5068 | 5071 |
5069 } // namespace internal | 5072 } // namespace internal |
5070 } // namespace v8 | 5073 } // namespace v8 |
5071 | 5074 |
5072 #endif // V8_TARGET_ARCH_ARM64 | 5075 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |