Chromium Code Reviews| Index: src/arm/code-stubs-arm.cc |
| diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc |
| index 62eb3e6b8ef0d0cfd077be5a4a6c77b30e42460b..8438efade39c46dbdde498d7cf15fd45511deb6f 100644 |
| --- a/src/arm/code-stubs-arm.cc |
| +++ b/src/arm/code-stubs-arm.cc |
| @@ -3716,32 +3716,47 @@ void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { |
| void TranscendentalCacheStub::Generate(MacroAssembler* masm) { |
| - // Argument is a number and is on stack and in r0. |
| - Label runtime_call; |
| + // Untagged case: double input in d2, double result goes |
| + // into d2. |
| + // Tagged case: tagged input on top of stack and in r0, |
| + // tagged result (heap number) goes into r0. |
| + |
| Label input_not_smi; |
| Label loaded; |
| + Label calculate; |
| + Label invalid_cache; |
| + const Register scratch0 = r9; |
| + const Register scratch1 = r7; |
| + const Register cache_entry = r0; |
| + const bool tagged = (argument_type_ == TAGGED); |
| if (CpuFeatures::IsSupported(VFP3)) { |
| - // Load argument and check if it is a smi. |
| - __ JumpIfNotSmi(r0, &input_not_smi); |
| - |
| CpuFeatures::Scope scope(VFP3); |
| - // Input is a smi. Convert to double and load the low and high words |
| - // of the double into r2, r3. |
| - __ IntegerToDoubleConversionWithVFP3(r0, r3, r2); |
| - __ b(&loaded); |
| - |
| - __ bind(&input_not_smi); |
| - // Check if input is a HeapNumber. |
| - __ CheckMap(r0, |
| - r1, |
| - Heap::kHeapNumberMapRootIndex, |
| - &runtime_call, |
| - true); |
| - // Input is a HeapNumber. Load it to a double register and store the |
| - // low and high words into r2, r3. |
| - __ Ldrd(r2, r3, FieldMemOperand(r0, HeapNumber::kValueOffset)); |
| - |
| + if (tagged) { |
| + // Argument is a number and is on stack and in r0. |
| + // Load argument and check if it is a smi. |
| + __ JumpIfNotSmi(r0, &input_not_smi); |
| + |
| + // Input is a smi. Convert to double and load the low and high words |
| + // of the double into r2, r3. |
| + __ IntegerToDoubleConversionWithVFP3(r0, r3, r2); |
| + __ b(&loaded); |
| + |
| + __ bind(&input_not_smi); |
| + // Check if input is a HeapNumber. |
| + __ CheckMap(r0, |
| + r1, |
| + Heap::kHeapNumberMapRootIndex, |
| + &calculate, |
| + true); |
| + // Input is a HeapNumber. Load it to a double register and store the |
| + // low and high words into r2, r3. |
| + __ vldr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset)); |
| + __ vmov(r2, r3, d0); |
| + } else { |
| + // Input is untagged double in d2. Output goes to d2. |
| + __ vmov(r2, r3, d2); |
| + } |
| __ bind(&loaded); |
| // r2 = low 32 bits of double value |
| // r3 = high 32 bits of double value |
| @@ -3756,14 +3771,15 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) { |
| // r2 = low 32 bits of double value. |
| // r3 = high 32 bits of double value. |
| // r1 = TranscendentalCache::hash(double value). |
| - __ mov(r0, |
| + __ mov(cache_entry, |
| Operand(ExternalReference::transcendental_cache_array_address())); |
| // r0 points to cache array. |
| - __ ldr(r0, MemOperand(r0, type_ * sizeof(TranscendentalCache::caches_[0]))); |
| + __ ldr(cache_entry, MemOperand(cache_entry, |
| + type_ * sizeof(TranscendentalCache::caches_[0]))); |
| // r0 points to the cache for the type type_. |
| // If NULL, the cache hasn't been initialized yet, so go through runtime. |
| - __ cmp(r0, Operand(0, RelocInfo::NONE)); |
| - __ b(eq, &runtime_call); |
| + __ cmp(cache_entry, Operand(0, RelocInfo::NONE)); |
| + __ b(eq, &invalid_cache); |
| #ifdef DEBUG |
| // Check that the layout of cache elements match expectations. |
| @@ -3782,21 +3798,109 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) { |
| // Find the address of the r1'st entry in the cache, i.e., &r0[r1*12]. |
| __ add(r1, r1, Operand(r1, LSL, 1)); |
| - __ add(r0, r0, Operand(r1, LSL, 2)); |
| + __ add(cache_entry, cache_entry, Operand(r1, LSL, 2)); |
| // Check if cache matches: Double value is stored in uint32_t[2] array. |
| - __ ldm(ia, r0, r4.bit()| r5.bit() | r6.bit()); |
| + __ ldm(ia, cache_entry, r4.bit() | r5.bit() | r6.bit()); |
| __ cmp(r2, r4); |
| - __ b(ne, &runtime_call); |
| + __ b(ne, &calculate); |
| __ cmp(r3, r5); |
| - __ b(ne, &runtime_call); |
| - // Cache hit. Load result, pop argument and return. |
| - __ mov(r0, Operand(r6)); |
| - __ pop(); |
| + __ b(ne, &calculate); |
| + // Cache hit. Load result, cleanup and return. |
| + if (tagged) { |
| + // Pop input value from stack and load result into r0. |
| + __ pop(); |
| + __ mov(r0, Operand(r6)); |
| + } else { |
| + // Load result into d2. |
| + __ vldr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset)); |
| + } |
| + __ Ret(); |
| + } // if (CpuFeatures::IsSupported(VFP3)) |
| + |
| + __ bind(&calculate); |
| + if (tagged) { |
| + __ bind(&invalid_cache); |
| + __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); |
| + } else { |
| + if (!CpuFeatures::IsSupported(VFP3)) UNREACHABLE(); |
| + CpuFeatures::Scope scope(VFP3); |
| + |
| + Label no_update; |
| + Label skip_cache; |
| + const Register heap_number_map = r5; |
| + |
| + // Call C function to calculate the result and update the cache. |
| + // Register r0 holds precalculated cache entry address; preserve |
| + // it on the stack and pop it into register cache_entry after the |
| + // call. |
| + __ push(cache_entry); |
| + GenerateCallCFunction(masm, scratch0); |
| + __ GetCFunctionDoubleResult(d2); |
| + |
| + // Try to update the cache. If we cannot allocate a |
| + // heap number, we return the result without updating. |
| + __ pop(cache_entry); |
| + __ LoadRoot(r5, Heap::kHeapNumberMapRootIndex); |
| + __ AllocateHeapNumber(r6, scratch0, scratch1, r5, &no_update); |
| + __ vstr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset)); |
| + __ stm(ia, cache_entry, r2.bit() | r3.bit() | r6.bit()); |
| + __ Ret(); |
| + |
| + __ bind(&invalid_cache); |
| + // The cache is invalid. Call runtime which will recreate the |
| + // cache. |
| + __ LoadRoot(r5, Heap::kHeapNumberMapRootIndex); |
| + __ AllocateHeapNumber(r0, scratch0, scratch1, r5, &skip_cache); |
| + __ vstr(d2, FieldMemOperand(r0, HeapNumber::kValueOffset)); |
| + __ EnterInternalFrame(); |
| + __ push(r0); |
| + __ CallRuntime(RuntimeFunction(), 1); |
| + __ LeaveInternalFrame(); |
| + __ vldr(d2, FieldMemOperand(r0, HeapNumber::kValueOffset)); |
| + __ Ret(); |
| + |
| + __ bind(&skip_cache); |
| + // Call C function to calculate the result and answer directly |
| + // without updating the cache. |
| + GenerateCallCFunction(masm, scratch0); |
| + __ GetCFunctionDoubleResult(d2); |
| + __ bind(&no_update); |
| + |
| + // We return the value in d2 without adding it to the cache, but |
| + // we cause a scavenging GC so that future allocations will succeed. |
| + __ EnterInternalFrame(); |
| + |
| + // Allocate an aligned object larger than a HeapNumber. |
| + ASSERT(4 * kPointerSize >= HeapNumber::kSize); |
| + __ mov(scratch0, Operand(4 * kPointerSize)); |
|
Søren Thygesen Gjesse
2011/03/04 07:44:18
Why not HeapNumber::kSize instead of 4 * kPointerS
|
| + __ push(scratch0); |
| + __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace); |
| + __ LeaveInternalFrame(); |
| __ Ret(); |
| } |
| +} |
| - __ bind(&runtime_call); |
| - __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); |
| + |
| +void TranscendentalCacheStub::GenerateCallCFunction(MacroAssembler* masm, |
| + Register scratch) { |
| + __ push(lr); |
| + __ PrepareCallCFunction(2, scratch); |
| + __ vmov(r0, r1, d2); |
| + switch (type_) { |
| + case TranscendentalCache::SIN: |
| + __ CallCFunction(ExternalReference::math_sin_double_function(), 2); |
| + break; |
| + case TranscendentalCache::COS: |
| + __ CallCFunction(ExternalReference::math_cos_double_function(), 2); |
| + break; |
| + case TranscendentalCache::LOG: |
| + __ CallCFunction(ExternalReference::math_log_double_function(), 2); |
| + break; |
| + default: |
| + UNIMPLEMENTED(); |
| + break; |
| + } |
| + __ pop(lr); |
| } |