Support %_IsObject in Crankshaft.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6027 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
erik.corry@gmail.com 2010-12-15 12:32:19 +00:00
parent eb7b4e347e
commit 2996dca6aa
10 changed files with 266 additions and 5 deletions

View File

@ -206,6 +206,13 @@ void LIsNullAndBranch::PrintDataTo(StringStream* stream) const {
} }
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) const {
stream->Add("if is_object(");
input()->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LIsSmiAndBranch::PrintDataTo(StringStream* stream) const { void LIsSmiAndBranch::PrintDataTo(StringStream* stream) const {
stream->Add("if is_smi("); stream->Add("if is_smi(");
input()->PrintTo(stream); input()->PrintTo(stream);
@ -1238,6 +1245,17 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
temp, temp,
first_id, first_id,
second_id); second_id);
} else if (v->IsIsObject()) {
HIsObject* compare = HIsObject::cast(v);
ASSERT(compare->value()->representation().IsTagged());
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()),
temp1,
temp2,
first_id,
second_id);
} else if (v->IsCompareJSObjectEq()) { } else if (v->IsCompareJSObjectEq()) {
HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v); HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()), return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
@ -1600,6 +1618,14 @@ LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) {
} }
LInstruction* LChunkBuilder::DoIsObject(HIsObject* instr) {
ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LIsObject(value, TempRegister()));
}
LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) { LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseAtStart(instr->value()); LOperand* value = UseAtStart(instr->value());

View File

@ -121,6 +121,8 @@ class Translation;
// LInteger32ToDouble // LInteger32ToDouble
// LIsNull // LIsNull
// LIsNullAndBranch // LIsNullAndBranch
// LIsObject
// LIsObjectAndBranch
// LIsSmi // LIsSmi
// LIsSmiAndBranch // LIsSmiAndBranch
// LLoadNamedField // LLoadNamedField
@ -203,6 +205,8 @@ class Translation;
V(Integer32ToDouble) \ V(Integer32ToDouble) \
V(IsNull) \ V(IsNull) \
V(IsNullAndBranch) \ V(IsNullAndBranch) \
V(IsObject) \
V(IsObjectAndBranch) \
V(IsSmi) \ V(IsSmi) \
V(IsSmiAndBranch) \ V(IsSmiAndBranch) \
V(HasInstanceType) \ V(HasInstanceType) \
@ -742,6 +746,48 @@ class LIsNullAndBranch: public LIsNull {
}; };
class LIsObject: public LUnaryOperation {
public:
LIsObject(LOperand* value, LOperand* temp)
: LUnaryOperation(value), temp_(temp) {}
DECLARE_CONCRETE_INSTRUCTION(IsObject, "is-object")
LOperand* temp() const { return temp_; }
private:
LOperand* temp_;
};
class LIsObjectAndBranch: public LIsObject {
public:
LIsObjectAndBranch(LOperand* value,
LOperand* temp,
LOperand* temp2,
int true_block_id,
int false_block_id)
: LIsObject(value, temp),
temp2_(temp2),
true_block_id_(true_block_id),
false_block_id_(false_block_id) { }
DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
virtual void PrintDataTo(StringStream* stream) const;
virtual bool IsControl() const { return true; }
int true_block_id() const { return true_block_id_; }
int false_block_id() const { return false_block_id_; }
LOperand* temp2() const { return temp2_; }
private:
LOperand* temp2_;
int true_block_id_;
int false_block_id_;
};
class LIsSmi: public LUnaryOperation { class LIsSmi: public LUnaryOperation {
public: public:
explicit LIsSmi(LOperand* value) : LUnaryOperation(value) {} explicit LIsSmi(LOperand* value) : LUnaryOperation(value) {}

View File

@ -1213,6 +1213,26 @@ void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) {
} }
Condition LCodeGen::EmitIsObject(Register input,
Register temp1,
Register temp2,
Label* is_not_object,
Label* is_object) {
Abort("EmitIsObject unimplemented.");
return ne;
}
void LCodeGen::DoIsObject(LIsObject* instr) {
Abort("DoIsObject unimplemented.");
}
void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
Abort("DoIsObjectAndBranch unimplemented.");
}
void LCodeGen::DoIsSmi(LIsSmi* instr) { void LCodeGen::DoIsSmi(LIsSmi* instr) {
ASSERT(instr->hydrogen()->value()->representation().IsTagged()); ASSERT(instr->hydrogen()->value()->representation().IsTagged());
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());

View File

@ -208,6 +208,15 @@ class LCodeGen BASE_EMBEDDED {
Condition EmitTypeofIs(Label* true_label, Label* false_label, Condition EmitTypeofIs(Label* true_label, Label* false_label,
Register input, Handle<String> type_name); Register input, Handle<String> type_name);
// Emits optimized code for %_IsObject(x). Preserves input register.
// Returns the condition on which a final split to
// true and false label should be made, to optimize fallthrough.
Condition EmitIsObject(Register input,
Register temp1,
Register temp2,
Label* is_not_object,
Label* is_object);
LChunk* const chunk_; LChunk* const chunk_;
MacroAssembler* const masm_; MacroAssembler* const masm_;
CompilationInfo* const info_; CompilationInfo* const info_;

View File

@ -140,6 +140,7 @@ class LChunkBuilder;
// HHasCachedArrayIndex // HHasCachedArrayIndex
// HHasInstanceType // HHasInstanceType
// HIsNull // HIsNull
// HIsObject
// HIsSmi // HIsSmi
// HValueOf // HValueOf
// HUnknownOSRValue // HUnknownOSRValue
@ -208,6 +209,7 @@ class LChunkBuilder;
V(Goto) \ V(Goto) \
V(InstanceOf) \ V(InstanceOf) \
V(IsNull) \ V(IsNull) \
V(IsObject) \
V(IsSmi) \ V(IsSmi) \
V(HasInstanceType) \ V(HasInstanceType) \
V(HasCachedArrayIndex) \ V(HasCachedArrayIndex) \
@ -2100,6 +2102,14 @@ class HIsNull: public HUnaryPredicate {
}; };
class HIsObject: public HUnaryPredicate {
public:
explicit HIsObject(HValue* value) : HUnaryPredicate(value) { }
DECLARE_CONCRETE_INSTRUCTION(IsObject, "is_object")
};
class HIsSmi: public HUnaryPredicate { class HIsSmi: public HUnaryPredicate {
public: public:
explicit HIsSmi(HValue* value) : HUnaryPredicate(value) { } explicit HIsSmi(HValue* value) : HUnaryPredicate(value) { }

View File

@ -4950,14 +4950,18 @@ void HGraphBuilder::GenerateIsRegExp(int argument_count, int ast_id) {
} }
void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count, void HGraphBuilder::GenerateIsObject(int argument_count, int ast_id) {
int ast_id) { ASSERT(argument_count == 1);
BAILOUT("inlined runtime function: IsNonNegativeSmi");
HValue* value = Pop();
HIsObject* test = new HIsObject(value);
ast_context()->ReturnInstruction(test, ast_id);
} }
void HGraphBuilder::GenerateIsObject(int argument_count, int ast_id) { void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count,
BAILOUT("inlined runtime function: IsObject"); int ast_id) {
BAILOUT("inlined runtime function: IsNonNegativeSmi");
} }

View File

@ -1403,6 +1403,71 @@ void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) {
} }
Condition LCodeGen::EmitIsObject(Register input,
Register temp1,
Register temp2,
Label* is_not_object,
Label* is_object) {
ASSERT(!input.is(temp1));
ASSERT(!input.is(temp2));
ASSERT(!temp1.is(temp2));
__ test(input, Immediate(kSmiTagMask));
__ j(equal, is_not_object);
__ cmp(input, Factory::null_value());
__ j(equal, is_object);
__ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
// Undetectable objects behave like undefined.
__ movzx_b(temp2, FieldOperand(temp1, Map::kBitFieldOffset));
__ test(temp2, Immediate(1 << Map::kIsUndetectable));
__ j(not_zero, is_not_object);
__ movzx_b(temp2, FieldOperand(temp1, Map::kInstanceTypeOffset));
__ cmp(temp2, FIRST_JS_OBJECT_TYPE);
__ j(below, is_not_object);
__ cmp(temp2, LAST_JS_OBJECT_TYPE);
return below_equal;
}
void LCodeGen::DoIsObject(LIsObject* instr) {
Register reg = ToRegister(instr->input());
Register result = ToRegister(instr->result());
Register temp = ToRegister(instr->temp());
Label is_false, is_true, done;
Condition true_cond = EmitIsObject(reg, result, temp, &is_false, &is_true);
__ j(true_cond, &is_true);
__ bind(&is_false);
__ mov(result, Handle<Object>(Heap::false_value()));
__ jmp(&done);
__ bind(&is_true);
__ mov(result, Handle<Object>(Heap::true_value()));
__ bind(&done);
}
void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
Register reg = ToRegister(instr->input());
Register temp = ToRegister(instr->temp());
Register temp2 = ToRegister(instr->temp2());
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);
Condition true_cond = EmitIsObject(reg, temp, temp2, false_label, true_label);
EmitBranch(true_block, false_block, true_cond);
}
void LCodeGen::DoIsSmi(LIsSmi* instr) { void LCodeGen::DoIsSmi(LIsSmi* instr) {
Operand input = ToOperand(instr->input()); Operand input = ToOperand(instr->input());
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());

View File

@ -197,6 +197,15 @@ class LCodeGen BASE_EMBEDDED {
Condition EmitTypeofIs(Label* true_label, Label* false_label, Condition EmitTypeofIs(Label* true_label, Label* false_label,
Register input, Handle<String> type_name); Register input, Handle<String> type_name);
// Emits optimized code for %_IsObject(x). Preserves input register.
// Returns the condition on which a final split to
// true and false label should be made, to optimize fallthrough.
Condition EmitIsObject(Register input,
Register temp1,
Register temp2,
Label* is_not_object,
Label* is_object);
LChunk* const chunk_; LChunk* const chunk_;
MacroAssembler* const masm_; MacroAssembler* const masm_;
CompilationInfo* const info_; CompilationInfo* const info_;

View File

@ -206,6 +206,13 @@ void LIsNullAndBranch::PrintDataTo(StringStream* stream) const {
} }
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) const {
stream->Add("if is_object(");
input()->PrintTo(stream);
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}
void LIsSmiAndBranch::PrintDataTo(StringStream* stream) const { void LIsSmiAndBranch::PrintDataTo(StringStream* stream) const {
stream->Add("if is_smi("); stream->Add("if is_smi(");
input()->PrintTo(stream); input()->PrintTo(stream);
@ -1251,6 +1258,17 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
temp, temp,
first_id, first_id,
second_id); second_id);
} else if (v->IsIsObject()) {
HIsObject* compare = HIsObject::cast(v);
ASSERT(compare->value()->representation().IsTagged());
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()),
temp1,
temp2,
first_id,
second_id);
} else if (v->IsCompareJSObjectEq()) { } else if (v->IsCompareJSObjectEq()) {
HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v); HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()), return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
@ -1630,6 +1648,14 @@ LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) {
} }
LInstruction* LChunkBuilder::DoIsObject(HIsObject* instr) {
ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseRegisterAtStart(instr->value());
return DefineAsRegister(new LIsObject(value, TempRegister()));
}
LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) { LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) {
ASSERT(instr->value()->representation().IsTagged()); ASSERT(instr->value()->representation().IsTagged());
LOperand* value = UseAtStart(instr->value()); LOperand* value = UseAtStart(instr->value());

View File

@ -124,6 +124,8 @@ class LGapNode;
// LInteger32ToDouble // LInteger32ToDouble
// LIsNull // LIsNull
// LIsNullAndBranch // LIsNullAndBranch
// LIsObject
// LIsObjectAndBranch
// LIsSmi // LIsSmi
// LIsSmiAndBranch // LIsSmiAndBranch
// LLoadNamedField // LLoadNamedField
@ -206,6 +208,8 @@ class LGapNode;
V(Integer32ToDouble) \ V(Integer32ToDouble) \
V(IsNull) \ V(IsNull) \
V(IsNullAndBranch) \ V(IsNullAndBranch) \
V(IsObject) \
V(IsObjectAndBranch) \
V(IsSmi) \ V(IsSmi) \
V(IsSmiAndBranch) \ V(IsSmiAndBranch) \
V(HasInstanceType) \ V(HasInstanceType) \
@ -747,6 +751,48 @@ class LIsNullAndBranch: public LIsNull {
}; };
class LIsObject: public LUnaryOperation {
public:
LIsObject(LOperand* value, LOperand* temp)
: LUnaryOperation(value), temp_(temp) {}
DECLARE_CONCRETE_INSTRUCTION(IsObject, "is-object")
LOperand* temp() const { return temp_; }
private:
LOperand* temp_;
};
class LIsObjectAndBranch: public LIsObject {
public:
LIsObjectAndBranch(LOperand* value,
LOperand* temp,
LOperand* temp2,
int true_block_id,
int false_block_id)
: LIsObject(value, temp),
temp2_(temp2),
true_block_id_(true_block_id),
false_block_id_(false_block_id) { }
DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
virtual void PrintDataTo(StringStream* stream) const;
virtual bool IsControl() const { return true; }
int true_block_id() const { return true_block_id_; }
int false_block_id() const { return false_block_id_; }
LOperand* temp2() const { return temp2_; }
private:
LOperand* temp2_;
int true_block_id_;
int false_block_id_;
};
class LIsSmi: public LUnaryOperation { class LIsSmi: public LUnaryOperation {
public: public:
explicit LIsSmi(LOperand* value) : LUnaryOperation(value) {} explicit LIsSmi(LOperand* value) : LUnaryOperation(value) {}