| Index: src/arm/lithium-codegen-arm.cc
|
| ===================================================================
|
| --- src/arm/lithium-codegen-arm.cc (revision 6268)
|
| +++ src/arm/lithium-codegen-arm.cc (working copy)
|
| @@ -958,12 +958,26 @@
|
| Register result = ToRegister(instr->result());
|
| Register array = ToRegister(instr->input());
|
| __ ldr(result, FieldMemOperand(array, FixedArray::kLengthOffset));
|
| - Abort("DoFixedArrayLength untested.");
|
| }
|
|
|
|
|
| void LCodeGen::DoValueOf(LValueOf* instr) {
|
| - Abort("DoValueOf unimplemented.");
|
| + Register input = ToRegister(instr->input());
|
| + Register result = ToRegister(instr->result());
|
| + Register map = ToRegister(instr->temporary());
|
| + ASSERT(input.is(result));
|
| + Label done;
|
| +
|
| + // If the object is a smi return the object.
|
| + __ tst(input, Operand(kSmiTagMask));
|
| + __ b(eq, &done);
|
| +
|
| + // If the object is not a value type, return the object.
|
| + __ CompareObjectType(input, map, map, JS_VALUE_TYPE);
|
| + __ b(ne, &done);
|
| + __ ldr(result, FieldMemOperand(input, JSValue::kValueOffset));
|
| +
|
| + __ bind(&done);
|
| }
|
|
|
|
|
| @@ -971,7 +985,6 @@
|
| LOperand* input = instr->input();
|
| ASSERT(input->Equals(instr->result()));
|
| __ mvn(ToRegister(input), Operand(ToRegister(input)));
|
| - Abort("DoBitNotI untested.");
|
| }
|
|
|
|
|
| @@ -1408,7 +1421,7 @@
|
| }
|
|
|
|
|
| -// Branches to a label or falls through with the answer in the z flag. Trashes
|
| +// Branches to a label or falls through with the answer in flags. Trashes
|
| // the temp registers, but not the input. Only input and temp2 may alias.
|
| void LCodeGen::EmitClassOfTest(Label* is_true,
|
| Label* is_false,
|
| @@ -1416,17 +1429,91 @@
|
| 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.
|
| + __ tst(input, Operand(kSmiTagMask));
|
| + __ b(eq, is_false);
|
| + __ CompareObjectType(input, temp, temp2, FIRST_JS_OBJECT_TYPE);
|
| + __ b(lt, is_false);
|
| +
|
| + // Map is now in temp.
|
| + // Functions have class 'Function'.
|
| + __ CompareInstanceType(temp, temp2, 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));
|
| +
|
| + // 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);
|
| + }
|
| +
|
| + // 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 flags.
|
| }
|
|
|
|
|
| void LCodeGen::DoClassOfTest(LClassOfTest* instr) {
|
| - Abort("DoClassOfTest unimplemented.");
|
| + Register input = ToRegister(instr->input());
|
| + Register result = ToRegister(instr->result());
|
| + ASSERT(input.is(result));
|
| + Handle<String> class_name = instr->hydrogen()->class_name();
|
| +
|
| + Label done, is_true, is_false;
|
| +
|
| + EmitClassOfTest(&is_true, &is_false, class_name, input, scratch0(), input);
|
| + __ b(ne, &is_false);
|
| +
|
| + __ bind(&is_true);
|
| + __ LoadRoot(result, Heap::kTrueValueRootIndex);
|
| + __ jmp(&done);
|
| +
|
| + __ bind(&is_false);
|
| + __ LoadRoot(result, Heap::kFalseValueRootIndex);
|
| + __ bind(&done);
|
| }
|
|
|
|
|
| void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
|
| - Abort("DoClassOfTestAndBranch unimplemented.");
|
| + Register input = ToRegister(instr->input());
|
| + Register temp = scratch0();
|
| + Register temp2 = ToRegister(instr->temporary());
|
| + 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);
|
| }
|
|
|
|
|
|
|