}
-LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
+LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
return AssignEnvironment(new(zone()) LCheckNonSmi(value));
}
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi")
+ DECLARE_HYDROGEN_ACCESSOR(CheckHeapObject)
};
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);
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;
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);
}
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));
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()));
__ 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,
// 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()) {
__ 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,
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());
+ }
}
// 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.
}
-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();
}
}
-void HCheckNonSmi::Verify() {
+void HCheckHeapObject::Verify() {
HInstruction::Verify();
ASSERT(HasNoUses());
}
V(CallStub) \
V(Change) \
V(CheckFunction) \
+ V(CheckHeapObject) \
V(CheckInstanceType) \
V(CheckMaps) \
- V(CheckNonSmi) \
V(CheckPrototypeMaps) \
V(ClampToUint8) \
V(ClassOfTestAndBranch) \
bool IsHeapObject() const {
ASSERT(type_ != kUninitialized);
- return IsHeapNumber() || IsString() || IsNonPrimitive();
+ return IsHeapNumber() || IsString() || IsBoolean() || IsNonPrimitive();
}
static HType TypeFromValue(Handle<Object> value);
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.
};
-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);
}
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; }
}
-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;
}
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
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()));
}
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);
}
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());
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(
LookupResult lookup(isolate());
if (ComputeLoadStoreField(map, name, &lookup, true)) {
if (count == 0) {
- BuildCheckNonSmi(object);
+ BuildCheckHeapObject(object);
join = graph()->CreateBasicBlock();
}
++count;
KeyedAccessStoreMode store_mode,
bool* has_side_effects) {
*has_side_effects = false;
- BuildCheckNonSmi(object);
+ BuildCheckHeapObject(object);
SmallMapList* maps = prop->GetReceiverTypes();
bool todo_external_array = false;
: BuildLoadKeyedGeneric(obj, key);
AddInstruction(instr);
} else {
- BuildCheckNonSmi(obj);
+ BuildCheckHeapObject(obj);
instr = BuildMonomorphicElementAccess(
obj, key, val, NULL, map, is_store, expr->GetStoreMode());
}
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()) {
} else if (expr->IsFunctionPrototype()) {
HValue* function = Pop();
- BuildCheckNonSmi(function);
+ BuildCheckHeapObject(function);
instr = new(zone()) HLoadFunctionPrototype(function);
} else if (expr->key()->IsPropertyName()) {
empty_smi_block->Goto(number_block);
set_current_block(not_smi_block);
} else {
- BuildCheckNonSmi(receiver);
+ BuildCheckHeapObject(receiver);
}
}
HBasicBlock* if_true = graph()->CreateBasicBlock();
return new(zone()) HConstant(s->Get(i));
}
}
- BuildCheckNonSmi(string);
+ BuildCheckHeapObject(string);
AddInstruction(HCheckInstanceType::NewIsString(string, zone()));
HInstruction* length = HStringLength::New(zone(), string);
AddInstruction(length);
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 {
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);
}
} 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);
HBasicBlock* CreateBasicBlock(HEnvironment* env);
HBasicBlock* CreateLoopHeaderBlock();
- HValue* BuildCheckNonSmi(HValue* object);
+ HValue* BuildCheckHeapObject(HValue* object);
HValue* BuildCheckMap(HValue* obj, Handle<Map> map);
// Building common constructs
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);
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);
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);
}
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);
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()));
__ 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,
}
// 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()) {
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,
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());
+ }
}
// 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.
}
-LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
+LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
LOperand* value = UseAtStart(instr->value());
return AssignEnvironment(new(zone()) LCheckNonSmi(value));
}
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch")
+ DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch)
virtual void PrintDataTo(StringStream* stream);
};
DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch,
"is-undetectable-and-branch")
+ DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch)
virtual void PrintDataTo(StringStream* stream);
};
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi")
+ DECLARE_HYDROGEN_ACCESSOR(CheckHeapObject)
};
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);
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;
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);
}
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));
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()));
__ 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,
}
// 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()) {
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);
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());
+ }
}
// 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.
}
-LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
+LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
return AssignEnvironment(new(zone()) LCheckNonSmi(value));
}
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi")
+ DECLARE_HYDROGEN_ACCESSOR(CheckHeapObject)
};