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:
parent
df181f2c11
commit
21cd74eaa2
@ -2000,7 +2000,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
|
||||
LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
|
||||
LOperand* value = UseRegisterAtStart(instr->value());
|
||||
return AssignEnvironment(new(zone()) LCheckNonSmi(value));
|
||||
}
|
||||
|
@ -2421,6 +2421,7 @@ class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> {
|
||||
LOperand* value() { return inputs_[0]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi")
|
||||
DECLARE_HYDROGEN_ACCESSOR(CheckHeapObject)
|
||||
};
|
||||
|
||||
|
||||
|
@ -1880,10 +1880,12 @@ void LCodeGen::DoValueOf(LValueOf* instr) {
|
||||
Register map = ToRegister(instr->temp());
|
||||
Label done;
|
||||
|
||||
// If the object is a smi return the object.
|
||||
__ SmiTst(input);
|
||||
__ Move(result, input, eq);
|
||||
__ b(eq, &done);
|
||||
if (!instr->hydrogen()->value()->IsHeapObject()) {
|
||||
// If the object is a smi return the object.
|
||||
__ SmiTst(input);
|
||||
__ Move(result, input, eq);
|
||||
__ b(eq, &done);
|
||||
}
|
||||
|
||||
// If the object is not a value type, return the object.
|
||||
__ CompareObjectType(input, map, map, JS_VALUE_TYPE);
|
||||
@ -2438,8 +2440,11 @@ void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
|
||||
|
||||
Condition LCodeGen::EmitIsString(Register input,
|
||||
Register temp1,
|
||||
Label* is_not_string) {
|
||||
__ JumpIfSmi(input, is_not_string);
|
||||
Label* 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);
|
||||
|
||||
return lt;
|
||||
@ -2450,8 +2455,11 @@ void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
|
||||
Register reg = ToRegister(instr->value());
|
||||
Register temp1 = ToRegister(instr->temp());
|
||||
|
||||
SmiCheck check_needed =
|
||||
instr->hydrogen()->value()->IsHeapObject()
|
||||
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
|
||||
Condition true_cond =
|
||||
EmitIsString(reg, temp1, instr->FalseLabel(chunk_));
|
||||
EmitIsString(reg, temp1, instr->FalseLabel(chunk_), check_needed);
|
||||
|
||||
EmitBranch(instr, true_cond);
|
||||
}
|
||||
@ -2468,7 +2476,9 @@ void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
|
||||
Register input = ToRegister(instr->value());
|
||||
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));
|
||||
__ ldrb(temp, FieldMemOperand(temp, Map::kBitFieldOffset));
|
||||
__ tst(temp, Operand(1 << Map::kIsUndetectable));
|
||||
@ -2534,7 +2544,9 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
|
||||
Register scratch = scratch0();
|
||||
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()));
|
||||
EmitBranch(instr, BranchCondition(instr->hydrogen()));
|
||||
@ -2969,9 +2981,9 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
|
||||
|
||||
__ str(value, target);
|
||||
if (instr->hydrogen()->NeedsWriteBarrier()) {
|
||||
HType type = instr->hydrogen()->value()->type();
|
||||
SmiCheck check_needed =
|
||||
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
|
||||
instr->hydrogen()->value()->IsHeapObject()
|
||||
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
|
||||
__ RecordWriteContextSlot(context,
|
||||
target.offset(),
|
||||
value,
|
||||
@ -4209,9 +4221,9 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
||||
// Do the store.
|
||||
Register value = ToRegister(instr->value());
|
||||
ASSERT(!object.is(value));
|
||||
HType type = instr->hydrogen()->value()->type();
|
||||
SmiCheck check_needed =
|
||||
type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
|
||||
instr->hydrogen()->value()->IsHeapObject()
|
||||
? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
|
||||
if (access.IsInobject()) {
|
||||
__ str(value, FieldMemOperand(object, offset));
|
||||
if (instr->hydrogen()->NeedsWriteBarrier()) {
|
||||
@ -4420,9 +4432,9 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
|
||||
__ str(value, FieldMemOperand(store_base, offset));
|
||||
|
||||
if (instr->hydrogen()->NeedsWriteBarrier()) {
|
||||
HType type = instr->hydrogen()->value()->type();
|
||||
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.
|
||||
__ add(key, store_base, Operand(offset - kHeapObjectTag));
|
||||
__ RecordWrite(elements,
|
||||
@ -5144,9 +5156,11 @@ void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
|
||||
LOperand* input = instr->value();
|
||||
__ SmiTst(ToRegister(input));
|
||||
DeoptimizeIf(eq, instr->environment());
|
||||
if (!instr->hydrogen()->value()->IsHeapObject()) {
|
||||
LOperand* input = instr->value();
|
||||
__ SmiTst(ToRegister(input));
|
||||
DeoptimizeIf(eq, instr->environment());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -349,7 +349,8 @@ class LCodeGen BASE_EMBEDDED {
|
||||
// true and false label should be made, to optimize fallthrough.
|
||||
Condition EmitIsString(Register input,
|
||||
Register temp1,
|
||||
Label* is_not_string);
|
||||
Label* is_not_string,
|
||||
SmiCheck check_needed);
|
||||
|
||||
// Emits optimized code for %_IsConstructCall().
|
||||
// Caller should branch on equal condition.
|
||||
|
@ -3065,9 +3065,8 @@ HType HCheckFunction::CalculateInferredType() {
|
||||
}
|
||||
|
||||
|
||||
HType HCheckNonSmi::CalculateInferredType() {
|
||||
// TODO(kasperl): Is there any way to signal that this isn't a smi?
|
||||
return HType::Tagged();
|
||||
HType HCheckHeapObject::CalculateInferredType() {
|
||||
return HType::NonPrimitive();
|
||||
}
|
||||
|
||||
|
||||
@ -3736,7 +3735,7 @@ void HSimulate::Verify() {
|
||||
}
|
||||
|
||||
|
||||
void HCheckNonSmi::Verify() {
|
||||
void HCheckHeapObject::Verify() {
|
||||
HInstruction::Verify();
|
||||
ASSERT(HasNoUses());
|
||||
}
|
||||
|
@ -89,9 +89,9 @@ class LChunkBuilder;
|
||||
V(CallStub) \
|
||||
V(Change) \
|
||||
V(CheckFunction) \
|
||||
V(CheckHeapObject) \
|
||||
V(CheckInstanceType) \
|
||||
V(CheckMaps) \
|
||||
V(CheckNonSmi) \
|
||||
V(CheckPrototypeMaps) \
|
||||
V(ClampToUint8) \
|
||||
V(ClassOfTestAndBranch) \
|
||||
@ -434,7 +434,7 @@ class HType {
|
||||
|
||||
bool IsHeapObject() const {
|
||||
ASSERT(type_ != kUninitialized);
|
||||
return IsHeapNumber() || IsString() || IsNonPrimitive();
|
||||
return IsHeapNumber() || IsString() || IsBoolean() || IsNonPrimitive();
|
||||
}
|
||||
|
||||
static HType TypeFromValue(Handle<Object> value);
|
||||
@ -918,6 +918,10 @@ class HValue: public ZoneObject {
|
||||
type_ = new_type;
|
||||
}
|
||||
|
||||
bool IsHeapObject() {
|
||||
return representation_.IsHeapObject() || type_.IsHeapObject();
|
||||
}
|
||||
|
||||
// An operation needs to override this function iff:
|
||||
// 1) it can produce an int32 output.
|
||||
// 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:
|
||||
explicit HCheckNonSmi(HValue* value) : HUnaryOperation(value) {
|
||||
explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) {
|
||||
set_representation(Representation::Tagged());
|
||||
SetFlag(kUseGVN);
|
||||
}
|
||||
@ -2967,17 +2971,13 @@ class HCheckNonSmi: public HUnaryOperation {
|
||||
|
||||
virtual HValue* Canonicalize() {
|
||||
HType value_type = value()->type();
|
||||
if (!value_type.IsUninitialized() &&
|
||||
(value_type.IsHeapNumber() ||
|
||||
value_type.IsString() ||
|
||||
value_type.IsBoolean() ||
|
||||
value_type.IsNonPrimitive())) {
|
||||
if (!value_type.IsUninitialized() && value_type.IsHeapObject()) {
|
||||
return NULL;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi)
|
||||
DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject)
|
||||
|
||||
protected:
|
||||
virtual bool DataEquals(HValue* other) { return true; }
|
||||
|
@ -1024,9 +1024,9 @@ HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() {
|
||||
}
|
||||
|
||||
|
||||
HValue* HGraphBuilder::BuildCheckNonSmi(HValue* obj) {
|
||||
HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) {
|
||||
if (obj->type().IsHeapObject()) return obj;
|
||||
HCheckNonSmi* check = new(zone()) HCheckNonSmi(obj);
|
||||
HCheckHeapObject* check = new(zone()) HCheckHeapObject(obj);
|
||||
AddInstruction(check);
|
||||
return check;
|
||||
}
|
||||
@ -1703,7 +1703,7 @@ void HGraphBuilder::BuildCompareNil(
|
||||
if_nil.Then();
|
||||
if_nil.Else();
|
||||
if (type->NumClasses() == 1) {
|
||||
BuildCheckNonSmi(value);
|
||||
BuildCheckHeapObject(value);
|
||||
// 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
|
||||
// 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) {
|
||||
BuildCheckNonSmi(object);
|
||||
BuildCheckHeapObject(object);
|
||||
AddInstruction(HCheckMaps::New(object, map, zone()));
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::AddCheckMapsWithTransitions(HValue* object,
|
||||
Handle<Map> map) {
|
||||
BuildCheckNonSmi(object);
|
||||
BuildCheckHeapObject(object);
|
||||
AddInstruction(HCheckMaps::NewWithTransitions(object, map, zone()));
|
||||
}
|
||||
|
||||
@ -6334,7 +6334,7 @@ HInstruction* HOptimizedGraphBuilder::TryLoadPolymorphicAsMonomorphic(
|
||||
if (count != types->length()) return NULL;
|
||||
|
||||
// Everything matched; can use monomorphic load.
|
||||
BuildCheckNonSmi(object);
|
||||
BuildCheckHeapObject(object);
|
||||
AddInstruction(HCheckMaps::New(object, types, zone()));
|
||||
return BuildLoadNamedField(object, access, representation);
|
||||
}
|
||||
@ -6349,7 +6349,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
|
||||
expr, object, types, name);
|
||||
if (instr == NULL) {
|
||||
// Something did not match; must use a polymorphic load.
|
||||
BuildCheckNonSmi(object);
|
||||
BuildCheckHeapObject(object);
|
||||
HValue* context = environment()->LookupContext();
|
||||
instr = new(zone()) HLoadNamedFieldPolymorphic(
|
||||
context, object, types, name, zone());
|
||||
@ -6405,7 +6405,7 @@ bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic(
|
||||
if (count != types->length()) return false;
|
||||
|
||||
// Everything matched; can use monomorphic store.
|
||||
BuildCheckNonSmi(object);
|
||||
BuildCheckHeapObject(object);
|
||||
AddInstruction(HCheckMaps::New(object, types, zone()));
|
||||
HInstruction* store;
|
||||
CHECK_ALIVE_OR_RETURN(
|
||||
@ -6444,7 +6444,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField(
|
||||
LookupResult lookup(isolate());
|
||||
if (ComputeLoadStoreField(map, name, &lookup, true)) {
|
||||
if (count == 0) {
|
||||
BuildCheckNonSmi(object);
|
||||
BuildCheckHeapObject(object);
|
||||
join = graph()->CreateBasicBlock();
|
||||
}
|
||||
++count;
|
||||
@ -7178,7 +7178,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
|
||||
KeyedAccessStoreMode store_mode,
|
||||
bool* has_side_effects) {
|
||||
*has_side_effects = false;
|
||||
BuildCheckNonSmi(object);
|
||||
BuildCheckHeapObject(object);
|
||||
SmallMapList* maps = prop->GetReceiverTypes();
|
||||
bool todo_external_array = false;
|
||||
|
||||
@ -7403,7 +7403,7 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
|
||||
: BuildLoadKeyedGeneric(obj, key);
|
||||
AddInstruction(instr);
|
||||
} else {
|
||||
BuildCheckNonSmi(obj);
|
||||
BuildCheckHeapObject(obj);
|
||||
instr = BuildMonomorphicElementAccess(
|
||||
obj, key, val, NULL, map, is_store, expr->GetStoreMode());
|
||||
}
|
||||
@ -7535,7 +7535,7 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
|
||||
HInstruction* instr = NULL;
|
||||
if (expr->IsStringLength()) {
|
||||
HValue* string = Pop();
|
||||
BuildCheckNonSmi(string);
|
||||
BuildCheckHeapObject(string);
|
||||
AddInstruction(HCheckInstanceType::NewIsString(string, zone()));
|
||||
instr = HStringLength::New(zone(), string);
|
||||
} else if (expr->IsStringAccess()) {
|
||||
@ -7550,7 +7550,7 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
|
||||
|
||||
} else if (expr->IsFunctionPrototype()) {
|
||||
HValue* function = Pop();
|
||||
BuildCheckNonSmi(function);
|
||||
BuildCheckHeapObject(function);
|
||||
instr = new(zone()) HLoadFunctionPrototype(function);
|
||||
|
||||
} else if (expr->key()->IsPropertyName()) {
|
||||
@ -7724,7 +7724,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
|
||||
empty_smi_block->Goto(number_block);
|
||||
set_current_block(not_smi_block);
|
||||
} else {
|
||||
BuildCheckNonSmi(receiver);
|
||||
BuildCheckHeapObject(receiver);
|
||||
}
|
||||
}
|
||||
HBasicBlock* if_true = graph()->CreateBasicBlock();
|
||||
@ -9335,7 +9335,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStringCharCodeAt(
|
||||
return new(zone()) HConstant(s->Get(i));
|
||||
}
|
||||
}
|
||||
BuildCheckNonSmi(string);
|
||||
BuildCheckHeapObject(string);
|
||||
AddInstruction(HCheckInstanceType::NewIsString(string, zone()));
|
||||
HInstruction* length = HStringLength::New(zone(), string);
|
||||
AddInstruction(length);
|
||||
@ -9426,9 +9426,9 @@ HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation(
|
||||
switch (expr->op()) {
|
||||
case Token::ADD:
|
||||
if (left_type->Is(Type::String()) && right_type->Is(Type::String())) {
|
||||
BuildCheckNonSmi(left);
|
||||
BuildCheckHeapObject(left);
|
||||
AddInstruction(HCheckInstanceType::NewIsString(left, zone()));
|
||||
BuildCheckNonSmi(right);
|
||||
BuildCheckHeapObject(right);
|
||||
AddInstruction(HCheckInstanceType::NewIsString(right, zone()));
|
||||
instr = HStringAdd::New(zone(), context, left, right);
|
||||
} else {
|
||||
@ -9845,9 +9845,9 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
|
||||
result->set_position(expr->position());
|
||||
return ast_context()->ReturnControl(result, expr->id());
|
||||
} else {
|
||||
BuildCheckNonSmi(left);
|
||||
BuildCheckHeapObject(left);
|
||||
AddInstruction(HCheckInstanceType::NewIsSpecObject(left, zone()));
|
||||
BuildCheckNonSmi(right);
|
||||
BuildCheckHeapObject(right);
|
||||
AddInstruction(HCheckInstanceType::NewIsSpecObject(right, zone()));
|
||||
HCompareObjectEqAndBranch* result =
|
||||
new(zone()) HCompareObjectEqAndBranch(left, right);
|
||||
@ -9860,9 +9860,9 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
|
||||
}
|
||||
} else if (combined_type->Is(Type::InternalizedString()) &&
|
||||
Token::IsEqualityOp(op)) {
|
||||
BuildCheckNonSmi(left);
|
||||
BuildCheckHeapObject(left);
|
||||
AddInstruction(HCheckInstanceType::NewIsInternalizedString(left, zone()));
|
||||
BuildCheckNonSmi(right);
|
||||
BuildCheckHeapObject(right);
|
||||
AddInstruction(HCheckInstanceType::NewIsInternalizedString(right, zone()));
|
||||
HCompareObjectEqAndBranch* result =
|
||||
new(zone()) HCompareObjectEqAndBranch(left, right);
|
||||
|
@ -1012,7 +1012,7 @@ class HGraphBuilder {
|
||||
HBasicBlock* CreateBasicBlock(HEnvironment* env);
|
||||
HBasicBlock* CreateLoopHeaderBlock();
|
||||
|
||||
HValue* BuildCheckNonSmi(HValue* object);
|
||||
HValue* BuildCheckHeapObject(HValue* object);
|
||||
HValue* BuildCheckMap(HValue* obj, Handle<Map> map);
|
||||
|
||||
// Building common constructs
|
||||
|
@ -1810,8 +1810,11 @@ void LCodeGen::DoValueOf(LValueOf* instr) {
|
||||
ASSERT(input.is(result));
|
||||
|
||||
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.
|
||||
__ CmpObjectType(input, JS_VALUE_TYPE, map);
|
||||
@ -2364,8 +2367,11 @@ void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
|
||||
|
||||
Condition LCodeGen::EmitIsString(Register input,
|
||||
Register temp1,
|
||||
Label* is_not_string) {
|
||||
__ JumpIfSmi(input, is_not_string);
|
||||
Label* 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);
|
||||
|
||||
@ -2377,7 +2383,12 @@ void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
|
||||
Register reg = ToRegister(instr->value());
|
||||
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);
|
||||
}
|
||||
@ -2395,8 +2406,10 @@ void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
|
||||
Register input = ToRegister(instr->value());
|
||||
Register temp = ToRegister(instr->temp());
|
||||
|
||||
STATIC_ASSERT(kSmiTag == 0);
|
||||
__ JumpIfSmi(input, instr->FalseLabel(chunk_));
|
||||
if (!instr->hydrogen()->value()->IsHeapObject()) {
|
||||
STATIC_ASSERT(kSmiTag == 0);
|
||||
__ JumpIfSmi(input, instr->FalseLabel(chunk_));
|
||||
}
|
||||
__ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
|
||||
__ test_b(FieldOperand(temp, Map::kBitFieldOffset),
|
||||
1 << Map::kIsUndetectable);
|
||||
@ -2461,7 +2474,9 @@ void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
|
||||
Register input = ToRegister(instr->value());
|
||||
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);
|
||||
EmitBranch(instr, BranchCondition(instr->hydrogen()));
|
||||
@ -2898,9 +2913,9 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
|
||||
|
||||
__ mov(target, value);
|
||||
if (instr->hydrogen()->NeedsWriteBarrier()) {
|
||||
HType type = instr->hydrogen()->value()->type();
|
||||
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());
|
||||
int offset = Context::SlotOffset(instr->slot_index());
|
||||
__ RecordWriteContextSlot(context,
|
||||
@ -4269,9 +4284,9 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
||||
}
|
||||
|
||||
// Do the store.
|
||||
HType type = instr->hydrogen()->value()->type();
|
||||
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;
|
||||
if (!access.IsInobject()) {
|
||||
@ -4508,9 +4523,9 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
|
||||
ASSERT(instr->value()->IsRegister());
|
||||
Register value = ToRegister(instr->value());
|
||||
ASSERT(!instr->key()->IsConstantOperand());
|
||||
HType type = instr->hydrogen()->value()->type();
|
||||
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.
|
||||
__ lea(key, operand);
|
||||
__ RecordWrite(elements,
|
||||
@ -5652,9 +5667,11 @@ void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
|
||||
LOperand* input = instr->value();
|
||||
__ test(ToOperand(input), Immediate(kSmiTagMask));
|
||||
DeoptimizeIf(zero, instr->environment());
|
||||
if (!instr->hydrogen()->value()->IsHeapObject()) {
|
||||
LOperand* input = instr->value();
|
||||
__ test(ToOperand(input), Immediate(kSmiTagMask));
|
||||
DeoptimizeIf(zero, instr->environment());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -357,7 +357,8 @@ class LCodeGen BASE_EMBEDDED {
|
||||
// true and false label should be made, to optimize fallthrough.
|
||||
Condition EmitIsString(Register input,
|
||||
Register temp1,
|
||||
Label* is_not_string);
|
||||
Label* is_not_string,
|
||||
SmiCheck check_needed);
|
||||
|
||||
// Emits optimized code for %_IsConstructCall().
|
||||
// Caller should branch on equal condition.
|
||||
|
@ -2040,7 +2040,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
|
||||
LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
|
||||
LOperand* value = UseAtStart(instr->value());
|
||||
return AssignEnvironment(new(zone()) LCheckNonSmi(value));
|
||||
}
|
||||
|
@ -895,6 +895,7 @@ class LIsStringAndBranch: public LControlInstruction<1, 1> {
|
||||
LOperand* temp() { return temps_[0]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch")
|
||||
DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch)
|
||||
|
||||
virtual void PrintDataTo(StringStream* stream);
|
||||
};
|
||||
@ -927,6 +928,7 @@ class LIsUndetectableAndBranch: public LControlInstruction<1, 1> {
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch,
|
||||
"is-undetectable-and-branch")
|
||||
DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch)
|
||||
|
||||
virtual void PrintDataTo(StringStream* stream);
|
||||
};
|
||||
@ -2570,6 +2572,7 @@ class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> {
|
||||
LOperand* value() { return inputs_[0]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi")
|
||||
DECLARE_HYDROGEN_ACCESSOR(CheckHeapObject)
|
||||
};
|
||||
|
||||
|
||||
|
@ -1586,8 +1586,11 @@ void LCodeGen::DoValueOf(LValueOf* instr) {
|
||||
Register result = ToRegister(instr->result());
|
||||
ASSERT(input.is(result));
|
||||
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.
|
||||
__ CmpObjectType(input, JS_VALUE_TYPE, kScratchRegister);
|
||||
@ -2151,8 +2154,12 @@ void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
|
||||
|
||||
Condition LCodeGen::EmitIsString(Register input,
|
||||
Register temp1,
|
||||
Label* is_not_string) {
|
||||
__ JumpIfSmi(input, is_not_string);
|
||||
Label* 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);
|
||||
|
||||
return cond;
|
||||
@ -2163,7 +2170,12 @@ void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
|
||||
Register reg = ToRegister(instr->value());
|
||||
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);
|
||||
}
|
||||
@ -2186,7 +2198,9 @@ void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
|
||||
Register input = ToRegister(instr->value());
|
||||
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));
|
||||
__ testb(FieldOperand(temp, Map::kBitFieldOffset),
|
||||
Immediate(1 << Map::kIsUndetectable));
|
||||
@ -2230,7 +2244,9 @@ static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
|
||||
void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
|
||||
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);
|
||||
EmitBranch(instr, BranchCondition(instr->hydrogen()));
|
||||
@ -2640,9 +2656,9 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
|
||||
__ movq(target, value);
|
||||
|
||||
if (instr->hydrogen()->NeedsWriteBarrier()) {
|
||||
HType type = instr->hydrogen()->value()->type();
|
||||
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());
|
||||
Register scratch = ToRegister(instr->temp());
|
||||
__ RecordWriteContextSlot(context,
|
||||
@ -3965,9 +3981,9 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
||||
}
|
||||
|
||||
// Do the store.
|
||||
HType type = instr->hydrogen()->value()->type();
|
||||
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;
|
||||
if (!access.IsInobject()) {
|
||||
@ -4206,9 +4222,9 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
|
||||
ASSERT(instr->value()->IsRegister());
|
||||
Register value = ToRegister(instr->value());
|
||||
ASSERT(!instr->key()->IsConstantOperand());
|
||||
HType type = instr->hydrogen()->value()->type();
|
||||
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.
|
||||
Register key_reg(ToRegister(key));
|
||||
__ lea(key_reg, operand);
|
||||
@ -4874,9 +4890,11 @@ void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
|
||||
LOperand* input = instr->value();
|
||||
Condition cc = masm()->CheckSmi(ToRegister(input));
|
||||
DeoptimizeIf(cc, instr->environment());
|
||||
if (!instr->hydrogen()->value()->IsHeapObject()) {
|
||||
LOperand* input = instr->value();
|
||||
Condition cc = masm()->CheckSmi(ToRegister(input));
|
||||
DeoptimizeIf(cc, instr->environment());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -312,7 +312,8 @@ class LCodeGen BASE_EMBEDDED {
|
||||
// true and false label should be made, to optimize fallthrough.
|
||||
Condition EmitIsString(Register input,
|
||||
Register temp1,
|
||||
Label* is_not_string);
|
||||
Label* is_not_string,
|
||||
SmiCheck check_needed);
|
||||
|
||||
// Emits optimized code for %_IsConstructCall().
|
||||
// Caller should branch on equal condition.
|
||||
|
@ -1913,7 +1913,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
|
||||
LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
|
||||
LOperand* value = UseRegisterAtStart(instr->value());
|
||||
return AssignEnvironment(new(zone()) LCheckNonSmi(value));
|
||||
}
|
||||
|
@ -2379,6 +2379,7 @@ class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> {
|
||||
LOperand* value() { return inputs_[0]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi")
|
||||
DECLARE_HYDROGEN_ACCESSOR(CheckHeapObject)
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user