Commit 59c158e4 authored by ager@chromium.org's avatar ager@chromium.org

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
parent a7c743d3
...@@ -997,7 +997,6 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) { ...@@ -997,7 +997,6 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
ASSERT(compare->value()->representation().IsTagged()); ASSERT(compare->value()->representation().IsTagged());
return new LClassOfTestAndBranch(UseTempRegister(compare->value()), return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
TempRegister(),
TempRegister(), TempRegister(),
first_id, first_id,
second_id); second_id);
...@@ -1485,8 +1484,7 @@ LInstruction* LChunkBuilder::DoHasCachedArrayIndex( ...@@ -1485,8 +1484,7 @@ LInstruction* LChunkBuilder::DoHasCachedArrayIndex(
LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) { LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseTempRegister(instr->value()); LOperand* value = UseTempRegister(instr->value());
return DefineSameAsFirst(new LClassOfTest(value));
return DefineSameAsFirst(new LClassOfTest(value, TempRegister()));
} }
......
...@@ -848,18 +848,12 @@ class LHasCachedArrayIndexAndBranch: public LHasCachedArrayIndex { ...@@ -848,18 +848,12 @@ class LHasCachedArrayIndexAndBranch: public LHasCachedArrayIndex {
class LClassOfTest: public LUnaryOperation { class LClassOfTest: public LUnaryOperation {
public: public:
LClassOfTest(LOperand* value, LOperand* temp) explicit LClassOfTest(LOperand* value) : LUnaryOperation(value) {}
: LUnaryOperation(value), temporary_(temp) {}
DECLARE_CONCRETE_INSTRUCTION(ClassOfTest, "class-of-test") DECLARE_CONCRETE_INSTRUCTION(ClassOfTest, "class-of-test")
DECLARE_HYDROGEN_ACCESSOR(ClassOfTest) DECLARE_HYDROGEN_ACCESSOR(ClassOfTest)
virtual void PrintDataTo(StringStream* stream) const; virtual void PrintDataTo(StringStream* stream) const;
LOperand* temporary() { return temporary_; }
private:
LOperand *temporary_;
}; };
...@@ -867,11 +861,10 @@ class LClassOfTestAndBranch: public LClassOfTest { ...@@ -867,11 +861,10 @@ class LClassOfTestAndBranch: public LClassOfTest {
public: public:
LClassOfTestAndBranch(LOperand* value, LClassOfTestAndBranch(LOperand* value,
LOperand* temporary, LOperand* temporary,
LOperand* temporary2,
int true_block_id, int true_block_id,
int false_block_id) int false_block_id)
: LClassOfTest(value, temporary), : LClassOfTest(value),
temporary2_(temporary2), temporary_(temporary),
true_block_id_(true_block_id), true_block_id_(true_block_id),
false_block_id_(false_block_id) { } false_block_id_(false_block_id) { }
...@@ -882,10 +875,10 @@ class LClassOfTestAndBranch: public LClassOfTest { ...@@ -882,10 +875,10 @@ class LClassOfTestAndBranch: public LClassOfTest {
int true_block_id() const { return true_block_id_; } int true_block_id() const { return true_block_id_; }
int false_block_id() const { return false_block_id_; } int false_block_id() const { return false_block_id_; }
LOperand* temporary2() { return temporary2_; } LOperand* temporary() { return temporary_; }
private: private:
LOperand* temporary2_; LOperand* temporary_;
int true_block_id_; int true_block_id_;
int false_block_id_; int false_block_id_;
}; };
......
...@@ -958,12 +958,26 @@ void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) { ...@@ -958,12 +958,26 @@ void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());
Register array = ToRegister(instr->input()); Register array = ToRegister(instr->input());
__ ldr(result, FieldMemOperand(array, FixedArray::kLengthOffset)); __ ldr(result, FieldMemOperand(array, FixedArray::kLengthOffset));
Abort("DoFixedArrayLength untested.");
} }
void LCodeGen::DoValueOf(LValueOf* instr) { 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) { ...@@ -971,7 +985,6 @@ void LCodeGen::DoBitNotI(LBitNotI* instr) {
LOperand* input = instr->input(); LOperand* input = instr->input();
ASSERT(input->Equals(instr->result())); ASSERT(input->Equals(instr->result()));
__ mvn(ToRegister(input), Operand(ToRegister(input))); __ mvn(ToRegister(input), Operand(ToRegister(input)));
Abort("DoBitNotI untested.");
} }
...@@ -1408,7 +1421,7 @@ void LCodeGen::DoHasCachedArrayIndexAndBranch( ...@@ -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. // the temp registers, but not the input. Only input and temp2 may alias.
void LCodeGen::EmitClassOfTest(Label* is_true, void LCodeGen::EmitClassOfTest(Label* is_true,
Label* is_false, Label* is_false,
...@@ -1416,17 +1429,91 @@ void LCodeGen::EmitClassOfTest(Label* is_true, ...@@ -1416,17 +1429,91 @@ void LCodeGen::EmitClassOfTest(Label* is_true,
Register input, Register input,
Register temp, Register temp,
Register temp2) { 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) { 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) { 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);
} }
......
...@@ -898,7 +898,7 @@ class LClassOfTest: public LUnaryOperation<1> { ...@@ -898,7 +898,7 @@ class LClassOfTest: public LUnaryOperation<1> {
LOperand* temporary() { return temporary_; } LOperand* temporary() { return temporary_; }
private: private:
LOperand *temporary_; LOperand* temporary_;
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment