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 7d374eecd79829f84b147fcd3f4f833bc4745ece..5d5c6c793e094583b7e5f770fc0f3a0a8add57ec 100644 |
| --- a/src/arm/code-stubs-arm.cc |
| +++ b/src/arm/code-stubs-arm.cc |
| @@ -3072,32 +3072,43 @@ void TypeRecordingBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { |
| void TranscendentalCacheStub::Generate(MacroAssembler* masm) { |
| - // Argument is a number and is on stack and in r0. |
| - Label runtime_call; |
| Label input_not_smi; |
| Label loaded; |
| + Label runtime_call; |
| + Label invalid_cache; |
| + const Register scratch0 = r9; |
| + 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.
|
| + const Register tagged_input = r7; |
| + 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); |
| + 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.
|
| + // 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. |
| + __ 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 |
| @@ -3119,7 +3130,7 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) { |
| // 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); |
| + __ b(eq, &invalid_cache); |
| #ifdef DEBUG |
| // Check that the layout of cache elements match expectations. |
| @@ -3140,19 +3151,117 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) { |
| __ add(r1, r1, Operand(r1, LSL, 1)); |
| __ add(r0, r0, 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, r0, r4.bit() | r5.bit() | r6.bit()); |
| __ cmp(r2, r4); |
| __ b(ne, &runtime_call); |
| __ cmp(r3, r5); |
| __ b(ne, &runtime_call); |
| - // Cache hit. Load result, pop argument and return. |
| - __ mov(r0, Operand(r6)); |
| - __ pop(); |
| + // 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 { |
| + //__ stop("cache hit"); |
|
Søren Thygesen Gjesse
2011/03/02 10:09:45
Debug code.
Karl Klose
2011/03/02 11:16:41
Done.
|
| + // Load result into d2. |
| + __ vldr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset)); |
| + } |
| __ Ret(); |
| - } |
| + } // 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.
|
| __ 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.
|
| - __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); |
| + if (tagged) { |
| + __ bind(&invalid_cache); |
| + __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); |
| + } else { |
| + if (!CpuFeatures::IsSupported(VFP3)) UNREACHABLE(); |
| + CpuFeatures::Scope scope(VFP3); |
| + |
| + Register cache_entry = r0; |
| + Register heap_number_map = r5; |
| + Label no_update; |
| + Label skip_cache; |
| + |
| + // Call C function to calculate the result and update the cache. |
| + __ push(r0); |
|
Søren Thygesen Gjesse
2011/03/02 10:09:45
r0 -> cache_entry
Karl Klose
2011/03/02 11:16:41
Done.
|
| + __ 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.
|
| + __ PrepareCallCFunction(2, scratch0); |
| + __ 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); |
| + __ GetCFunctionDoubleResult(d2); |
| + |
| + // Try to update the cache. |
| + __ pop(cache_entry); |
| + |
| + // Check if the cache is valid. |
| + __ cmp(r0, Operand(0, RelocInfo::NONE)); |
| + __ b(&no_update, eq); |
| + __ 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()); |
| + __ bind(&no_update); |
| + __ Ret(); |
| + |
| + __ bind(&skip_cache); |
| + // Call C function to calculate the result and answer directly |
| + // without updating the cache. |
| + __ push(lr); |
| + __ PrepareCallCFunction(2, scratch0); |
| + __ 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); |
| + __ GetCFunctionDoubleResult(d2); |
| + // 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 unused object bigger than a HeapNumber. |
| + __ 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.
|
| + __ push(scratch0); |
| + __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace); |
| + __ LeaveInternalFrame(); |
| + __ Ret(); |
| + |
| + __ bind(&invalid_cache); |
| + // The cache is invalid. Call runtime which will recreate the |
| + // cache. |
| + __ LoadRoot(r5, Heap::kHeapNumberMapRootIndex); |
| + __ 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.
|
| + __ vstr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset)); |
| + __ EnterInternalFrame(); |
| + __ push(r6); |
| + __ CallRuntime(RuntimeFunction(), 1); |
| + __ LeaveInternalFrame(); |
| + __ vldr(d2, FieldMemOperand(r0, HeapNumber::kValueOffset)); |
| + __ Ret(); |
| + } |
| } |