ARM: Implement ClassOf in the lithium arm backend.

Review URL: http://codereview.chromium.org/6201004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6271 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
ager@chromium.org 2011-01-11 14:01:53 +00:00
parent a7c743d3ac
commit 59c158e43f
4 changed files with 101 additions and 23 deletions

View File

@ -997,7 +997,6 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
ASSERT(compare->value()->representation().IsTagged());
return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
TempRegister(),
TempRegister(),
first_id,
second_id);
@ -1485,8 +1484,7 @@ LInstruction* LChunkBuilder::DoHasCachedArrayIndex(
LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) {
ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseTempRegister(instr->value());
return DefineSameAsFirst(new LClassOfTest(value, TempRegister()));
return DefineSameAsFirst(new LClassOfTest(value));
}

View File

@ -848,18 +848,12 @@ class LHasCachedArrayIndexAndBranch: public LHasCachedArrayIndex {
class LClassOfTest: public LUnaryOperation {
public:
LClassOfTest(LOperand* value, LOperand* temp)
: LUnaryOperation(value), temporary_(temp) {}
explicit LClassOfTest(LOperand* value) : LUnaryOperation(value) {}
DECLARE_CONCRETE_INSTRUCTION(ClassOfTest, "class-of-test")
DECLARE_HYDROGEN_ACCESSOR(ClassOfTest)
virtual void PrintDataTo(StringStream* stream) const;
LOperand* temporary() { return temporary_; }
private:
LOperand *temporary_;
};
@ -867,11 +861,10 @@ class LClassOfTestAndBranch: public LClassOfTest {
public:
LClassOfTestAndBranch(LOperand* value,
LOperand* temporary,
LOperand* temporary2,
int true_block_id,
int false_block_id)
: LClassOfTest(value, temporary),
temporary2_(temporary2),
: LClassOfTest(value),
temporary_(temporary),
true_block_id_(true_block_id),
false_block_id_(false_block_id) { }
@ -882,10 +875,10 @@ class LClassOfTestAndBranch: public LClassOfTest {
int true_block_id() const { return true_block_id_; }
int false_block_id() const { return false_block_id_; }
LOperand* temporary2() { return temporary2_; }
LOperand* temporary() { return temporary_; }
private:
LOperand* temporary2_;
LOperand* temporary_;
int true_block_id_;
int false_block_id_;
};

View File

@ -958,12 +958,26 @@ void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
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 @@ void LCodeGen::DoBitNotI(LBitNotI* instr) {
LOperand* input = instr->input();
ASSERT(input->Equals(instr->result()));
__ mvn(ToRegister(input), Operand(ToRegister(input)));
Abort("DoBitNotI untested.");
}
@ -1408,7 +1421,7 @@ void LCodeGen::DoHasCachedArrayIndexAndBranch(
}
// 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 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
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);
}