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:
parent
eb7b4e347e
commit
2996dca6aa
@ -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 {
|
||||
stream->Add("if is_smi(");
|
||||
input()->PrintTo(stream);
|
||||
@ -1238,6 +1245,17 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
|
||||
temp,
|
||||
first_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()) {
|
||||
HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
|
||||
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) {
|
||||
ASSERT(instr->value()->representation().IsTagged());
|
||||
LOperand* value = UseAtStart(instr->value());
|
||||
|
@ -121,6 +121,8 @@ class Translation;
|
||||
// LInteger32ToDouble
|
||||
// LIsNull
|
||||
// LIsNullAndBranch
|
||||
// LIsObject
|
||||
// LIsObjectAndBranch
|
||||
// LIsSmi
|
||||
// LIsSmiAndBranch
|
||||
// LLoadNamedField
|
||||
@ -203,6 +205,8 @@ class Translation;
|
||||
V(Integer32ToDouble) \
|
||||
V(IsNull) \
|
||||
V(IsNullAndBranch) \
|
||||
V(IsObject) \
|
||||
V(IsObjectAndBranch) \
|
||||
V(IsSmi) \
|
||||
V(IsSmiAndBranch) \
|
||||
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 {
|
||||
public:
|
||||
explicit LIsSmi(LOperand* value) : LUnaryOperation(value) {}
|
||||
|
@ -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) {
|
||||
ASSERT(instr->hydrogen()->value()->representation().IsTagged());
|
||||
Register result = ToRegister(instr->result());
|
||||
|
@ -208,6 +208,15 @@ class LCodeGen BASE_EMBEDDED {
|
||||
Condition EmitTypeofIs(Label* true_label, Label* false_label,
|
||||
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_;
|
||||
MacroAssembler* const masm_;
|
||||
CompilationInfo* const info_;
|
||||
|
@ -140,6 +140,7 @@ class LChunkBuilder;
|
||||
// HHasCachedArrayIndex
|
||||
// HHasInstanceType
|
||||
// HIsNull
|
||||
// HIsObject
|
||||
// HIsSmi
|
||||
// HValueOf
|
||||
// HUnknownOSRValue
|
||||
@ -208,6 +209,7 @@ class LChunkBuilder;
|
||||
V(Goto) \
|
||||
V(InstanceOf) \
|
||||
V(IsNull) \
|
||||
V(IsObject) \
|
||||
V(IsSmi) \
|
||||
V(HasInstanceType) \
|
||||
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 {
|
||||
public:
|
||||
explicit HIsSmi(HValue* value) : HUnaryPredicate(value) { }
|
||||
|
@ -4950,14 +4950,18 @@ void HGraphBuilder::GenerateIsRegExp(int argument_count, int ast_id) {
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count,
|
||||
int ast_id) {
|
||||
BAILOUT("inlined runtime function: IsNonNegativeSmi");
|
||||
void HGraphBuilder::GenerateIsObject(int argument_count, int ast_id) {
|
||||
ASSERT(argument_count == 1);
|
||||
|
||||
HValue* value = Pop();
|
||||
HIsObject* test = new HIsObject(value);
|
||||
ast_context()->ReturnInstruction(test, ast_id);
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::GenerateIsObject(int argument_count, int ast_id) {
|
||||
BAILOUT("inlined runtime function: IsObject");
|
||||
void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count,
|
||||
int ast_id) {
|
||||
BAILOUT("inlined runtime function: IsNonNegativeSmi");
|
||||
}
|
||||
|
||||
|
||||
|
@ -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) {
|
||||
Operand input = ToOperand(instr->input());
|
||||
Register result = ToRegister(instr->result());
|
||||
|
@ -197,6 +197,15 @@ class LCodeGen BASE_EMBEDDED {
|
||||
Condition EmitTypeofIs(Label* true_label, Label* false_label,
|
||||
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_;
|
||||
MacroAssembler* const masm_;
|
||||
CompilationInfo* const info_;
|
||||
|
@ -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 {
|
||||
stream->Add("if is_smi(");
|
||||
input()->PrintTo(stream);
|
||||
@ -1251,6 +1258,17 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
|
||||
temp,
|
||||
first_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()) {
|
||||
HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
|
||||
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) {
|
||||
ASSERT(instr->value()->representation().IsTagged());
|
||||
LOperand* value = UseAtStart(instr->value());
|
||||
|
@ -124,6 +124,8 @@ class LGapNode;
|
||||
// LInteger32ToDouble
|
||||
// LIsNull
|
||||
// LIsNullAndBranch
|
||||
// LIsObject
|
||||
// LIsObjectAndBranch
|
||||
// LIsSmi
|
||||
// LIsSmiAndBranch
|
||||
// LLoadNamedField
|
||||
@ -206,6 +208,8 @@ class LGapNode;
|
||||
V(Integer32ToDouble) \
|
||||
V(IsNull) \
|
||||
V(IsNullAndBranch) \
|
||||
V(IsObject) \
|
||||
V(IsObjectAndBranch) \
|
||||
V(IsSmi) \
|
||||
V(IsSmiAndBranch) \
|
||||
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 {
|
||||
public:
|
||||
explicit LIsSmi(LOperand* value) : LUnaryOperation(value) {}
|
||||
|
Loading…
Reference in New Issue
Block a user