Avoid Unnecessary Smi Checks

BUG=
R=ulan@chromium.org

Review URL: https://codereview.chromium.org/16026023

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15344 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
olivf@chromium.org 2013-06-26 17:37:55 +00:00
parent df181f2c11
commit 21cd74eaa2
16 changed files with 149 additions and 93 deletions

View File

@ -2000,7 +2000,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
} }
LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) { LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
LOperand* value = UseRegisterAtStart(instr->value()); LOperand* value = UseRegisterAtStart(instr->value());
return AssignEnvironment(new(zone()) LCheckNonSmi(value)); return AssignEnvironment(new(zone()) LCheckNonSmi(value));
} }

View File

@ -2421,6 +2421,7 @@ class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> {
LOperand* value() { return inputs_[0]; } LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi") DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi")
DECLARE_HYDROGEN_ACCESSOR(CheckHeapObject)
}; };

View File

@ -1880,10 +1880,12 @@ void LCodeGen::DoValueOf(LValueOf* instr) {
Register map = ToRegister(instr->temp()); Register map = ToRegister(instr->temp());
Label done; Label done;
// If the object is a smi return the object. if (!instr->hydrogen()->value()->IsHeapObject()) {
__ SmiTst(input); // If the object is a smi return the object.
__ Move(result, input, eq); __ SmiTst(input);
__ b(eq, &done); __ Move(result, input, eq);
__ b(eq, &done);
}
// If the object is not a value type, return the object. // If the object is not a value type, return the object.
__ CompareObjectType(input, map, map, JS_VALUE_TYPE); __ CompareObjectType(input, map, map, JS_VALUE_TYPE);
@ -2438,8 +2440,11 @@ void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
Condition LCodeGen::EmitIsString(Register input, Condition LCodeGen::EmitIsString(Register input,
Register temp1, Register temp1,
Label* is_not_string) { Label* is_not_string,
__ JumpIfSmi(input, is_not_string); SmiCheck check_needed = INLINE_SMI_CHECK) {
if (check_needed == INLINE_SMI_CHECK) {
__ JumpIfSmi(input, is_not_string);
}
__ CompareObjectType(input, temp1, temp1, FIRST_NONSTRING_TYPE); __ CompareObjectType(input, temp1, temp1, FIRST_NONSTRING_TYPE);
return lt; return lt;
@ -2450,8 +2455,11 @@ void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
Register reg = ToRegister(instr->value()); Register reg = ToRegister(instr->value());
Register temp1 = ToRegister(instr->temp()); Register temp1 = ToRegister(instr->temp());
SmiCheck check_needed =
instr->hydrogen()->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
Condition true_cond = Condition true_cond =
EmitIsString(reg, temp1, instr->FalseLabel(chunk_)); EmitIsString(reg, temp1, instr->FalseLabel(chunk_), check_needed);
EmitBranch(instr, true_cond); EmitBranch(instr, true_cond);
} }
@ -2468,7 +2476,9 @@ void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
Register input = ToRegister(instr->value()); Register input = ToRegister(instr->value());
Register temp = ToRegister(instr->temp()); Register temp = ToRegister(instr->temp());
__ JumpIfSmi(input, instr->FalseLabel(chunk_)); if (!instr->hydrogen()->value()->IsHeapObject()) {
__ JumpIfSmi(input, instr->FalseLabel(chunk_));
}
__ ldr(temp, FieldMemOperand(input, HeapObject::kMapOffset)); __ ldr(temp, FieldMemOperand(input, HeapObject::kMapOffset));
__ ldrb(temp, FieldMemOperand(temp, Map::kBitFieldOffset)); __ ldrb(temp, FieldMemOperand(temp, Map::kBitFieldOffset));
__ tst(temp, Operand(1 << Map::kIsUndetectable)); __ tst(temp, Operand(1 << Map::kIsUndetectable));
@ -2534,7 +2544,9 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
Register scratch = scratch0(); Register scratch = scratch0();
Register input = ToRegister(instr->value()); Register input = ToRegister(instr->value());
__ JumpIfSmi(input, instr->FalseLabel(chunk_)); if (!instr->hydrogen()->value()->IsHeapObject()) {
__ JumpIfSmi(input, instr->FalseLabel(chunk_));
}
__ CompareObjectType(input, scratch, scratch, TestType(instr->hydrogen())); __ CompareObjectType(input, scratch, scratch, TestType(instr->hydrogen()));
EmitBranch(instr, BranchCondition(instr->hydrogen())); EmitBranch(instr, BranchCondition(instr->hydrogen()));
@ -2969,9 +2981,9 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
__ str(value, target); __ str(value, target);
if (instr->hydrogen()->NeedsWriteBarrier()) { if (instr->hydrogen()->NeedsWriteBarrier()) {
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed = SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; instr->hydrogen()->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
__ RecordWriteContextSlot(context, __ RecordWriteContextSlot(context,
target.offset(), target.offset(),
value, value,
@ -4209,9 +4221,9 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
// Do the store. // Do the store.
Register value = ToRegister(instr->value()); Register value = ToRegister(instr->value());
ASSERT(!object.is(value)); ASSERT(!object.is(value));
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed = SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; instr->hydrogen()->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
if (access.IsInobject()) { if (access.IsInobject()) {
__ str(value, FieldMemOperand(object, offset)); __ str(value, FieldMemOperand(object, offset));
if (instr->hydrogen()->NeedsWriteBarrier()) { if (instr->hydrogen()->NeedsWriteBarrier()) {
@ -4420,9 +4432,9 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
__ str(value, FieldMemOperand(store_base, offset)); __ str(value, FieldMemOperand(store_base, offset));
if (instr->hydrogen()->NeedsWriteBarrier()) { if (instr->hydrogen()->NeedsWriteBarrier()) {
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed = SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; instr->hydrogen()->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
// Compute address of modified element and store it into key register. // Compute address of modified element and store it into key register.
__ add(key, store_base, Operand(offset - kHeapObjectTag)); __ add(key, store_base, Operand(offset - kHeapObjectTag));
__ RecordWrite(elements, __ RecordWrite(elements,
@ -5144,9 +5156,11 @@ void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
LOperand* input = instr->value(); if (!instr->hydrogen()->value()->IsHeapObject()) {
__ SmiTst(ToRegister(input)); LOperand* input = instr->value();
DeoptimizeIf(eq, instr->environment()); __ SmiTst(ToRegister(input));
DeoptimizeIf(eq, instr->environment());
}
} }

View File

@ -349,7 +349,8 @@ class LCodeGen BASE_EMBEDDED {
// true and false label should be made, to optimize fallthrough. // true and false label should be made, to optimize fallthrough.
Condition EmitIsString(Register input, Condition EmitIsString(Register input,
Register temp1, Register temp1,
Label* is_not_string); Label* is_not_string,
SmiCheck check_needed);
// Emits optimized code for %_IsConstructCall(). // Emits optimized code for %_IsConstructCall().
// Caller should branch on equal condition. // Caller should branch on equal condition.

View File

@ -3065,9 +3065,8 @@ HType HCheckFunction::CalculateInferredType() {
} }
HType HCheckNonSmi::CalculateInferredType() { HType HCheckHeapObject::CalculateInferredType() {
// TODO(kasperl): Is there any way to signal that this isn't a smi? return HType::NonPrimitive();
return HType::Tagged();
} }
@ -3736,7 +3735,7 @@ void HSimulate::Verify() {
} }
void HCheckNonSmi::Verify() { void HCheckHeapObject::Verify() {
HInstruction::Verify(); HInstruction::Verify();
ASSERT(HasNoUses()); ASSERT(HasNoUses());
} }

View File

@ -89,9 +89,9 @@ class LChunkBuilder;
V(CallStub) \ V(CallStub) \
V(Change) \ V(Change) \
V(CheckFunction) \ V(CheckFunction) \
V(CheckHeapObject) \
V(CheckInstanceType) \ V(CheckInstanceType) \
V(CheckMaps) \ V(CheckMaps) \
V(CheckNonSmi) \
V(CheckPrototypeMaps) \ V(CheckPrototypeMaps) \
V(ClampToUint8) \ V(ClampToUint8) \
V(ClassOfTestAndBranch) \ V(ClassOfTestAndBranch) \
@ -434,7 +434,7 @@ class HType {
bool IsHeapObject() const { bool IsHeapObject() const {
ASSERT(type_ != kUninitialized); ASSERT(type_ != kUninitialized);
return IsHeapNumber() || IsString() || IsNonPrimitive(); return IsHeapNumber() || IsString() || IsBoolean() || IsNonPrimitive();
} }
static HType TypeFromValue(Handle<Object> value); static HType TypeFromValue(Handle<Object> value);
@ -918,6 +918,10 @@ class HValue: public ZoneObject {
type_ = new_type; type_ = new_type;
} }
bool IsHeapObject() {
return representation_.IsHeapObject() || type_.IsHeapObject();
}
// An operation needs to override this function iff: // An operation needs to override this function iff:
// 1) it can produce an int32 output. // 1) it can produce an int32 output.
// 2) the true value of its output can potentially be minus zero. // 2) the true value of its output can potentially be minus zero.
@ -2948,9 +2952,9 @@ class HCheckInstanceType: public HUnaryOperation {
}; };
class HCheckNonSmi: public HUnaryOperation { class HCheckHeapObject: public HUnaryOperation {
public: public:
explicit HCheckNonSmi(HValue* value) : HUnaryOperation(value) { explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) {
set_representation(Representation::Tagged()); set_representation(Representation::Tagged());
SetFlag(kUseGVN); SetFlag(kUseGVN);
} }
@ -2967,17 +2971,13 @@ class HCheckNonSmi: public HUnaryOperation {
virtual HValue* Canonicalize() { virtual HValue* Canonicalize() {
HType value_type = value()->type(); HType value_type = value()->type();
if (!value_type.IsUninitialized() && if (!value_type.IsUninitialized() && value_type.IsHeapObject()) {
(value_type.IsHeapNumber() ||
value_type.IsString() ||
value_type.IsBoolean() ||
value_type.IsNonPrimitive())) {
return NULL; return NULL;
} }
return this; return this;
} }
DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi) DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject)
protected: protected:
virtual bool DataEquals(HValue* other) { return true; } virtual bool DataEquals(HValue* other) { return true; }

View File

@ -1024,9 +1024,9 @@ HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() {
} }
HValue* HGraphBuilder::BuildCheckNonSmi(HValue* obj) { HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) {
if (obj->type().IsHeapObject()) return obj; if (obj->type().IsHeapObject()) return obj;
HCheckNonSmi* check = new(zone()) HCheckNonSmi(obj); HCheckHeapObject* check = new(zone()) HCheckHeapObject(obj);
AddInstruction(check); AddInstruction(check);
return check; return check;
} }
@ -1703,7 +1703,7 @@ void HGraphBuilder::BuildCompareNil(
if_nil.Then(); if_nil.Then();
if_nil.Else(); if_nil.Else();
if (type->NumClasses() == 1) { if (type->NumClasses() == 1) {
BuildCheckNonSmi(value); BuildCheckHeapObject(value);
// For ICs, the map checked below is a sentinel map that gets replaced by // For ICs, the map checked below is a sentinel map that gets replaced by
// the monomorphic map when the code is used as a template to generate a // the monomorphic map when the code is used as a template to generate a
// new IC. For optimized functions, there is no sentinel map, the map // new IC. For optimized functions, there is no sentinel map, the map
@ -6158,14 +6158,14 @@ static Representation ComputeLoadStoreRepresentation(Handle<Map> type,
void HOptimizedGraphBuilder::AddCheckMap(HValue* object, Handle<Map> map) { void HOptimizedGraphBuilder::AddCheckMap(HValue* object, Handle<Map> map) {
BuildCheckNonSmi(object); BuildCheckHeapObject(object);
AddInstruction(HCheckMaps::New(object, map, zone())); AddInstruction(HCheckMaps::New(object, map, zone()));
} }
void HOptimizedGraphBuilder::AddCheckMapsWithTransitions(HValue* object, void HOptimizedGraphBuilder::AddCheckMapsWithTransitions(HValue* object,
Handle<Map> map) { Handle<Map> map) {
BuildCheckNonSmi(object); BuildCheckHeapObject(object);
AddInstruction(HCheckMaps::NewWithTransitions(object, map, zone())); AddInstruction(HCheckMaps::NewWithTransitions(object, map, zone()));
} }
@ -6334,7 +6334,7 @@ HInstruction* HOptimizedGraphBuilder::TryLoadPolymorphicAsMonomorphic(
if (count != types->length()) return NULL; if (count != types->length()) return NULL;
// Everything matched; can use monomorphic load. // Everything matched; can use monomorphic load.
BuildCheckNonSmi(object); BuildCheckHeapObject(object);
AddInstruction(HCheckMaps::New(object, types, zone())); AddInstruction(HCheckMaps::New(object, types, zone()));
return BuildLoadNamedField(object, access, representation); return BuildLoadNamedField(object, access, representation);
} }
@ -6349,7 +6349,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
expr, object, types, name); expr, object, types, name);
if (instr == NULL) { if (instr == NULL) {
// Something did not match; must use a polymorphic load. // Something did not match; must use a polymorphic load.
BuildCheckNonSmi(object); BuildCheckHeapObject(object);
HValue* context = environment()->LookupContext(); HValue* context = environment()->LookupContext();
instr = new(zone()) HLoadNamedFieldPolymorphic( instr = new(zone()) HLoadNamedFieldPolymorphic(
context, object, types, name, zone()); context, object, types, name, zone());
@ -6405,7 +6405,7 @@ bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic(
if (count != types->length()) return false; if (count != types->length()) return false;
// Everything matched; can use monomorphic store. // Everything matched; can use monomorphic store.
BuildCheckNonSmi(object); BuildCheckHeapObject(object);
AddInstruction(HCheckMaps::New(object, types, zone())); AddInstruction(HCheckMaps::New(object, types, zone()));
HInstruction* store; HInstruction* store;
CHECK_ALIVE_OR_RETURN( CHECK_ALIVE_OR_RETURN(
@ -6444,7 +6444,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField(
LookupResult lookup(isolate()); LookupResult lookup(isolate());
if (ComputeLoadStoreField(map, name, &lookup, true)) { if (ComputeLoadStoreField(map, name, &lookup, true)) {
if (count == 0) { if (count == 0) {
BuildCheckNonSmi(object); BuildCheckHeapObject(object);
join = graph()->CreateBasicBlock(); join = graph()->CreateBasicBlock();
} }
++count; ++count;
@ -7178,7 +7178,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
KeyedAccessStoreMode store_mode, KeyedAccessStoreMode store_mode,
bool* has_side_effects) { bool* has_side_effects) {
*has_side_effects = false; *has_side_effects = false;
BuildCheckNonSmi(object); BuildCheckHeapObject(object);
SmallMapList* maps = prop->GetReceiverTypes(); SmallMapList* maps = prop->GetReceiverTypes();
bool todo_external_array = false; bool todo_external_array = false;
@ -7403,7 +7403,7 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
: BuildLoadKeyedGeneric(obj, key); : BuildLoadKeyedGeneric(obj, key);
AddInstruction(instr); AddInstruction(instr);
} else { } else {
BuildCheckNonSmi(obj); BuildCheckHeapObject(obj);
instr = BuildMonomorphicElementAccess( instr = BuildMonomorphicElementAccess(
obj, key, val, NULL, map, is_store, expr->GetStoreMode()); obj, key, val, NULL, map, is_store, expr->GetStoreMode());
} }
@ -7535,7 +7535,7 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
HInstruction* instr = NULL; HInstruction* instr = NULL;
if (expr->IsStringLength()) { if (expr->IsStringLength()) {
HValue* string = Pop(); HValue* string = Pop();
BuildCheckNonSmi(string); BuildCheckHeapObject(string);
AddInstruction(HCheckInstanceType::NewIsString(string, zone())); AddInstruction(HCheckInstanceType::NewIsString(string, zone()));
instr = HStringLength::New(zone(), string); instr = HStringLength::New(zone(), string);
} else if (expr->IsStringAccess()) { } else if (expr->IsStringAccess()) {
@ -7550,7 +7550,7 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
} else if (expr->IsFunctionPrototype()) { } else if (expr->IsFunctionPrototype()) {
HValue* function = Pop(); HValue* function = Pop();
BuildCheckNonSmi(function); BuildCheckHeapObject(function);
instr = new(zone()) HLoadFunctionPrototype(function); instr = new(zone()) HLoadFunctionPrototype(function);
} else if (expr->key()->IsPropertyName()) { } else if (expr->key()->IsPropertyName()) {
@ -7724,7 +7724,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
empty_smi_block->Goto(number_block); empty_smi_block->Goto(number_block);
set_current_block(not_smi_block); set_current_block(not_smi_block);
} else { } else {
BuildCheckNonSmi(receiver); BuildCheckHeapObject(receiver);
} }
} }
HBasicBlock* if_true = graph()->CreateBasicBlock(); HBasicBlock* if_true = graph()->CreateBasicBlock();
@ -9335,7 +9335,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStringCharCodeAt(
return new(zone()) HConstant(s->Get(i)); return new(zone()) HConstant(s->Get(i));
} }
} }
BuildCheckNonSmi(string); BuildCheckHeapObject(string);
AddInstruction(HCheckInstanceType::NewIsString(string, zone())); AddInstruction(HCheckInstanceType::NewIsString(string, zone()));
HInstruction* length = HStringLength::New(zone(), string); HInstruction* length = HStringLength::New(zone(), string);
AddInstruction(length); AddInstruction(length);
@ -9426,9 +9426,9 @@ HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation(
switch (expr->op()) { switch (expr->op()) {
case Token::ADD: case Token::ADD:
if (left_type->Is(Type::String()) && right_type->Is(Type::String())) { if (left_type->Is(Type::String()) && right_type->Is(Type::String())) {
BuildCheckNonSmi(left); BuildCheckHeapObject(left);
AddInstruction(HCheckInstanceType::NewIsString(left, zone())); AddInstruction(HCheckInstanceType::NewIsString(left, zone()));
BuildCheckNonSmi(right); BuildCheckHeapObject(right);
AddInstruction(HCheckInstanceType::NewIsString(right, zone())); AddInstruction(HCheckInstanceType::NewIsString(right, zone()));
instr = HStringAdd::New(zone(), context, left, right); instr = HStringAdd::New(zone(), context, left, right);
} else { } else {
@ -9845,9 +9845,9 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
result->set_position(expr->position()); result->set_position(expr->position());
return ast_context()->ReturnControl(result, expr->id()); return ast_context()->ReturnControl(result, expr->id());
} else { } else {
BuildCheckNonSmi(left); BuildCheckHeapObject(left);
AddInstruction(HCheckInstanceType::NewIsSpecObject(left, zone())); AddInstruction(HCheckInstanceType::NewIsSpecObject(left, zone()));
BuildCheckNonSmi(right); BuildCheckHeapObject(right);
AddInstruction(HCheckInstanceType::NewIsSpecObject(right, zone())); AddInstruction(HCheckInstanceType::NewIsSpecObject(right, zone()));
HCompareObjectEqAndBranch* result = HCompareObjectEqAndBranch* result =
new(zone()) HCompareObjectEqAndBranch(left, right); new(zone()) HCompareObjectEqAndBranch(left, right);
@ -9860,9 +9860,9 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
} }
} else if (combined_type->Is(Type::InternalizedString()) && } else if (combined_type->Is(Type::InternalizedString()) &&
Token::IsEqualityOp(op)) { Token::IsEqualityOp(op)) {
BuildCheckNonSmi(left); BuildCheckHeapObject(left);
AddInstruction(HCheckInstanceType::NewIsInternalizedString(left, zone())); AddInstruction(HCheckInstanceType::NewIsInternalizedString(left, zone()));
BuildCheckNonSmi(right); BuildCheckHeapObject(right);
AddInstruction(HCheckInstanceType::NewIsInternalizedString(right, zone())); AddInstruction(HCheckInstanceType::NewIsInternalizedString(right, zone()));
HCompareObjectEqAndBranch* result = HCompareObjectEqAndBranch* result =
new(zone()) HCompareObjectEqAndBranch(left, right); new(zone()) HCompareObjectEqAndBranch(left, right);

View File

@ -1012,7 +1012,7 @@ class HGraphBuilder {
HBasicBlock* CreateBasicBlock(HEnvironment* env); HBasicBlock* CreateBasicBlock(HEnvironment* env);
HBasicBlock* CreateLoopHeaderBlock(); HBasicBlock* CreateLoopHeaderBlock();
HValue* BuildCheckNonSmi(HValue* object); HValue* BuildCheckHeapObject(HValue* object);
HValue* BuildCheckMap(HValue* obj, Handle<Map> map); HValue* BuildCheckMap(HValue* obj, Handle<Map> map);
// Building common constructs // Building common constructs

View File

@ -1810,8 +1810,11 @@ void LCodeGen::DoValueOf(LValueOf* instr) {
ASSERT(input.is(result)); ASSERT(input.is(result));
Label done; Label done;
// If the object is a smi return the object.
__ JumpIfSmi(input, &done, Label::kNear); if (!instr->hydrogen()->value()->IsHeapObject()) {
// If the object is a smi return the object.
__ JumpIfSmi(input, &done, Label::kNear);
}
// If the object is not a value type, return the object. // If the object is not a value type, return the object.
__ CmpObjectType(input, JS_VALUE_TYPE, map); __ CmpObjectType(input, JS_VALUE_TYPE, map);
@ -2364,8 +2367,11 @@ void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
Condition LCodeGen::EmitIsString(Register input, Condition LCodeGen::EmitIsString(Register input,
Register temp1, Register temp1,
Label* is_not_string) { Label* is_not_string,
__ JumpIfSmi(input, is_not_string); SmiCheck check_needed = INLINE_SMI_CHECK) {
if (check_needed == INLINE_SMI_CHECK) {
__ JumpIfSmi(input, is_not_string);
}
Condition cond = masm_->IsObjectStringType(input, temp1, temp1); Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
@ -2377,7 +2383,12 @@ void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
Register reg = ToRegister(instr->value()); Register reg = ToRegister(instr->value());
Register temp = ToRegister(instr->temp()); Register temp = ToRegister(instr->temp());
Condition true_cond = EmitIsString(reg, temp, instr->FalseLabel(chunk_)); SmiCheck check_needed =
instr->hydrogen()->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
Condition true_cond = EmitIsString(
reg, temp, instr->FalseLabel(chunk_), check_needed);
EmitBranch(instr, true_cond); EmitBranch(instr, true_cond);
} }
@ -2395,8 +2406,10 @@ void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
Register input = ToRegister(instr->value()); Register input = ToRegister(instr->value());
Register temp = ToRegister(instr->temp()); Register temp = ToRegister(instr->temp());
STATIC_ASSERT(kSmiTag == 0); if (!instr->hydrogen()->value()->IsHeapObject()) {
__ JumpIfSmi(input, instr->FalseLabel(chunk_)); STATIC_ASSERT(kSmiTag == 0);
__ JumpIfSmi(input, instr->FalseLabel(chunk_));
}
__ mov(temp, FieldOperand(input, HeapObject::kMapOffset)); __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
__ test_b(FieldOperand(temp, Map::kBitFieldOffset), __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
1 << Map::kIsUndetectable); 1 << Map::kIsUndetectable);
@ -2461,7 +2474,9 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
Register input = ToRegister(instr->value()); Register input = ToRegister(instr->value());
Register temp = ToRegister(instr->temp()); Register temp = ToRegister(instr->temp());
__ JumpIfSmi(input, instr->FalseLabel(chunk_)); if (!instr->hydrogen()->value()->IsHeapObject()) {
__ JumpIfSmi(input, instr->FalseLabel(chunk_));
}
__ CmpObjectType(input, TestType(instr->hydrogen()), temp); __ CmpObjectType(input, TestType(instr->hydrogen()), temp);
EmitBranch(instr, BranchCondition(instr->hydrogen())); EmitBranch(instr, BranchCondition(instr->hydrogen()));
@ -2898,9 +2913,9 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
__ mov(target, value); __ mov(target, value);
if (instr->hydrogen()->NeedsWriteBarrier()) { if (instr->hydrogen()->NeedsWriteBarrier()) {
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed = SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; instr->hydrogen()->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
Register temp = ToRegister(instr->temp()); Register temp = ToRegister(instr->temp());
int offset = Context::SlotOffset(instr->slot_index()); int offset = Context::SlotOffset(instr->slot_index());
__ RecordWriteContextSlot(context, __ RecordWriteContextSlot(context,
@ -4269,9 +4284,9 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
} }
// Do the store. // Do the store.
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed = SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; instr->hydrogen()->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
Register write_register = object; Register write_register = object;
if (!access.IsInobject()) { if (!access.IsInobject()) {
@ -4508,9 +4523,9 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
ASSERT(instr->value()->IsRegister()); ASSERT(instr->value()->IsRegister());
Register value = ToRegister(instr->value()); Register value = ToRegister(instr->value());
ASSERT(!instr->key()->IsConstantOperand()); ASSERT(!instr->key()->IsConstantOperand());
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed = SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; instr->hydrogen()->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
// Compute address of modified element and store it into key register. // Compute address of modified element and store it into key register.
__ lea(key, operand); __ lea(key, operand);
__ RecordWrite(elements, __ RecordWrite(elements,
@ -5652,9 +5667,11 @@ void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
LOperand* input = instr->value(); if (!instr->hydrogen()->value()->IsHeapObject()) {
__ test(ToOperand(input), Immediate(kSmiTagMask)); LOperand* input = instr->value();
DeoptimizeIf(zero, instr->environment()); __ test(ToOperand(input), Immediate(kSmiTagMask));
DeoptimizeIf(zero, instr->environment());
}
} }

View File

@ -357,7 +357,8 @@ class LCodeGen BASE_EMBEDDED {
// true and false label should be made, to optimize fallthrough. // true and false label should be made, to optimize fallthrough.
Condition EmitIsString(Register input, Condition EmitIsString(Register input,
Register temp1, Register temp1,
Label* is_not_string); Label* is_not_string,
SmiCheck check_needed);
// Emits optimized code for %_IsConstructCall(). // Emits optimized code for %_IsConstructCall().
// Caller should branch on equal condition. // Caller should branch on equal condition.

View File

@ -2040,7 +2040,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
} }
LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) { LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
LOperand* value = UseAtStart(instr->value()); LOperand* value = UseAtStart(instr->value());
return AssignEnvironment(new(zone()) LCheckNonSmi(value)); return AssignEnvironment(new(zone()) LCheckNonSmi(value));
} }

View File

@ -895,6 +895,7 @@ class LIsStringAndBranch: public LControlInstruction<1, 1> {
LOperand* temp() { return temps_[0]; } LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch") DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch)
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
}; };
@ -927,6 +928,7 @@ class LIsUndetectableAndBranch: public LControlInstruction<1, 1> {
DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch, DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch,
"is-undetectable-and-branch") "is-undetectable-and-branch")
DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch)
virtual void PrintDataTo(StringStream* stream); virtual void PrintDataTo(StringStream* stream);
}; };
@ -2570,6 +2572,7 @@ class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> {
LOperand* value() { return inputs_[0]; } LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi") DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi")
DECLARE_HYDROGEN_ACCESSOR(CheckHeapObject)
}; };

View File

@ -1586,8 +1586,11 @@ void LCodeGen::DoValueOf(LValueOf* instr) {
Register result = ToRegister(instr->result()); Register result = ToRegister(instr->result());
ASSERT(input.is(result)); ASSERT(input.is(result));
Label done; Label done;
// If the object is a smi return the object.
__ JumpIfSmi(input, &done, Label::kNear); if (!instr->hydrogen()->value()->IsHeapObject()) {
// If the object is a smi return the object.
__ JumpIfSmi(input, &done, Label::kNear);
}
// If the object is not a value type, return the object. // If the object is not a value type, return the object.
__ CmpObjectType(input, JS_VALUE_TYPE, kScratchRegister); __ CmpObjectType(input, JS_VALUE_TYPE, kScratchRegister);
@ -2151,8 +2154,12 @@ void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
Condition LCodeGen::EmitIsString(Register input, Condition LCodeGen::EmitIsString(Register input,
Register temp1, Register temp1,
Label* is_not_string) { Label* is_not_string,
__ JumpIfSmi(input, is_not_string); SmiCheck check_needed = INLINE_SMI_CHECK) {
if (check_needed == INLINE_SMI_CHECK) {
__ JumpIfSmi(input, is_not_string);
}
Condition cond = masm_->IsObjectStringType(input, temp1, temp1); Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
return cond; return cond;
@ -2163,7 +2170,12 @@ void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
Register reg = ToRegister(instr->value()); Register reg = ToRegister(instr->value());
Register temp = ToRegister(instr->temp()); Register temp = ToRegister(instr->temp());
Condition true_cond = EmitIsString(reg, temp, instr->FalseLabel(chunk_)); SmiCheck check_needed =
instr->hydrogen()->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
Condition true_cond = EmitIsString(
reg, temp, instr->FalseLabel(chunk_), check_needed);
EmitBranch(instr, true_cond); EmitBranch(instr, true_cond);
} }
@ -2186,7 +2198,9 @@ void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
Register input = ToRegister(instr->value()); Register input = ToRegister(instr->value());
Register temp = ToRegister(instr->temp()); Register temp = ToRegister(instr->temp());
__ JumpIfSmi(input, instr->FalseLabel(chunk_)); if (!instr->hydrogen()->value()->IsHeapObject()) {
__ JumpIfSmi(input, instr->FalseLabel(chunk_));
}
__ movq(temp, FieldOperand(input, HeapObject::kMapOffset)); __ movq(temp, FieldOperand(input, HeapObject::kMapOffset));
__ testb(FieldOperand(temp, Map::kBitFieldOffset), __ testb(FieldOperand(temp, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable)); Immediate(1 << Map::kIsUndetectable));
@ -2230,7 +2244,9 @@ static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
Register input = ToRegister(instr->value()); Register input = ToRegister(instr->value());
__ JumpIfSmi(input, instr->FalseLabel(chunk_)); if (!instr->hydrogen()->value()->IsHeapObject()) {
__ JumpIfSmi(input, instr->FalseLabel(chunk_));
}
__ CmpObjectType(input, TestType(instr->hydrogen()), kScratchRegister); __ CmpObjectType(input, TestType(instr->hydrogen()), kScratchRegister);
EmitBranch(instr, BranchCondition(instr->hydrogen())); EmitBranch(instr, BranchCondition(instr->hydrogen()));
@ -2640,9 +2656,9 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
__ movq(target, value); __ movq(target, value);
if (instr->hydrogen()->NeedsWriteBarrier()) { if (instr->hydrogen()->NeedsWriteBarrier()) {
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed = SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; instr->hydrogen()->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
int offset = Context::SlotOffset(instr->slot_index()); int offset = Context::SlotOffset(instr->slot_index());
Register scratch = ToRegister(instr->temp()); Register scratch = ToRegister(instr->temp());
__ RecordWriteContextSlot(context, __ RecordWriteContextSlot(context,
@ -3965,9 +3981,9 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
} }
// Do the store. // Do the store.
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed = SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; instr->hydrogen()->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
Register write_register = object; Register write_register = object;
if (!access.IsInobject()) { if (!access.IsInobject()) {
@ -4206,9 +4222,9 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
ASSERT(instr->value()->IsRegister()); ASSERT(instr->value()->IsRegister());
Register value = ToRegister(instr->value()); Register value = ToRegister(instr->value());
ASSERT(!instr->key()->IsConstantOperand()); ASSERT(!instr->key()->IsConstantOperand());
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed = SmiCheck check_needed =
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; instr->hydrogen()->value()->IsHeapObject()
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
// Compute address of modified element and store it into key register. // Compute address of modified element and store it into key register.
Register key_reg(ToRegister(key)); Register key_reg(ToRegister(key));
__ lea(key_reg, operand); __ lea(key_reg, operand);
@ -4874,9 +4890,11 @@ void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
LOperand* input = instr->value(); if (!instr->hydrogen()->value()->IsHeapObject()) {
Condition cc = masm()->CheckSmi(ToRegister(input)); LOperand* input = instr->value();
DeoptimizeIf(cc, instr->environment()); Condition cc = masm()->CheckSmi(ToRegister(input));
DeoptimizeIf(cc, instr->environment());
}
} }

View File

@ -312,7 +312,8 @@ class LCodeGen BASE_EMBEDDED {
// true and false label should be made, to optimize fallthrough. // true and false label should be made, to optimize fallthrough.
Condition EmitIsString(Register input, Condition EmitIsString(Register input,
Register temp1, Register temp1,
Label* is_not_string); Label* is_not_string,
SmiCheck check_needed);
// Emits optimized code for %_IsConstructCall(). // Emits optimized code for %_IsConstructCall().
// Caller should branch on equal condition. // Caller should branch on equal condition.

View File

@ -1913,7 +1913,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
} }
LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) { LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
LOperand* value = UseRegisterAtStart(instr->value()); LOperand* value = UseRegisterAtStart(instr->value());
return AssignEnvironment(new(zone()) LCheckNonSmi(value)); return AssignEnvironment(new(zone()) LCheckNonSmi(value));
} }

View File

@ -2379,6 +2379,7 @@ class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> {
LOperand* value() { return inputs_[0]; } LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi") DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi")
DECLARE_HYDROGEN_ACCESSOR(CheckHeapObject)
}; };