Index: src/arm/lithium-codegen-arm.cc |
=================================================================== |
--- src/arm/lithium-codegen-arm.cc (revision 6231) |
+++ src/arm/lithium-codegen-arm.cc (working copy) |
@@ -1380,15 +1380,64 @@ |
} |
-// Branches to a label or falls through with the answer in the z flag. Trashes |
-// the temp registers, but not the input. Only input and temp2 may alias. |
+// Branches to a label or falls through with the answer in the z flag. Trashes |
+// the temp registers, but not the input. Only input and temp2 may alias. |
Søren Thygesen Gjesse
2011/01/10 09:56:08
input is trashed if temp2 aliases it.
Alexandre
2011/01/10 10:48:27
Indeed. Changed the code to have input and temp2 a
|
void LCodeGen::EmitClassOfTest(Label* is_true, |
Label* is_false, |
Handle<String>class_name, |
Register input, |
Register temp, |
Register temp2) { |
- Abort("EmitClassOfTest unimplemented."); |
+ ASSERT(!input.is(temp)); |
+ ASSERT(!temp.is(temp2)); // But input and temp2 may be the same register. |
+ |
+ __ BranchOnSmi(input, is_false); |
+ |
+ __ CompareObjectType(input, temp, temp2, FIRST_JS_OBJECT_TYPE); |
+ __ b(lt, is_false); |
+ |
Søren Thygesen Gjesse
2011/01/10 09:56:08
How about just
// temp: map of input
// temp2: o
Alexandre
2011/01/10 10:48:27
Done.
|
+ // After CompareObjectType: |
+ // - Input's map is in temp. |
+ // - Input's type is in temp2. |
+ |
+ // Functions have class 'Function'. |
+ __ cmp(temp2, Operand(JS_FUNCTION_TYPE)); |
+ if (class_name->IsEqualTo(CStrVector("Function"))) { |
+ __ b(eq, is_true); |
+ } else { |
+ __ b(eq, is_false); |
+ } |
+ |
+ // Check if the constructor in the map is a function. |
+ __ ldr(temp, FieldMemOperand(temp, Map::kConstructorOffset)); |
Søren Thygesen Gjesse
2011/01/10 09:56:08
After this
// temp: constructor
Alexandre
2011/01/10 10:48:27
Done.
|
+ |
+ // As long as JS_FUNCTION_TYPE is the last instance type and it is |
+ // right after LAST_JS_OBJECT_TYPE, we can avoid checking for |
+ // LAST_JS_OBJECT_TYPE. |
+ ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
+ ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); |
+ |
+ // Objects with a non-function constructor have class 'Object'. |
+ __ CompareObjectType(temp, temp2, temp2, JS_FUNCTION_TYPE); |
+ if (class_name->IsEqualTo(CStrVector("Object"))) { |
+ __ b(ne, is_true); |
+ } else { |
+ __ b(ne, is_false); |
+ } |
+ |
Søren Thygesen Gjesse
2011/01/10 09:56:08
Change comment to
// Get the instance class name
Alexandre
2011/01/10 10:48:27
Done.
|
+ // temp now contains the constructor function. Grab the |
+ // instance class name from there. |
+ __ ldr(temp, FieldMemOperand(temp, JSFunction::kSharedFunctionInfoOffset)); |
+ __ ldr(temp, FieldMemOperand(temp, |
+ SharedFunctionInfo::kInstanceClassNameOffset)); |
+ // The class name we are testing against is a symbol because it's a literal. |
+ // The name in the constructor is a symbol because of the way the context is |
+ // booted. This routine isn't expected to work for random API-created |
+ // classes and it doesn't have to because you can't access it with natives |
+ // syntax. Since both sides are symbols it is sufficient to use an identity |
+ // comparison. |
+ __ cmp(temp, Operand(class_name)); |
+ // End with the answer in the z flag. |
} |
@@ -1398,7 +1447,26 @@ |
void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { |
- Abort("DoClassOfTestAndBranch unimplemented."); |
+ Register input = ToRegister(instr->input()); |
+ Register temp = ToRegister(instr->temporary()); |
+ Register temp2 = ToRegister(instr->temporary2()); |
+ if (input.is(temp)) { |
+ // Swap. |
Søren Thygesen Gjesse
2011/01/10 09:56:08
There is a Swap instruction in the macro assembler
Alexandre
2011/01/10 10:48:27
Removed. Not needed anymore, as all these register
|
+ Register swapper = temp; |
+ temp = temp2; |
+ temp2 = swapper; |
+ } |
+ Handle<String> class_name = instr->hydrogen()->class_name(); |
+ |
+ int true_block = chunk_->LookupDestination(instr->true_block_id()); |
+ int false_block = chunk_->LookupDestination(instr->false_block_id()); |
+ |
+ Label* true_label = chunk_->GetAssemblyLabel(true_block); |
+ Label* false_label = chunk_->GetAssemblyLabel(false_block); |
+ |
+ EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2); |
+ |
+ EmitBranch(true_block, false_block, eq); |
} |
@@ -1784,12 +1852,42 @@ |
void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { |
- Abort("DoMathFloor unimplemented."); |
+ DoubleRegister input_reg = ToDoubleRegister(instr->input()); |
Søren Thygesen Gjesse
2011/01/10 09:56:08
input_reg -> input?
|
+ SwVfpRegister single_precision_scratch = s0; |
Søren Thygesen Gjesse
2011/01/10 09:56:08
Please add double_scratch0() and single_scratch0()
|
+ Register result = ToRegister(instr->result()); |
+ Register scratch = scratch0(); |
+ |
+ // Set custom FPCSR: |
+ // - Set rounding mode to "Round towards Minus Infinity" |
Søren Thygesen Gjesse
2011/01/10 09:56:08
No need to refer to specific bit numbers in the co
|
+ // (ie bits [23:22] = 0b10). |
+ // - Clear vfp cumulative exception flags (bits [3:0]). |
+ // - Make sure Flush-to-zero mode control bit is unset (bit 22). |
+ __ vmrs(scratch); |
Søren Thygesen Gjesse
2011/01/10 09:56:08
Don't we need to backup and restore FPSCR here? Th
|
+ __ bic(scratch, scratch, |
+ Operand(kVFPExceptionMask | kVFPRoundingModeMask | kVFPFlushToZeroMask)); |
+ __ orr(scratch, scratch, Operand(kVFPRoundToMinusInfinityBits)); |
+ __ vmsr(scratch); |
+ |
+ // Convert the argument to an integer. |
+ __ vcvt_s32_f64(single_precision_scratch, |
+ input_reg, |
+ Assembler::FPSCRRounding, |
+ al); |
+ |
+ // Retrieve FPSCR and check for vfp exceptions. |
+ __ vmrs(scratch); |
+ __ tst(scratch, Operand(kVFPExceptionMask)); |
+ DeoptimizeIf(ne, instr->environment()); |
+ |
+ // Move the result back to general purpose register r0. |
+ __ vmov(result, single_precision_scratch); |
} |
void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { |
- Abort("DoMathSqrt unimplemented."); |
+ DoubleRegister input_reg = ToDoubleRegister(instr->input()); |
Søren Thygesen Gjesse
2011/01/10 09:56:08
input_reg -> input?
Alexandre
2011/01/10 10:48:27
Done.
|
+ ASSERT(ToDoubleRegister(instr->result()).is(input_reg)); |
+ __ vsqrt(input_reg, input_reg); |
} |