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(); |
+ } |
} |