OLD | NEW |
---|---|
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 3054 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3065 } | 3065 } |
3066 } | 3066 } |
3067 | 3067 |
3068 | 3068 |
3069 void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { | 3069 void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { |
3070 __ Push(r1, r0); | 3070 __ Push(r1, r0); |
3071 } | 3071 } |
3072 | 3072 |
3073 | 3073 |
3074 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { | 3074 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { |
3075 // Argument is a number and is on stack and in r0. | |
3076 Label runtime_call; | |
3077 Label input_not_smi; | 3075 Label input_not_smi; |
3078 Label loaded; | 3076 Label loaded; |
3077 Label runtime_call; | |
3078 Label invalid_cache; | |
3079 const Register scratch0 = r9; | |
3080 const Register scratch1 = r10; | |
Søren Thygesen Gjesse
2011/03/02 10:09:45
As discussed offline using r10 here is might be th
Karl Klose
2011/03/02 11:16:41
Yes, it is. Used different register.
| |
3081 const Register tagged_input = r7; | |
3082 const bool tagged = (argument_type_ == TAGGED); | |
3079 | 3083 |
3080 if (CpuFeatures::IsSupported(VFP3)) { | 3084 if (CpuFeatures::IsSupported(VFP3)) { |
3081 // Load argument and check if it is a smi. | 3085 CpuFeatures::Scope scope(VFP3); |
3082 __ JumpIfNotSmi(r0, &input_not_smi); | 3086 if (tagged) { |
3087 // Argument is a number and is on stack and in r0. | |
3088 // Load argument and check if it is a smi. | |
3089 __ JumpIfNotSmi(r0, &input_not_smi); | |
3083 | 3090 |
3084 CpuFeatures::Scope scope(VFP3); | 3091 CpuFeatures::Scope scope(VFP3); |
Søren Thygesen Gjesse
2011/03/02 10:09:45
Duplicate CpuFeatures::Scope.
Karl Klose
2011/03/02 11:16:41
Done, removed.
| |
3085 // Input is a smi. Convert to double and load the low and high words | 3092 // Input is a smi. Convert to double and load the low and high words |
3086 // of the double into r2, r3. | 3093 // of the double into r2, r3. |
3087 __ IntegerToDoubleConversionWithVFP3(r0, r3, r2); | 3094 __ IntegerToDoubleConversionWithVFP3(r0, r3, r2); |
3088 __ b(&loaded); | 3095 __ b(&loaded); |
3089 | 3096 |
3090 __ bind(&input_not_smi); | 3097 __ bind(&input_not_smi); |
3091 // Check if input is a HeapNumber. | 3098 // Check if input is a HeapNumber. |
3092 __ CheckMap(r0, | 3099 __ CheckMap(r0, |
3093 r1, | 3100 r1, |
3094 Heap::kHeapNumberMapRootIndex, | 3101 Heap::kHeapNumberMapRootIndex, |
3095 &runtime_call, | 3102 &runtime_call, |
3096 true); | 3103 true); |
3097 // Input is a HeapNumber. Load it to a double register and store the | 3104 // Input is a HeapNumber. Load it to a double register and store the |
3098 // low and high words into r2, r3. | 3105 // low and high words into r2, r3. |
3099 __ Ldrd(r2, r3, FieldMemOperand(r0, HeapNumber::kValueOffset)); | 3106 __ vldr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset)); |
3100 | 3107 __ vmov(r2, r3, d0); |
3108 } else { | |
3109 // Input is untagged double in d2. Output goes to d2. | |
3110 __ vmov(r2, r3, d2); | |
3111 } | |
3101 __ bind(&loaded); | 3112 __ bind(&loaded); |
3102 // r2 = low 32 bits of double value | 3113 // r2 = low 32 bits of double value |
3103 // r3 = high 32 bits of double value | 3114 // r3 = high 32 bits of double value |
3104 // Compute hash (the shifts are arithmetic): | 3115 // Compute hash (the shifts are arithmetic): |
3105 // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1); | 3116 // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1); |
3106 __ eor(r1, r2, Operand(r3)); | 3117 __ eor(r1, r2, Operand(r3)); |
3107 __ eor(r1, r1, Operand(r1, ASR, 16)); | 3118 __ eor(r1, r1, Operand(r1, ASR, 16)); |
3108 __ eor(r1, r1, Operand(r1, ASR, 8)); | 3119 __ eor(r1, r1, Operand(r1, ASR, 8)); |
3109 ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize)); | 3120 ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize)); |
3110 __ And(r1, r1, Operand(TranscendentalCache::kCacheSize - 1)); | 3121 __ And(r1, r1, Operand(TranscendentalCache::kCacheSize - 1)); |
3111 | 3122 |
3112 // r2 = low 32 bits of double value. | 3123 // r2 = low 32 bits of double value. |
3113 // r3 = high 32 bits of double value. | 3124 // r3 = high 32 bits of double value. |
3114 // r1 = TranscendentalCache::hash(double value). | 3125 // r1 = TranscendentalCache::hash(double value). |
3115 __ mov(r0, | 3126 __ mov(r0, |
3116 Operand(ExternalReference::transcendental_cache_array_address())); | 3127 Operand(ExternalReference::transcendental_cache_array_address())); |
3117 // r0 points to cache array. | 3128 // r0 points to cache array. |
3118 __ ldr(r0, MemOperand(r0, type_ * sizeof(TranscendentalCache::caches_[0]))); | 3129 __ ldr(r0, MemOperand(r0, type_ * sizeof(TranscendentalCache::caches_[0]))); |
3119 // r0 points to the cache for the type type_. | 3130 // r0 points to the cache for the type type_. |
3120 // If NULL, the cache hasn't been initialized yet, so go through runtime. | 3131 // If NULL, the cache hasn't been initialized yet, so go through runtime. |
3121 __ cmp(r0, Operand(0, RelocInfo::NONE)); | 3132 __ cmp(r0, Operand(0, RelocInfo::NONE)); |
3122 __ b(eq, &runtime_call); | 3133 __ b(eq, &invalid_cache); |
3123 | 3134 |
3124 #ifdef DEBUG | 3135 #ifdef DEBUG |
3125 // Check that the layout of cache elements match expectations. | 3136 // Check that the layout of cache elements match expectations. |
3126 { TranscendentalCache::Element test_elem[2]; | 3137 { TranscendentalCache::Element test_elem[2]; |
3127 char* elem_start = reinterpret_cast<char*>(&test_elem[0]); | 3138 char* elem_start = reinterpret_cast<char*>(&test_elem[0]); |
3128 char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); | 3139 char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); |
3129 char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0])); | 3140 char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0])); |
3130 char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1])); | 3141 char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1])); |
3131 char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); | 3142 char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); |
3132 CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer. | 3143 CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer. |
3133 CHECK_EQ(0, elem_in0 - elem_start); | 3144 CHECK_EQ(0, elem_in0 - elem_start); |
3134 CHECK_EQ(kIntSize, elem_in1 - elem_start); | 3145 CHECK_EQ(kIntSize, elem_in1 - elem_start); |
3135 CHECK_EQ(2 * kIntSize, elem_out - elem_start); | 3146 CHECK_EQ(2 * kIntSize, elem_out - elem_start); |
3136 } | 3147 } |
3137 #endif | 3148 #endif |
3138 | 3149 |
3139 // Find the address of the r1'st entry in the cache, i.e., &r0[r1*12]. | 3150 // Find the address of the r1'st entry in the cache, i.e., &r0[r1*12]. |
3140 __ add(r1, r1, Operand(r1, LSL, 1)); | 3151 __ add(r1, r1, Operand(r1, LSL, 1)); |
3141 __ add(r0, r0, Operand(r1, LSL, 2)); | 3152 __ add(r0, r0, Operand(r1, LSL, 2)); |
3142 // Check if cache matches: Double value is stored in uint32_t[2] array. | 3153 // Check if cache matches: Double value is stored in uint32_t[2] array. |
3143 __ ldm(ia, r0, r4.bit()| r5.bit() | r6.bit()); | 3154 __ ldm(ia, r0, r4.bit() | r5.bit() | r6.bit()); |
3144 __ cmp(r2, r4); | 3155 __ cmp(r2, r4); |
3145 __ b(ne, &runtime_call); | 3156 __ b(ne, &runtime_call); |
3146 __ cmp(r3, r5); | 3157 __ cmp(r3, r5); |
3147 __ b(ne, &runtime_call); | 3158 __ b(ne, &runtime_call); |
3148 // Cache hit. Load result, pop argument and return. | 3159 // Cache hit. Load result, cleanup and return. |
3149 __ mov(r0, Operand(r6)); | 3160 if (tagged) { |
3150 __ pop(); | 3161 // Pop input value from stack and load result into r0. |
3162 __ pop(); | |
3163 __ mov(r0, Operand(r6)); | |
3164 } else { | |
3165 //__ stop("cache hit"); | |
Søren Thygesen Gjesse
2011/03/02 10:09:45
Debug code.
Karl Klose
2011/03/02 11:16:41
Done.
| |
3166 // Load result into d2. | |
3167 __ vldr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset)); | |
3168 } | |
3169 __ Ret(); | |
3170 } // if (CpuFeatures::IsSupported(VFP3)) | |
Søren Thygesen Gjesse
2011/03/02 10:09:45
Two spaces before //.
Karl Klose
2011/03/02 11:16:41
Done.
| |
3171 | |
3172 __ bind(&runtime_call); | |
Søren Thygesen Gjesse
2011/03/02 10:09:45
Maybe the name of this label should be "calculate"
Karl Klose
2011/03/02 11:16:41
Done.
| |
3173 if (tagged) { | |
3174 __ bind(&invalid_cache); | |
3175 __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); | |
3176 } else { | |
3177 if (!CpuFeatures::IsSupported(VFP3)) UNREACHABLE(); | |
3178 CpuFeatures::Scope scope(VFP3); | |
3179 | |
3180 Register cache_entry = r0; | |
3181 Register heap_number_map = r5; | |
3182 Label no_update; | |
3183 Label skip_cache; | |
3184 | |
3185 // Call C function to calculate the result and update the cache. | |
3186 __ push(r0); | |
Søren Thygesen Gjesse
2011/03/02 10:09:45
r0 -> cache_entry
Karl Klose
2011/03/02 11:16:41
Done.
| |
3187 __ push(lr); | |
Søren Thygesen Gjesse
2011/03/02 10:09:45
The code for calling the C functions are repeated.
Karl Klose
2011/03/02 11:16:41
Done.
| |
3188 __ PrepareCallCFunction(2, scratch0); | |
3189 __ vmov(r0, r1, d2); | |
3190 switch(type_) { | |
3191 case TranscendentalCache::SIN: | |
3192 __ CallCFunction(ExternalReference::math_sin_double_function(), 2); | |
3193 break; | |
3194 case TranscendentalCache::COS: | |
3195 __ CallCFunction(ExternalReference::math_cos_double_function(), 2); | |
3196 break; | |
3197 case TranscendentalCache::LOG: | |
3198 __ CallCFunction(ExternalReference::math_log_double_function(), 2); | |
3199 break; | |
3200 default: | |
3201 UNIMPLEMENTED(); | |
3202 break; | |
3203 } | |
3204 __ pop(lr); | |
3205 __ GetCFunctionDoubleResult(d2); | |
3206 | |
3207 // Try to update the cache. | |
3208 __ pop(cache_entry); | |
3209 | |
3210 // Check if the cache is valid. | |
3211 __ cmp(r0, Operand(0, RelocInfo::NONE)); | |
3212 __ b(&no_update, eq); | |
3213 __ LoadRoot(r5, Heap::kHeapNumberMapRootIndex); | |
3214 __ AllocateHeapNumber(r6, scratch0, scratch1, r5, &no_update); | |
3215 __ vstr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset)); | |
3216 __ stm(ia, cache_entry, r2.bit() | r3.bit() | r6.bit()); | |
3217 __ bind(&no_update); | |
3218 __ Ret(); | |
3219 | |
3220 __ bind(&skip_cache); | |
3221 // Call C function to calculate the result and answer directly | |
3222 // without updating the cache. | |
3223 __ push(lr); | |
3224 __ PrepareCallCFunction(2, scratch0); | |
3225 __ vmov(r0, r1, d2); | |
3226 switch(type_) { | |
3227 case TranscendentalCache::SIN: | |
3228 __ CallCFunction(ExternalReference::math_sin_double_function(), 2); | |
3229 break; | |
3230 case TranscendentalCache::COS: | |
3231 __ CallCFunction(ExternalReference::math_cos_double_function(), 2); | |
3232 break; | |
3233 case TranscendentalCache::LOG: | |
3234 __ CallCFunction(ExternalReference::math_log_double_function(), 2); | |
3235 break; | |
3236 default: | |
3237 UNIMPLEMENTED(); | |
3238 break; | |
3239 } | |
3240 __ pop(lr); | |
3241 __ GetCFunctionDoubleResult(d2); | |
3242 // We return the value in d2 without adding it to the cache, but | |
3243 // we cause a scavenging GC so that future allocations will succeed. | |
3244 __ EnterInternalFrame(); | |
3245 // Allocate an unused object bigger than a HeapNumber. | |
3246 __ mov(scratch0, Operand(Smi::FromInt(2 * kDoubleSize))); | |
Søren Thygesen Gjesse
2011/03/02 10:09:45
Shouldn't HeapNumber::kSize be enough? Allocating
Karl Klose
2011/03/02 11:16:41
Done.
| |
3247 __ push(scratch0); | |
3248 __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace); | |
3249 __ LeaveInternalFrame(); | |
3250 __ Ret(); | |
3251 | |
3252 __ bind(&invalid_cache); | |
3253 // The cache is invalid. Call runtime which will recreate the | |
3254 // cache. | |
3255 __ LoadRoot(r5, Heap::kHeapNumberMapRootIndex); | |
3256 __ AllocateHeapNumber(r6, scratch0, scratch1, r5, &skip_cache); | |
Søren Thygesen Gjesse
2011/03/02 10:09:45
Any reason for having the skip cache code before t
Karl Klose
2011/03/02 11:16:41
There is no reason. I changed the order.
| |
3257 __ vstr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset)); | |
3258 __ EnterInternalFrame(); | |
3259 __ push(r6); | |
3260 __ CallRuntime(RuntimeFunction(), 1); | |
3261 __ LeaveInternalFrame(); | |
3262 __ vldr(d2, FieldMemOperand(r0, HeapNumber::kValueOffset)); | |
3151 __ Ret(); | 3263 __ Ret(); |
3152 } | 3264 } |
3153 | |
3154 __ bind(&runtime_call); | |
3155 __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); | |
3156 } | 3265 } |
3157 | 3266 |
3158 | 3267 |
3159 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { | 3268 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { |
3160 switch (type_) { | 3269 switch (type_) { |
3161 // Add more cases when necessary. | 3270 // Add more cases when necessary. |
3162 case TranscendentalCache::SIN: return Runtime::kMath_sin; | 3271 case TranscendentalCache::SIN: return Runtime::kMath_sin; |
3163 case TranscendentalCache::COS: return Runtime::kMath_cos; | 3272 case TranscendentalCache::COS: return Runtime::kMath_cos; |
3164 case TranscendentalCache::LOG: return Runtime::kMath_log; | 3273 case TranscendentalCache::LOG: return Runtime::kMath_log; |
3165 default: | 3274 default: |
(...skipping 2964 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6130 __ strb(untagged_value, MemOperand(external_pointer, untagged_key)); | 6239 __ strb(untagged_value, MemOperand(external_pointer, untagged_key)); |
6131 __ Ret(); | 6240 __ Ret(); |
6132 } | 6241 } |
6133 | 6242 |
6134 | 6243 |
6135 #undef __ | 6244 #undef __ |
6136 | 6245 |
6137 } } // namespace v8::internal | 6246 } } // namespace v8::internal |
6138 | 6247 |
6139 #endif // V8_TARGET_ARCH_ARM | 6248 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |