Chromium Code Reviews| Index: src/arm/code-stubs-arm.cc |
| =================================================================== |
| --- src/arm/code-stubs-arm.cc (revision 6618) |
| +++ src/arm/code-stubs-arm.cc (working copy) |
| @@ -396,6 +396,19 @@ |
| Register scratch1, |
| Register scratch2, |
| Label* not_number); |
| + |
| + // Loads the number from object into dst as a 32-bit integer if possible. If |
| + // the object is not a 32-bit integer control continues at the label |
| + // not_int32. If VFP is supported double_scratch is used but not scratch2. |
| + static void LoadNumberAsInteger(MacroAssembler* masm, |
| + Register object, |
| + Register dst, |
| + Register heap_number_map, |
| + Register scratch1, |
| + Register scratch2, |
| + DwVfpRegister double_scratch, |
| + Label* not_int32); |
| + |
| private: |
| static void LoadNumber(MacroAssembler* masm, |
| FloatingPointHelper::Destination destination, |
| @@ -461,15 +474,21 @@ |
| void FloatingPointHelper::LoadNumber(MacroAssembler* masm, |
| - Destination destination, |
| - Register object, |
| - DwVfpRegister dst, |
| - Register dst1, |
| - Register dst2, |
| - Register heap_number_map, |
| - Register scratch1, |
| - Register scratch2, |
| - Label* not_number) { |
| + Destination destination, |
| + Register object, |
| + DwVfpRegister dst, |
| + Register dst1, |
| + Register dst2, |
| + Register heap_number_map, |
| + Register scratch1, |
| + Register scratch2, |
| + Label* not_number) { |
| + if (FLAG_debug_code) { |
| + __ AbortIfNotRootValue(heap_number_map, |
| + Heap::kHeapNumberMapRootIndex, |
| + "HeapNumberMap register clobbered."); |
| + } |
| + |
| Label is_smi, done; |
| __ JumpIfSmi(object, &is_smi); |
| @@ -514,6 +533,34 @@ |
| } |
| +void FloatingPointHelper::LoadNumberAsInteger(MacroAssembler* masm, |
| + Register object, |
| + Register dst, |
| + Register heap_number_map, |
| + Register scratch1, |
| + Register scratch2, |
| + DwVfpRegister double_scratch, |
| + Label* not_number) { |
|
Karl Klose
2011/02/04 10:19:23
not_number -> not_int32?
Søren Thygesen Gjesse
2011/02/04 10:40:51
Done.
|
| + if (FLAG_debug_code) { |
| + __ AbortIfNotRootValue(heap_number_map, |
| + Heap::kHeapNumberMapRootIndex, |
| + "HeapNumberMap register clobbered."); |
| + } |
| + Label is_smi, done; |
| + __ JumpIfSmi(object, &is_smi); |
| + __ ldr(scratch1, FieldMemOperand(object, HeapNumber::kMapOffset)); |
| + __ cmp(scratch1, heap_number_map); |
| + __ b(ne, not_number); |
| + __ ConvertToInt32( |
| + object, dst, scratch1, scratch2, double_scratch, not_number); |
| + __ jmp(&done); |
| + __ bind(&is_smi); |
| + __ SmiUntag(dst, object); |
| + __ bind(&done); |
| +} |
| + |
| + |
| + |
| // See comment for class. |
| void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) { |
| Label max_negative_int; |
| @@ -1676,7 +1723,7 @@ |
| __ ldr(r4, FieldMemOperand(lhs, HeapNumber::kMapOffset)); |
| __ cmp(r4, heap_number_map); |
| __ b(ne, &slow); |
| - __ ConvertToInt32(lhs, r3, r5, r4, &slow); |
| + __ ConvertToInt32(lhs, r3, r5, r4, d0, &slow); |
| __ jmp(&done_checking_lhs); |
| __ bind(&lhs_is_smi); |
| __ mov(r3, Operand(lhs, ASR, 1)); |
| @@ -1687,7 +1734,7 @@ |
| __ ldr(r4, FieldMemOperand(rhs, HeapNumber::kMapOffset)); |
| __ cmp(r4, heap_number_map); |
| __ b(ne, &slow); |
| - __ ConvertToInt32(rhs, r2, r5, r4, &slow); |
| + __ ConvertToInt32(rhs, r2, r5, r4, d0, &slow); |
| __ jmp(&done_checking_rhs); |
| __ bind(&rhs_is_smi); |
| __ mov(r2, Operand(rhs, ASR, 1)); |
| @@ -2529,6 +2576,18 @@ |
| __ and_(right, left, Operand(scratch1)); |
| __ Ret(); |
| break; |
| + case Token::BIT_OR: |
| + __ orr(right, left, Operand(right)); |
| + __ Ret(); |
| + break; |
| + case Token::BIT_AND: |
| + __ and_(right, left, Operand(right)); |
| + __ Ret(); |
| + break; |
| + case Token::BIT_XOR: |
| + __ eor(right, left, Operand(right)); |
| + __ Ret(); |
| + break; |
| default: |
| UNREACHABLE(); |
| } |
| @@ -2545,90 +2604,177 @@ |
| Register scratch1 = r7; |
| Register scratch2 = r9; |
| - // Load left and right operands into d6 and d7 or r0/r1 and r2/r3 depending |
| - // on whether VFP3 is available. |
| - FloatingPointHelper::Destination destination = |
| - CpuFeatures::IsSupported(VFP3) && op_ != Token::MOD ? |
| - FloatingPointHelper::kVFPRegisters : |
| - FloatingPointHelper::kCoreRegisters; |
| + ASSERT(smi_operands || (not_numbers != NULL)); |
| + if (smi_operands && FLAG_debug_code) { |
| + __ AbortIfNotSmi(left); |
| + __ AbortIfNotSmi(right); |
| + } |
| Register heap_number_map = r6; |
| __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
| - // Allocate new heap number for result. |
| - Register result = r5; |
| - __ AllocateHeapNumber( |
| - result, scratch1, scratch2, heap_number_map, gc_required); |
| + switch (op_) { |
| + case Token::ADD: |
| + case Token::SUB: |
| + case Token::MUL: |
| + case Token::DIV: |
| + case Token::MOD: { |
| + // Load left and right operands into d6 and d7 or r0/r1 and r2/r3 |
| + // depending on whether VFP3 is available or not. |
| + FloatingPointHelper::Destination destination = |
| + CpuFeatures::IsSupported(VFP3) && op_ != Token::MOD ? |
| + FloatingPointHelper::kVFPRegisters : |
| + FloatingPointHelper::kCoreRegisters; |
| - // Load the operands. |
| - if (smi_operands) { |
| - if (FLAG_debug_code) { |
| - __ AbortIfNotSmi(left); |
| - __ AbortIfNotSmi(right); |
| - } |
| - FloatingPointHelper::LoadSmis(masm, destination, scratch1, scratch2); |
| - } else { |
| - FloatingPointHelper::LoadOperands(masm, |
| - destination, |
| - heap_number_map, |
| - scratch1, |
| - scratch2, |
| - not_numbers); |
| - } |
| + // Allocate new heap number for result. |
| + Register result = r5; |
| + __ AllocateHeapNumber( |
| + result, scratch1, scratch2, heap_number_map, gc_required); |
| - // Calculate the result. |
| - if (destination == FloatingPointHelper::kVFPRegisters) { |
| - // Using VFP registers: |
| - // d6: Left value |
| - // d7: Right value |
| - CpuFeatures::Scope scope(VFP3); |
| - switch (op_) { |
| - case Token::ADD: |
| - __ vadd(d5, d6, d7); |
| - break; |
| - case Token::SUB: |
| - __ vsub(d5, d6, d7); |
| - break; |
| - case Token::MUL: |
| - __ vmul(d5, d6, d7); |
| - break; |
| - case Token::DIV: |
| - __ vdiv(d5, d6, d7); |
| - break; |
| - default: |
| - UNREACHABLE(); |
| - } |
| + // Load the operands. |
| + if (smi_operands) { |
| + FloatingPointHelper::LoadSmis(masm, destination, scratch1, scratch2); |
| + } else { |
| + FloatingPointHelper::LoadOperands(masm, |
| + destination, |
| + heap_number_map, |
| + scratch1, |
| + scratch2, |
| + not_numbers); |
| + } |
| - __ sub(r0, result, Operand(kHeapObjectTag)); |
| - __ vstr(d5, r0, HeapNumber::kValueOffset); |
| - __ add(r0, r0, Operand(kHeapObjectTag)); |
| - __ Ret(); |
| - } else { |
| - // Using core registers: |
| - // r0: Left value (least significant part of mantissa). |
| - // r1: Left value (sign, exponent, top of mantissa). |
| - // r2: Right value (least significant part of mantissa). |
| - // r3: Right value (sign, exponent, top of mantissa). |
| + // Calculate the result. |
| + if (destination == FloatingPointHelper::kVFPRegisters) { |
| + // Using VFP registers: |
| + // d6: Left value |
| + // d7: Right value |
| + CpuFeatures::Scope scope(VFP3); |
| + switch (op_) { |
| + case Token::ADD: |
| + __ vadd(d5, d6, d7); |
| + break; |
| + case Token::SUB: |
| + __ vsub(d5, d6, d7); |
| + break; |
| + case Token::MUL: |
| + __ vmul(d5, d6, d7); |
| + break; |
| + case Token::DIV: |
| + __ vdiv(d5, d6, d7); |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + } |
| - __ push(lr); // For later. |
| - __ PrepareCallCFunction(4, scratch1); // Two doubles are 4 arguments. |
| - // Call C routine that may not cause GC or other trouble. r5 is callee |
| - // save. |
| - __ CallCFunction(ExternalReference::double_fp_operation(op_), 4); |
| - // Store answer in the overwritable heap number. |
| + __ sub(r0, result, Operand(kHeapObjectTag)); |
| + __ vstr(d5, r0, HeapNumber::kValueOffset); |
| + __ add(r0, r0, Operand(kHeapObjectTag)); |
| + __ Ret(); |
| + } else { |
| + // Using core registers: |
| + // r0: Left value (least significant part of mantissa). |
| + // r1: Left value (sign, exponent, top of mantissa). |
| + // r2: Right value (least significant part of mantissa). |
| + // r3: Right value (sign, exponent, top of mantissa). |
| + |
| + __ push(lr); // For later. |
|
Karl Klose
2011/02/04 10:19:23
Where is it used later?
Søren Thygesen Gjesse
2011/02/04 10:40:51
There is a pop(pc) below to return. I have updated
|
| + __ PrepareCallCFunction(4, scratch1); // Two doubles are 4 arguments. |
| + // Call C routine that may not cause GC or other trouble. r5 is callee |
| + // save. |
| + __ CallCFunction(ExternalReference::double_fp_operation(op_), 4); |
| + // Store answer in the overwritable heap number. |
| #if !defined(USE_ARM_EABI) |
| - // Double returned in fp coprocessor register 0 and 1, encoded as |
| - // register cr8. Offsets must be divisible by 4 for coprocessor so we |
| - // need to substract the tag from r5. |
| - __ sub(scratch1, result, Operand(kHeapObjectTag)); |
| - __ stc(p1, cr8, MemOperand(scratch1, HeapNumber::kValueOffset)); |
| + // Double returned in fp coprocessor register 0 and 1, encoded as |
| + // register cr8. Offsets must be divisible by 4 for coprocessor so we |
| + // need to substract the tag from r5. |
| + __ sub(scratch1, result, Operand(kHeapObjectTag)); |
| + __ stc(p1, cr8, MemOperand(scratch1, HeapNumber::kValueOffset)); |
| #else |
| - // Double returned in registers 0 and 1. |
| - __ Strd(r0, r1, FieldMemOperand(result, HeapNumber::kValueOffset)); |
| + // Double returned in registers 0 and 1. |
| + __ Strd(r0, r1, FieldMemOperand(result, HeapNumber::kValueOffset)); |
| #endif |
| - __ mov(r0, Operand(result)); |
| - // And we are done. |
| - __ pop(pc); |
| + __ mov(r0, Operand(result)); |
| + // And we are done. |
| + __ pop(pc); |
| + } |
| + break; |
| + } |
| + case Token::BIT_OR: |
| + case Token::BIT_XOR: |
| + case Token::BIT_AND: { |
| + if (smi_operands) { |
| + __ SmiUntag(r3, left); |
| + __ SmiUntag(r2, right); |
| + } else { |
| + // Convert operands to 32-bit integers. Right in r2 and left in r3. |
| + FloatingPointHelper::LoadNumberAsInteger(masm, |
| + left, |
| + r3, |
| + heap_number_map, |
| + scratch1, |
| + scratch2, |
| + d0, |
| + not_numbers); |
| + FloatingPointHelper::LoadNumberAsInteger(masm, |
| + right, |
| + r2, |
| + heap_number_map, |
| + scratch1, |
| + scratch2, |
| + d0, |
| + not_numbers); |
| + } |
| + switch (op_) { |
| + case Token::BIT_OR: |
| + __ orr(r2, r3, Operand(r2)); |
| + break; |
| + case Token::BIT_XOR: |
| + __ eor(r2, r3, Operand(r2)); |
| + break; |
| + case Token::BIT_AND: |
| + __ and_(r2, r3, Operand(r2)); |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + } |
| + |
| + Label result_not_a_smi; |
| + // Check that the *signed* result fits in a smi. |
| + __ add(r3, r2, Operand(0x40000000), SetCC); |
| + __ b(mi, &result_not_a_smi); |
| + __ SmiTag(r0, r2); |
| + __ Ret(); |
| + |
| + // Allocate new heap number for result. |
| + __ bind(&result_not_a_smi); |
| + __ AllocateHeapNumber( |
| + r5, scratch1, scratch2, heap_number_map, gc_required); |
| + |
| + // r2: Answer as signed int32. |
| + // r5: Heap number to write answer into. |
| + |
| + // Nothing can go wrong now, so move the heap number to r0, which is the |
| + // result. |
| + __ mov(r0, Operand(r5)); |
| + |
| + if (CpuFeatures::IsSupported(VFP3)) { |
| + // Convert the int32 in r2 to the heap number in r0. r3 is corrupted. |
| + CpuFeatures::Scope scope(VFP3); |
| + __ vmov(s0, r2); |
| + __ vcvt_f64_s32(d0, s0); |
| + __ sub(r3, r0, Operand(kHeapObjectTag)); |
| + __ vstr(d0, r3, HeapNumber::kValueOffset); |
| + __ Ret(); |
| + } else { |
| + // Tail call that writes the int32 in r2 to the heap number in r0, using |
| + // r3 as scratch. r0 is preserved and returned. |
| + WriteInt32ToHeapNumberStub stub(r2, r0, r3); |
| + __ TailCallStub(&stub); |
| + } |
| + break; |
| + } |
| + default: |
| + UNREACHABLE(); |
| } |
| } |
| @@ -2646,7 +2792,10 @@ |
| op_ == Token::SUB || |
| op_ == Token::MUL || |
| op_ == Token::DIV || |
| - op_ == Token::MOD); |
| + op_ == Token::MOD || |
| + op_ == Token::BIT_OR || |
| + op_ == Token::BIT_AND || |
| + op_ == Token::BIT_XOR); |
| Register left = r1; |
| Register right = r0; |
| @@ -2678,7 +2827,10 @@ |
| op_ == Token::SUB || |
| op_ == Token::MUL || |
| op_ == Token::DIV || |
| - op_ == Token::MOD); |
| + op_ == Token::MOD || |
| + op_ == Token::BIT_OR || |
| + op_ == Token::BIT_AND || |
| + op_ == Token::BIT_XOR); |
| if (result_type_ == TRBinaryOpIC::UNINITIALIZED || |
| result_type_ == TRBinaryOpIC::SMI) { |
| @@ -2714,7 +2866,10 @@ |
| op_ == Token::SUB || |
| op_ == Token::MUL || |
| op_ == Token::DIV || |
| - op_ == Token::MOD); |
| + op_ == Token::MOD || |
| + op_ == Token::BIT_OR || |
| + op_ == Token::BIT_AND || |
| + op_ == Token::BIT_XOR); |
| ASSERT(operands_type_ == TRBinaryOpIC::INT32); |
| @@ -2727,7 +2882,10 @@ |
| op_ == Token::SUB || |
| op_ == Token::MUL || |
| op_ == Token::DIV || |
| - op_ == Token::MOD); |
| + op_ == Token::MOD || |
| + op_ == Token::BIT_OR || |
| + op_ == Token::BIT_AND || |
| + op_ == Token::BIT_XOR); |
| Label not_numbers, call_runtime; |
| ASSERT(operands_type_ == TRBinaryOpIC::HEAP_NUMBER); |
| @@ -2747,7 +2905,10 @@ |
| op_ == Token::SUB || |
| op_ == Token::MUL || |
| op_ == Token::DIV || |
| - op_ == Token::MOD); |
| + op_ == Token::MOD || |
| + op_ == Token::BIT_OR || |
| + op_ == Token::BIT_AND || |
| + op_ == Token::BIT_XOR); |
| Label call_runtime; |
| @@ -2812,6 +2973,15 @@ |
| case Token::MOD: |
| __ InvokeBuiltin(Builtins::MOD, JUMP_JS); |
| break; |
| + case Token::BIT_OR: |
| + __ InvokeBuiltin(Builtins::BIT_OR, JUMP_JS); |
| + break; |
| + case Token::BIT_AND: |
| + __ InvokeBuiltin(Builtins::BIT_AND, JUMP_JS); |
| + break; |
| + case Token::BIT_XOR: |
| + __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_JS); |
| + break; |
| default: |
| UNREACHABLE(); |
| } |
| @@ -3037,7 +3207,7 @@ |
| __ b(ne, &slow); |
| // Convert the heap number is r0 to an untagged integer in r1. |
| - __ ConvertToInt32(r0, r1, r2, r3, &slow); |
| + __ ConvertToInt32(r0, r1, r2, r3, d0, &slow); |
| // Do the bitwise operation (move negated) and check if the result |
| // fits in a smi. |