[runtime] Remove the redundant %_IsObject intrinsic.
%_IsObject(foo) is equivalent to typeof foo === 'object' and has exactly the same optimizations, so there's zero need for %_IsObject in our code base. R=mstarzinger@chromium.org Review URL: https://codereview.chromium.org/1313903003 Cr-Commit-Position: refs/heads/master@{#30380}
This commit is contained in:
parent
299f775cf4
commit
b4c7399464
@ -168,13 +168,6 @@ void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
|
||||
stream->Add("if is_object(");
|
||||
value()->PrintTo(stream);
|
||||
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
|
||||
}
|
||||
|
||||
|
||||
void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
|
||||
stream->Add("if is_string(");
|
||||
value()->PrintTo(stream);
|
||||
@ -1776,14 +1769,6 @@ LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
|
||||
DCHECK(instr->value()->representation().IsTagged());
|
||||
LOperand* value = UseRegisterAtStart(instr->value());
|
||||
LOperand* temp = TempRegister();
|
||||
return new(zone()) LIsObjectAndBranch(value, temp);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
|
||||
DCHECK(instr->value()->representation().IsTagged());
|
||||
LOperand* value = UseRegisterAtStart(instr->value());
|
||||
|
@ -91,7 +91,6 @@ class LCodeGen;
|
||||
V(Integer32ToDouble) \
|
||||
V(InvokeFunction) \
|
||||
V(IsConstructCallAndBranch) \
|
||||
V(IsObjectAndBranch) \
|
||||
V(IsStringAndBranch) \
|
||||
V(IsSmiAndBranch) \
|
||||
V(IsUndetectableAndBranch) \
|
||||
@ -1009,23 +1008,6 @@ class LCompareMinusZeroAndBranch final : public LControlInstruction<1, 1> {
|
||||
};
|
||||
|
||||
|
||||
class LIsObjectAndBranch final : public LControlInstruction<1, 1> {
|
||||
public:
|
||||
LIsObjectAndBranch(LOperand* value, LOperand* temp) {
|
||||
inputs_[0] = value;
|
||||
temps_[0] = temp;
|
||||
}
|
||||
|
||||
LOperand* value() { return inputs_[0]; }
|
||||
LOperand* temp() { return temps_[0]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
|
||||
DECLARE_HYDROGEN_ACCESSOR(IsObjectAndBranch)
|
||||
|
||||
void PrintDataTo(StringStream* stream) override;
|
||||
};
|
||||
|
||||
|
||||
class LIsStringAndBranch final : public LControlInstruction<1, 1> {
|
||||
public:
|
||||
LIsStringAndBranch(LOperand* value, LOperand* temp) {
|
||||
|
@ -2460,45 +2460,6 @@ void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
|
||||
}
|
||||
|
||||
|
||||
Condition LCodeGen::EmitIsObject(Register input,
|
||||
Register temp1,
|
||||
Label* is_not_object,
|
||||
Label* is_object) {
|
||||
Register temp2 = scratch0();
|
||||
__ JumpIfSmi(input, is_not_object);
|
||||
|
||||
__ LoadRoot(temp2, Heap::kNullValueRootIndex);
|
||||
__ cmp(input, temp2);
|
||||
__ b(eq, is_object);
|
||||
|
||||
// Load map.
|
||||
__ ldr(temp1, FieldMemOperand(input, HeapObject::kMapOffset));
|
||||
// Undetectable objects behave like undefined.
|
||||
__ ldrb(temp2, FieldMemOperand(temp1, Map::kBitFieldOffset));
|
||||
__ tst(temp2, Operand(1 << Map::kIsUndetectable));
|
||||
__ b(ne, is_not_object);
|
||||
|
||||
// Load instance type and check that it is in object type range.
|
||||
__ ldrb(temp2, FieldMemOperand(temp1, Map::kInstanceTypeOffset));
|
||||
__ cmp(temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
__ b(lt, is_not_object);
|
||||
__ cmp(temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
return le;
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
|
||||
Register reg = ToRegister(instr->value());
|
||||
Register temp1 = ToRegister(instr->temp());
|
||||
|
||||
Condition true_cond =
|
||||
EmitIsObject(reg, temp1,
|
||||
instr->FalseLabel(chunk_), instr->TrueLabel(chunk_));
|
||||
|
||||
EmitBranch(instr, true_cond);
|
||||
}
|
||||
|
||||
|
||||
Condition LCodeGen::EmitIsString(Register input,
|
||||
Register temp1,
|
||||
Label* is_not_string,
|
||||
|
@ -285,14 +285,6 @@ class LCodeGen: public LCodeGenBase {
|
||||
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,
|
||||
Label* is_not_object,
|
||||
Label* is_object);
|
||||
|
||||
// Emits optimized code for %_IsString(x). Preserves input register.
|
||||
// Returns the condition on which a final split to
|
||||
// true and false label should be made, to optimize fallthrough.
|
||||
|
@ -205,13 +205,6 @@ void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
|
||||
stream->Add("if is_object(");
|
||||
value()->PrintTo(stream);
|
||||
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
|
||||
}
|
||||
|
||||
|
||||
void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
|
||||
stream->Add("if is_string(");
|
||||
value()->PrintTo(stream);
|
||||
@ -1620,15 +1613,6 @@ LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
|
||||
DCHECK(instr->value()->representation().IsTagged());
|
||||
LOperand* value = UseRegisterAtStart(instr->value());
|
||||
LOperand* temp1 = TempRegister();
|
||||
LOperand* temp2 = TempRegister();
|
||||
return new(zone()) LIsObjectAndBranch(value, temp1, temp2);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
|
||||
DCHECK(instr->value()->representation().IsTagged());
|
||||
LOperand* value = UseRegisterAtStart(instr->value());
|
||||
|
@ -94,7 +94,6 @@ class LCodeGen;
|
||||
V(Integer32ToDouble) \
|
||||
V(InvokeFunction) \
|
||||
V(IsConstructCallAndBranch) \
|
||||
V(IsObjectAndBranch) \
|
||||
V(IsSmiAndBranch) \
|
||||
V(IsStringAndBranch) \
|
||||
V(IsUndetectableAndBranch) \
|
||||
@ -1595,25 +1594,6 @@ class LIsConstructCallAndBranch final : public LControlInstruction<0, 2> {
|
||||
};
|
||||
|
||||
|
||||
class LIsObjectAndBranch final : public LControlInstruction<1, 2> {
|
||||
public:
|
||||
LIsObjectAndBranch(LOperand* value, LOperand* temp1, LOperand* temp2) {
|
||||
inputs_[0] = value;
|
||||
temps_[0] = temp1;
|
||||
temps_[1] = temp2;
|
||||
}
|
||||
|
||||
LOperand* value() { return inputs_[0]; }
|
||||
LOperand* temp1() { return temps_[0]; }
|
||||
LOperand* temp2() { return temps_[1]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
|
||||
DECLARE_HYDROGEN_ACCESSOR(IsObjectAndBranch)
|
||||
|
||||
void PrintDataTo(StringStream* stream) override;
|
||||
};
|
||||
|
||||
|
||||
class LIsStringAndBranch final : public LControlInstruction<1, 1> {
|
||||
public:
|
||||
LIsStringAndBranch(LOperand* value, LOperand* temp) {
|
||||
|
@ -3099,31 +3099,6 @@ void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
|
||||
Label* is_object = instr->TrueLabel(chunk_);
|
||||
Label* is_not_object = instr->FalseLabel(chunk_);
|
||||
Register value = ToRegister(instr->value());
|
||||
Register map = ToRegister(instr->temp1());
|
||||
Register scratch = ToRegister(instr->temp2());
|
||||
|
||||
__ JumpIfSmi(value, is_not_object);
|
||||
__ JumpIfRoot(value, Heap::kNullValueRootIndex, is_object);
|
||||
|
||||
__ Ldr(map, FieldMemOperand(value, HeapObject::kMapOffset));
|
||||
|
||||
// Check for undetectable objects.
|
||||
__ Ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
|
||||
__ TestAndBranchIfAnySet(scratch, 1 << Map::kIsUndetectable, is_not_object);
|
||||
|
||||
// Check that instance type is in object type range.
|
||||
__ IsInstanceJSObjectType(map, scratch, NULL);
|
||||
// Flags have been updated by IsInstanceJSObjectType. We can now test the
|
||||
// flags for "le" condition to check if the object's type is a valid
|
||||
// JS object type.
|
||||
EmitBranch(instr, le);
|
||||
}
|
||||
|
||||
|
||||
Condition LCodeGen::EmitIsString(Register input,
|
||||
Register temp1,
|
||||
Label* is_not_string,
|
||||
|
@ -3371,39 +3371,6 @@ void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
Label materialize_true, materialize_false;
|
||||
Label* if_true = NULL;
|
||||
Label* if_false = NULL;
|
||||
Label* fall_through = NULL;
|
||||
context()->PrepareTest(&materialize_true, &materialize_false,
|
||||
&if_true, &if_false, &fall_through);
|
||||
|
||||
__ JumpIfSmi(r0, if_false);
|
||||
__ LoadRoot(ip, Heap::kNullValueRootIndex);
|
||||
__ cmp(r0, ip);
|
||||
__ b(eq, if_true);
|
||||
__ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
|
||||
// Undetectable objects behave like undefined when tested with typeof.
|
||||
__ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset));
|
||||
__ tst(r1, Operand(1 << Map::kIsUndetectable));
|
||||
__ b(ne, if_false);
|
||||
__ ldrb(r1, FieldMemOperand(r2, Map::kInstanceTypeOffset));
|
||||
__ cmp(r1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
__ b(lt, if_false);
|
||||
__ cmp(r1, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
|
||||
Split(le, if_true, if_false, fall_through);
|
||||
|
||||
context()->Plug(if_true, if_false);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -3065,36 +3065,6 @@ void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
Label materialize_true, materialize_false;
|
||||
Label* if_true = NULL;
|
||||
Label* if_false = NULL;
|
||||
Label* fall_through = NULL;
|
||||
context()->PrepareTest(&materialize_true, &materialize_false,
|
||||
&if_true, &if_false, &fall_through);
|
||||
|
||||
__ JumpIfSmi(x0, if_false);
|
||||
__ JumpIfRoot(x0, Heap::kNullValueRootIndex, if_true);
|
||||
__ Ldr(x10, FieldMemOperand(x0, HeapObject::kMapOffset));
|
||||
// Undetectable objects behave like undefined when tested with typeof.
|
||||
__ Ldrb(x11, FieldMemOperand(x10, Map::kBitFieldOffset));
|
||||
__ Tbnz(x11, Map::kIsUndetectable, if_false);
|
||||
__ Ldrb(x12, FieldMemOperand(x10, Map::kInstanceTypeOffset));
|
||||
__ Cmp(x12, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
||||
__ B(lt, if_false);
|
||||
__ Cmp(x12, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
||||
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
|
||||
Split(le, if_true, if_false, fall_through);
|
||||
|
||||
context()->Plug(if_true, if_false);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -507,7 +507,6 @@ class FullCodeGenerator: public AstVisitor {
|
||||
F(OneByteSeqStringSetChar) \
|
||||
F(TwoByteSeqStringSetChar) \
|
||||
F(ObjectEquals) \
|
||||
F(IsObject) \
|
||||
F(IsFunction) \
|
||||
F(IsSpecObject) \
|
||||
F(IsSimdValue) \
|
||||
|
@ -3264,38 +3264,6 @@ void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
Label materialize_true, materialize_false;
|
||||
Label* if_true = NULL;
|
||||
Label* if_false = NULL;
|
||||
Label* fall_through = NULL;
|
||||
context()->PrepareTest(&materialize_true, &materialize_false,
|
||||
&if_true, &if_false, &fall_through);
|
||||
|
||||
__ JumpIfSmi(eax, if_false);
|
||||
__ cmp(eax, isolate()->factory()->null_value());
|
||||
__ j(equal, if_true);
|
||||
__ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
|
||||
// Undetectable objects behave like undefined when tested with typeof.
|
||||
__ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset));
|
||||
__ test(ecx, Immediate(1 << Map::kIsUndetectable));
|
||||
__ j(not_zero, if_false);
|
||||
__ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset));
|
||||
__ cmp(ecx, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
||||
__ j(below, if_false);
|
||||
__ cmp(ecx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
||||
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
|
||||
Split(below_equal, if_true, if_false, fall_through);
|
||||
|
||||
context()->Plug(if_true, if_false);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -3362,37 +3362,6 @@ void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
Label materialize_true, materialize_false;
|
||||
Label* if_true = NULL;
|
||||
Label* if_false = NULL;
|
||||
Label* fall_through = NULL;
|
||||
context()->PrepareTest(&materialize_true, &materialize_false,
|
||||
&if_true, &if_false, &fall_through);
|
||||
|
||||
__ JumpIfSmi(v0, if_false);
|
||||
__ LoadRoot(at, Heap::kNullValueRootIndex);
|
||||
__ Branch(if_true, eq, v0, Operand(at));
|
||||
__ lw(a2, FieldMemOperand(v0, HeapObject::kMapOffset));
|
||||
// Undetectable objects behave like undefined when tested with typeof.
|
||||
__ lbu(a1, FieldMemOperand(a2, Map::kBitFieldOffset));
|
||||
__ And(at, a1, Operand(1 << Map::kIsUndetectable));
|
||||
__ Branch(if_false, ne, at, Operand(zero_reg));
|
||||
__ lbu(a1, FieldMemOperand(a2, Map::kInstanceTypeOffset));
|
||||
__ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
|
||||
Split(le, a1, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE),
|
||||
if_true, if_false, fall_through);
|
||||
|
||||
context()->Plug(if_true, if_false);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -3363,37 +3363,6 @@ void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
Label materialize_true, materialize_false;
|
||||
Label* if_true = NULL;
|
||||
Label* if_false = NULL;
|
||||
Label* fall_through = NULL;
|
||||
context()->PrepareTest(&materialize_true, &materialize_false,
|
||||
&if_true, &if_false, &fall_through);
|
||||
|
||||
__ JumpIfSmi(v0, if_false);
|
||||
__ LoadRoot(at, Heap::kNullValueRootIndex);
|
||||
__ Branch(if_true, eq, v0, Operand(at));
|
||||
__ ld(a2, FieldMemOperand(v0, HeapObject::kMapOffset));
|
||||
// Undetectable objects behave like undefined when tested with typeof.
|
||||
__ lbu(a1, FieldMemOperand(a2, Map::kBitFieldOffset));
|
||||
__ And(at, a1, Operand(1 << Map::kIsUndetectable));
|
||||
__ Branch(if_false, ne, at, Operand(zero_reg));
|
||||
__ lbu(a1, FieldMemOperand(a2, Map::kInstanceTypeOffset));
|
||||
__ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
|
||||
Split(le, a1, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE),
|
||||
if_true, if_false, fall_through);
|
||||
|
||||
context()->Plug(if_true, if_false);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -3363,39 +3363,6 @@ void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
Label materialize_true, materialize_false;
|
||||
Label* if_true = NULL;
|
||||
Label* if_false = NULL;
|
||||
Label* fall_through = NULL;
|
||||
context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
|
||||
&if_false, &fall_through);
|
||||
|
||||
__ JumpIfSmi(r3, if_false);
|
||||
__ LoadRoot(ip, Heap::kNullValueRootIndex);
|
||||
__ cmp(r3, ip);
|
||||
__ beq(if_true);
|
||||
__ LoadP(r5, FieldMemOperand(r3, HeapObject::kMapOffset));
|
||||
// Undetectable objects behave like undefined when tested with typeof.
|
||||
__ lbz(r4, FieldMemOperand(r5, Map::kBitFieldOffset));
|
||||
__ andi(r0, r4, Operand(1 << Map::kIsUndetectable));
|
||||
__ bne(if_false, cr0);
|
||||
__ lbz(r4, FieldMemOperand(r5, Map::kInstanceTypeOffset));
|
||||
__ cmpi(r4, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
__ blt(if_false);
|
||||
__ cmpi(r4, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
|
||||
Split(le, if_true, if_false, fall_through);
|
||||
|
||||
context()->Plug(if_true, if_false);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -3256,38 +3256,6 @@ void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
Label materialize_true, materialize_false;
|
||||
Label* if_true = NULL;
|
||||
Label* if_false = NULL;
|
||||
Label* fall_through = NULL;
|
||||
context()->PrepareTest(&materialize_true, &materialize_false,
|
||||
&if_true, &if_false, &fall_through);
|
||||
|
||||
__ JumpIfSmi(rax, if_false);
|
||||
__ CompareRoot(rax, Heap::kNullValueRootIndex);
|
||||
__ j(equal, if_true);
|
||||
__ movp(rbx, FieldOperand(rax, HeapObject::kMapOffset));
|
||||
// Undetectable objects behave like undefined when tested with typeof.
|
||||
__ testb(FieldOperand(rbx, Map::kBitFieldOffset),
|
||||
Immediate(1 << Map::kIsUndetectable));
|
||||
__ j(not_zero, if_false);
|
||||
__ movzxbp(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
|
||||
__ cmpp(rbx, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
__ j(below, if_false);
|
||||
__ cmpp(rbx, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
|
||||
Split(below_equal, if_true, if_false, fall_through);
|
||||
|
||||
context()->Plug(if_true, if_false);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -3255,38 +3255,6 @@ void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
|
||||
Label materialize_true, materialize_false;
|
||||
Label* if_true = NULL;
|
||||
Label* if_false = NULL;
|
||||
Label* fall_through = NULL;
|
||||
context()->PrepareTest(&materialize_true, &materialize_false,
|
||||
&if_true, &if_false, &fall_through);
|
||||
|
||||
__ JumpIfSmi(eax, if_false);
|
||||
__ cmp(eax, isolate()->factory()->null_value());
|
||||
__ j(equal, if_true);
|
||||
__ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
|
||||
// Undetectable objects behave like undefined when tested with typeof.
|
||||
__ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset));
|
||||
__ test(ecx, Immediate(1 << Map::kIsUndetectable));
|
||||
__ j(not_zero, if_false);
|
||||
__ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset));
|
||||
__ cmp(ecx, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
||||
__ j(below, if_false);
|
||||
__ cmp(ecx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
||||
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
|
||||
Split(below_equal, if_true, if_false, fall_through);
|
||||
|
||||
context()->Plug(if_true, if_false);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -813,7 +813,6 @@ bool HInstruction::CanDeoptimize() {
|
||||
case HValue::kInstanceOf:
|
||||
case HValue::kIsConstructCallAndBranch:
|
||||
case HValue::kHasInPrototypeChainAndBranch:
|
||||
case HValue::kIsObjectAndBranch:
|
||||
case HValue::kIsSmiAndBranch:
|
||||
case HValue::kIsStringAndBranch:
|
||||
case HValue::kIsUndetectableAndBranch:
|
||||
@ -3273,29 +3272,6 @@ bool HCompareObjectEqAndBranch::KnownSuccessorBlock(HBasicBlock** block) {
|
||||
}
|
||||
|
||||
|
||||
bool ConstantIsObject(HConstant* constant, Isolate* isolate) {
|
||||
if (constant->HasNumberValue()) return false;
|
||||
if (constant->GetUnique().IsKnownGlobal(isolate->heap()->null_value())) {
|
||||
return true;
|
||||
}
|
||||
if (constant->IsUndetectable()) return false;
|
||||
InstanceType type = constant->GetInstanceType();
|
||||
return (FIRST_NONCALLABLE_SPEC_OBJECT_TYPE <= type) &&
|
||||
(type <= LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
||||
}
|
||||
|
||||
|
||||
bool HIsObjectAndBranch::KnownSuccessorBlock(HBasicBlock** block) {
|
||||
if (FLAG_fold_constants && value()->IsConstant()) {
|
||||
*block = ConstantIsObject(HConstant::cast(value()), isolate())
|
||||
? FirstSuccessor() : SecondSuccessor();
|
||||
return true;
|
||||
}
|
||||
*block = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool HIsStringAndBranch::KnownSuccessorBlock(HBasicBlock** block) {
|
||||
if (known_successor_index() != kNoKnownSuccessorIndex) {
|
||||
*block = SuccessorAt(known_successor_index());
|
||||
|
@ -108,7 +108,6 @@ class LChunkBuilder;
|
||||
V(InvokeFunction) \
|
||||
V(IsConstructCallAndBranch) \
|
||||
V(HasInPrototypeChainAndBranch) \
|
||||
V(IsObjectAndBranch) \
|
||||
V(IsStringAndBranch) \
|
||||
V(IsSmiAndBranch) \
|
||||
V(IsUndetectableAndBranch) \
|
||||
@ -4454,28 +4453,6 @@ class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> {
|
||||
};
|
||||
|
||||
|
||||
class HIsObjectAndBranch final : public HUnaryControlInstruction {
|
||||
public:
|
||||
DECLARE_INSTRUCTION_FACTORY_P1(HIsObjectAndBranch, HValue*);
|
||||
DECLARE_INSTRUCTION_FACTORY_P3(HIsObjectAndBranch, HValue*,
|
||||
HBasicBlock*, HBasicBlock*);
|
||||
|
||||
Representation RequiredInputRepresentation(int index) override {
|
||||
return Representation::Tagged();
|
||||
}
|
||||
|
||||
bool KnownSuccessorBlock(HBasicBlock** block) override;
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch)
|
||||
|
||||
private:
|
||||
HIsObjectAndBranch(HValue* value,
|
||||
HBasicBlock* true_target = NULL,
|
||||
HBasicBlock* false_target = NULL)
|
||||
: HUnaryControlInstruction(value, true_target, false_target) {}
|
||||
};
|
||||
|
||||
|
||||
class HIsStringAndBranch final : public HUnaryControlInstruction {
|
||||
public:
|
||||
DECLARE_INSTRUCTION_FACTORY_P1(HIsStringAndBranch, HValue*);
|
||||
|
@ -12027,15 +12027,6 @@ void HOptimizedGraphBuilder::GenerateIsRegExp(CallRuntime* call) {
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::GenerateIsObject(CallRuntime* call) {
|
||||
DCHECK(call->arguments()->length() == 1);
|
||||
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
||||
HValue* value = Pop();
|
||||
HIsObjectAndBranch* result = New<HIsObjectAndBranch>(value);
|
||||
return ast_context()->ReturnControl(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::GenerateToObject(CallRuntime* call) {
|
||||
DCHECK_EQ(1, call->arguments()->length());
|
||||
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
||||
|
@ -2196,7 +2196,6 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
F(OneByteSeqStringSetChar) \
|
||||
F(TwoByteSeqStringSetChar) \
|
||||
F(ObjectEquals) \
|
||||
F(IsObject) \
|
||||
F(ToObject) \
|
||||
F(IsFunction) \
|
||||
F(IsSpecObject) \
|
||||
|
@ -2364,40 +2364,6 @@ void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
|
||||
}
|
||||
|
||||
|
||||
Condition LCodeGen::EmitIsObject(Register input,
|
||||
Register temp1,
|
||||
Label* is_not_object,
|
||||
Label* is_object) {
|
||||
__ JumpIfSmi(input, is_not_object);
|
||||
|
||||
__ cmp(input, isolate()->factory()->null_value());
|
||||
__ j(equal, is_object);
|
||||
|
||||
__ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
|
||||
// Undetectable objects behave like undefined.
|
||||
__ test_b(FieldOperand(temp1, Map::kBitFieldOffset),
|
||||
1 << Map::kIsUndetectable);
|
||||
__ j(not_zero, is_not_object);
|
||||
|
||||
__ movzx_b(temp1, FieldOperand(temp1, Map::kInstanceTypeOffset));
|
||||
__ cmp(temp1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
||||
__ j(below, is_not_object);
|
||||
__ cmp(temp1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
||||
return below_equal;
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
|
||||
Register reg = ToRegister(instr->value());
|
||||
Register temp = ToRegister(instr->temp());
|
||||
|
||||
Condition true_cond = EmitIsObject(
|
||||
reg, temp, instr->FalseLabel(chunk_), instr->TrueLabel(chunk_));
|
||||
|
||||
EmitBranch(instr, true_cond);
|
||||
}
|
||||
|
||||
|
||||
Condition LCodeGen::EmitIsString(Register input,
|
||||
Register temp1,
|
||||
Label* is_not_string,
|
||||
|
@ -270,14 +270,6 @@ class LCodeGen: public LCodeGenBase {
|
||||
// true and false label should be made, to optimize fallthrough.
|
||||
Condition EmitTypeofIs(LTypeofIsAndBranch* instr, Register input);
|
||||
|
||||
// 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,
|
||||
Label* is_not_object,
|
||||
Label* is_object);
|
||||
|
||||
// Emits optimized code for %_IsString(x). Preserves input register.
|
||||
// Returns the condition on which a final split to
|
||||
// true and false label should be made, to optimize fallthrough.
|
||||
|
@ -187,13 +187,6 @@ void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
|
||||
stream->Add("if is_object(");
|
||||
value()->PrintTo(stream);
|
||||
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
|
||||
}
|
||||
|
||||
|
||||
void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
|
||||
stream->Add("if is_string(");
|
||||
value()->PrintTo(stream);
|
||||
@ -1736,13 +1729,6 @@ LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
|
||||
DCHECK(instr->value()->representation().IsSmiOrTagged());
|
||||
LOperand* temp = TempRegister();
|
||||
return new(zone()) LIsObjectAndBranch(UseRegister(instr->value()), temp);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
|
||||
DCHECK(instr->value()->representation().IsTagged());
|
||||
LOperand* temp = TempRegister();
|
||||
|
@ -95,7 +95,6 @@ class LCodeGen;
|
||||
V(Integer32ToDouble) \
|
||||
V(InvokeFunction) \
|
||||
V(IsConstructCallAndBranch) \
|
||||
V(IsObjectAndBranch) \
|
||||
V(IsStringAndBranch) \
|
||||
V(IsSmiAndBranch) \
|
||||
V(IsUndetectableAndBranch) \
|
||||
@ -992,22 +991,6 @@ class LCompareMinusZeroAndBranch final : public LControlInstruction<1, 1> {
|
||||
};
|
||||
|
||||
|
||||
class LIsObjectAndBranch final : public LControlInstruction<1, 1> {
|
||||
public:
|
||||
LIsObjectAndBranch(LOperand* value, LOperand* temp) {
|
||||
inputs_[0] = value;
|
||||
temps_[0] = temp;
|
||||
}
|
||||
|
||||
LOperand* value() { return inputs_[0]; }
|
||||
LOperand* temp() { return temps_[0]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
|
||||
|
||||
void PrintDataTo(StringStream* stream) override;
|
||||
};
|
||||
|
||||
|
||||
class LIsStringAndBranch final : public LControlInstruction<1, 1> {
|
||||
public:
|
||||
LIsStringAndBranch(LOperand* value, LOperand* temp) {
|
||||
|
@ -93,7 +93,7 @@ macro IS_NUMBER(arg) = (typeof(arg) === 'number');
|
||||
macro IS_STRING(arg) = (typeof(arg) === 'string');
|
||||
macro IS_BOOLEAN(arg) = (typeof(arg) === 'boolean');
|
||||
macro IS_SYMBOL(arg) = (typeof(arg) === 'symbol');
|
||||
macro IS_OBJECT(arg) = (%_IsObject(arg));
|
||||
macro IS_OBJECT(arg) = (typeof(arg) === 'object');
|
||||
macro IS_ARRAY(arg) = (%_IsArray(arg));
|
||||
macro IS_DATE(arg) = (%_IsDate(arg));
|
||||
macro IS_FUNCTION(arg) = (%_IsFunction(arg));
|
||||
|
@ -2384,46 +2384,6 @@ void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
|
||||
}
|
||||
|
||||
|
||||
Condition LCodeGen::EmitIsObject(Register input,
|
||||
Register temp1,
|
||||
Register temp2,
|
||||
Label* is_not_object,
|
||||
Label* is_object) {
|
||||
__ JumpIfSmi(input, is_not_object);
|
||||
|
||||
__ LoadRoot(temp2, Heap::kNullValueRootIndex);
|
||||
__ Branch(is_object, eq, input, Operand(temp2));
|
||||
|
||||
// Load map.
|
||||
__ lw(temp1, FieldMemOperand(input, HeapObject::kMapOffset));
|
||||
// Undetectable objects behave like undefined.
|
||||
__ lbu(temp2, FieldMemOperand(temp1, Map::kBitFieldOffset));
|
||||
__ And(temp2, temp2, Operand(1 << Map::kIsUndetectable));
|
||||
__ Branch(is_not_object, ne, temp2, Operand(zero_reg));
|
||||
|
||||
// Load instance type and check that it is in object type range.
|
||||
__ lbu(temp2, FieldMemOperand(temp1, Map::kInstanceTypeOffset));
|
||||
__ Branch(is_not_object,
|
||||
lt, temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
|
||||
return le;
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
|
||||
Register reg = ToRegister(instr->value());
|
||||
Register temp1 = ToRegister(instr->temp());
|
||||
Register temp2 = scratch0();
|
||||
|
||||
Condition true_cond =
|
||||
EmitIsObject(reg, temp1, temp2,
|
||||
instr->FalseLabel(chunk_), instr->TrueLabel(chunk_));
|
||||
|
||||
EmitBranch(instr, true_cond, temp2,
|
||||
Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
}
|
||||
|
||||
|
||||
Condition LCodeGen::EmitIsString(Register input,
|
||||
Register temp1,
|
||||
Label* is_not_string,
|
||||
|
@ -302,15 +302,6 @@ class LCodeGen: public LCodeGenBase {
|
||||
Register* cmp1,
|
||||
Operand* cmp2);
|
||||
|
||||
// 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);
|
||||
|
||||
// Emits optimized code for %_IsString(x). Preserves input register.
|
||||
// Returns the condition on which a final split to
|
||||
// true and false label should be made, to optimize fallthrough.
|
||||
|
@ -175,13 +175,6 @@ void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
|
||||
stream->Add("if is_object(");
|
||||
value()->PrintTo(stream);
|
||||
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
|
||||
}
|
||||
|
||||
|
||||
void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
|
||||
stream->Add("if is_string(");
|
||||
value()->PrintTo(stream);
|
||||
@ -1723,14 +1716,6 @@ LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
|
||||
DCHECK(instr->value()->representation().IsTagged());
|
||||
LOperand* temp = TempRegister();
|
||||
return new(zone()) LIsObjectAndBranch(UseRegisterAtStart(instr->value()),
|
||||
temp);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
|
||||
DCHECK(instr->value()->representation().IsTagged());
|
||||
LOperand* temp = TempRegister();
|
||||
|
@ -91,7 +91,6 @@ class LCodeGen;
|
||||
V(Integer32ToDouble) \
|
||||
V(InvokeFunction) \
|
||||
V(IsConstructCallAndBranch) \
|
||||
V(IsObjectAndBranch) \
|
||||
V(IsStringAndBranch) \
|
||||
V(IsSmiAndBranch) \
|
||||
V(IsUndetectableAndBranch) \
|
||||
@ -987,23 +986,6 @@ class LCompareMinusZeroAndBranch final : public LControlInstruction<1, 1> {
|
||||
};
|
||||
|
||||
|
||||
class LIsObjectAndBranch final : public LControlInstruction<1, 1> {
|
||||
public:
|
||||
LIsObjectAndBranch(LOperand* value, LOperand* temp) {
|
||||
inputs_[0] = value;
|
||||
temps_[0] = temp;
|
||||
}
|
||||
|
||||
LOperand* value() { return inputs_[0]; }
|
||||
LOperand* temp() { return temps_[0]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
|
||||
DECLARE_HYDROGEN_ACCESSOR(IsObjectAndBranch)
|
||||
|
||||
void PrintDataTo(StringStream* stream) override;
|
||||
};
|
||||
|
||||
|
||||
class LIsStringAndBranch final : public LControlInstruction<1, 1> {
|
||||
public:
|
||||
LIsStringAndBranch(LOperand* value, LOperand* temp) {
|
||||
|
@ -2488,46 +2488,6 @@ void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
|
||||
}
|
||||
|
||||
|
||||
Condition LCodeGen::EmitIsObject(Register input,
|
||||
Register temp1,
|
||||
Register temp2,
|
||||
Label* is_not_object,
|
||||
Label* is_object) {
|
||||
__ JumpIfSmi(input, is_not_object);
|
||||
|
||||
__ LoadRoot(temp2, Heap::kNullValueRootIndex);
|
||||
__ Branch(is_object, eq, input, Operand(temp2));
|
||||
|
||||
// Load map.
|
||||
__ ld(temp1, FieldMemOperand(input, HeapObject::kMapOffset));
|
||||
// Undetectable objects behave like undefined.
|
||||
__ lbu(temp2, FieldMemOperand(temp1, Map::kBitFieldOffset));
|
||||
__ And(temp2, temp2, Operand(1 << Map::kIsUndetectable));
|
||||
__ Branch(is_not_object, ne, temp2, Operand(zero_reg));
|
||||
|
||||
// Load instance type and check that it is in object type range.
|
||||
__ lbu(temp2, FieldMemOperand(temp1, Map::kInstanceTypeOffset));
|
||||
__ Branch(is_not_object,
|
||||
lt, temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
|
||||
return le;
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
|
||||
Register reg = ToRegister(instr->value());
|
||||
Register temp1 = ToRegister(instr->temp());
|
||||
Register temp2 = scratch0();
|
||||
|
||||
Condition true_cond =
|
||||
EmitIsObject(reg, temp1, temp2,
|
||||
instr->FalseLabel(chunk_), instr->TrueLabel(chunk_));
|
||||
|
||||
EmitBranch(instr, true_cond, temp2,
|
||||
Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
}
|
||||
|
||||
|
||||
Condition LCodeGen::EmitIsString(Register input,
|
||||
Register temp1,
|
||||
Label* is_not_string,
|
||||
|
@ -305,15 +305,6 @@ class LCodeGen: public LCodeGenBase {
|
||||
Register* cmp1,
|
||||
Operand* cmp2);
|
||||
|
||||
// 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);
|
||||
|
||||
// Emits optimized code for %_IsString(x). Preserves input register.
|
||||
// Returns the condition on which a final split to
|
||||
// true and false label should be made, to optimize fallthrough.
|
||||
|
@ -175,13 +175,6 @@ void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
|
||||
stream->Add("if is_object(");
|
||||
value()->PrintTo(stream);
|
||||
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
|
||||
}
|
||||
|
||||
|
||||
void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
|
||||
stream->Add("if is_string(");
|
||||
value()->PrintTo(stream);
|
||||
@ -1729,14 +1722,6 @@ LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
|
||||
DCHECK(instr->value()->representation().IsTagged());
|
||||
LOperand* temp = TempRegister();
|
||||
return new(zone()) LIsObjectAndBranch(UseRegisterAtStart(instr->value()),
|
||||
temp);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
|
||||
DCHECK(instr->value()->representation().IsTagged());
|
||||
LOperand* temp = TempRegister();
|
||||
|
@ -93,7 +93,6 @@ class LCodeGen;
|
||||
V(Integer32ToDouble) \
|
||||
V(InvokeFunction) \
|
||||
V(IsConstructCallAndBranch) \
|
||||
V(IsObjectAndBranch) \
|
||||
V(IsStringAndBranch) \
|
||||
V(IsSmiAndBranch) \
|
||||
V(IsUndetectableAndBranch) \
|
||||
@ -1005,23 +1004,6 @@ class LCompareMinusZeroAndBranch final : public LControlInstruction<1, 1> {
|
||||
};
|
||||
|
||||
|
||||
class LIsObjectAndBranch final : public LControlInstruction<1, 1> {
|
||||
public:
|
||||
LIsObjectAndBranch(LOperand* value, LOperand* temp) {
|
||||
inputs_[0] = value;
|
||||
temps_[0] = temp;
|
||||
}
|
||||
|
||||
LOperand* value() { return inputs_[0]; }
|
||||
LOperand* temp() { return temps_[0]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
|
||||
DECLARE_HYDROGEN_ACCESSOR(IsObjectAndBranch)
|
||||
|
||||
void PrintDataTo(StringStream* stream) override;
|
||||
};
|
||||
|
||||
|
||||
class LIsStringAndBranch final : public LControlInstruction<1, 1> {
|
||||
public:
|
||||
LIsStringAndBranch(LOperand* value, LOperand* temp) {
|
||||
|
@ -2525,42 +2525,6 @@ void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
|
||||
}
|
||||
|
||||
|
||||
Condition LCodeGen::EmitIsObject(Register input, Register temp1,
|
||||
Label* is_not_object, Label* is_object) {
|
||||
Register temp2 = scratch0();
|
||||
__ JumpIfSmi(input, is_not_object);
|
||||
|
||||
__ LoadRoot(temp2, Heap::kNullValueRootIndex);
|
||||
__ cmp(input, temp2);
|
||||
__ beq(is_object);
|
||||
|
||||
// Load map.
|
||||
__ LoadP(temp1, FieldMemOperand(input, HeapObject::kMapOffset));
|
||||
// Undetectable objects behave like undefined.
|
||||
__ lbz(temp2, FieldMemOperand(temp1, Map::kBitFieldOffset));
|
||||
__ TestBit(temp2, Map::kIsUndetectable, r0);
|
||||
__ bne(is_not_object, cr0);
|
||||
|
||||
// Load instance type and check that it is in object type range.
|
||||
__ lbz(temp2, FieldMemOperand(temp1, Map::kInstanceTypeOffset));
|
||||
__ cmpi(temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
__ blt(is_not_object);
|
||||
__ cmpi(temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
return le;
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
|
||||
Register reg = ToRegister(instr->value());
|
||||
Register temp1 = ToRegister(instr->temp());
|
||||
|
||||
Condition true_cond = EmitIsObject(reg, temp1, instr->FalseLabel(chunk_),
|
||||
instr->TrueLabel(chunk_));
|
||||
|
||||
EmitBranch(instr, true_cond);
|
||||
}
|
||||
|
||||
|
||||
Condition LCodeGen::EmitIsString(Register input, Register temp1,
|
||||
Label* is_not_string,
|
||||
SmiCheck check_needed = INLINE_SMI_CHECK) {
|
||||
|
@ -254,12 +254,6 @@ class LCodeGen : public LCodeGenBase {
|
||||
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, Label* is_not_object,
|
||||
Label* is_object);
|
||||
|
||||
// Emits optimized code for %_IsString(x). Preserves input register.
|
||||
// Returns the condition on which a final split to
|
||||
// true and false label should be made, to optimize fallthrough.
|
||||
|
@ -183,13 +183,6 @@ void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
|
||||
stream->Add("if is_object(");
|
||||
value()->PrintTo(stream);
|
||||
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
|
||||
}
|
||||
|
||||
|
||||
void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
|
||||
stream->Add("if is_string(");
|
||||
value()->PrintTo(stream);
|
||||
@ -1745,14 +1738,6 @@ LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
|
||||
DCHECK(instr->value()->representation().IsTagged());
|
||||
LOperand* value = UseRegisterAtStart(instr->value());
|
||||
LOperand* temp = TempRegister();
|
||||
return new (zone()) LIsObjectAndBranch(value, temp);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
|
||||
DCHECK(instr->value()->representation().IsTagged());
|
||||
LOperand* value = UseRegisterAtStart(instr->value());
|
||||
|
@ -91,7 +91,6 @@ class LCodeGen;
|
||||
V(Integer32ToDouble) \
|
||||
V(InvokeFunction) \
|
||||
V(IsConstructCallAndBranch) \
|
||||
V(IsObjectAndBranch) \
|
||||
V(IsStringAndBranch) \
|
||||
V(IsSmiAndBranch) \
|
||||
V(IsUndetectableAndBranch) \
|
||||
@ -973,23 +972,6 @@ class LCompareMinusZeroAndBranch final : public LControlInstruction<1, 1> {
|
||||
};
|
||||
|
||||
|
||||
class LIsObjectAndBranch final : public LControlInstruction<1, 1> {
|
||||
public:
|
||||
LIsObjectAndBranch(LOperand* value, LOperand* temp) {
|
||||
inputs_[0] = value;
|
||||
temps_[0] = temp;
|
||||
}
|
||||
|
||||
LOperand* value() { return inputs_[0]; }
|
||||
LOperand* temp() { return temps_[0]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
|
||||
DECLARE_HYDROGEN_ACCESSOR(IsObjectAndBranch)
|
||||
|
||||
void PrintDataTo(StringStream* stream) override;
|
||||
};
|
||||
|
||||
|
||||
class LIsStringAndBranch final : public LControlInstruction<1, 1> {
|
||||
public:
|
||||
LIsStringAndBranch(LOperand* value, LOperand* temp) {
|
||||
|
@ -1363,21 +1363,6 @@ RUNTIME_FUNCTION(Runtime_ObjectEquals) {
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_IsObject) {
|
||||
SealHandleScope shs(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_CHECKED(Object, obj, 0);
|
||||
if (!obj->IsHeapObject()) return isolate->heap()->false_value();
|
||||
if (obj->IsNull()) return isolate->heap()->true_value();
|
||||
if (obj->IsUndetectableObject()) return isolate->heap()->false_value();
|
||||
Map* map = HeapObject::cast(obj)->map();
|
||||
bool is_non_callable_spec_object =
|
||||
map->instance_type() >= FIRST_NONCALLABLE_SPEC_OBJECT_TYPE &&
|
||||
map->instance_type() <= LAST_NONCALLABLE_SPEC_OBJECT_TYPE;
|
||||
return isolate->heap()->ToBoolean(is_non_callable_spec_object);
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_IsSpecObject) {
|
||||
SealHandleScope shs(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
|
@ -486,7 +486,6 @@ namespace internal {
|
||||
F(HeapObjectGetMap, 1, 1) \
|
||||
F(MapGetInstanceType, 1, 1) \
|
||||
F(ObjectEquals, 2, 1) \
|
||||
F(IsObject, 1, 1) \
|
||||
F(IsSpecObject, 1, 1) \
|
||||
F(IsStrong, 1, 1) \
|
||||
F(ClassOf, 1, 1) \
|
||||
|
@ -2427,41 +2427,6 @@ void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
|
||||
}
|
||||
|
||||
|
||||
Condition LCodeGen::EmitIsObject(Register input,
|
||||
Label* is_not_object,
|
||||
Label* is_object) {
|
||||
DCHECK(!input.is(kScratchRegister));
|
||||
|
||||
__ JumpIfSmi(input, is_not_object);
|
||||
|
||||
__ CompareRoot(input, Heap::kNullValueRootIndex);
|
||||
__ j(equal, is_object);
|
||||
|
||||
__ movp(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset));
|
||||
// Undetectable objects behave like undefined.
|
||||
__ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset),
|
||||
Immediate(1 << Map::kIsUndetectable));
|
||||
__ j(not_zero, is_not_object);
|
||||
|
||||
__ movzxbl(kScratchRegister,
|
||||
FieldOperand(kScratchRegister, Map::kInstanceTypeOffset));
|
||||
__ cmpb(kScratchRegister, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
__ j(below, is_not_object);
|
||||
__ cmpb(kScratchRegister, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
|
||||
return below_equal;
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
|
||||
Register reg = ToRegister(instr->value());
|
||||
|
||||
Condition true_cond = EmitIsObject(
|
||||
reg, instr->FalseLabel(chunk_), instr->TrueLabel(chunk_));
|
||||
|
||||
EmitBranch(instr, true_cond);
|
||||
}
|
||||
|
||||
|
||||
Condition LCodeGen::EmitIsString(Register input,
|
||||
Register temp1,
|
||||
Label* is_not_string,
|
||||
|
@ -265,13 +265,6 @@ class LCodeGen: public LCodeGenBase {
|
||||
// true and false label should be made, to optimize fallthrough.
|
||||
Condition EmitTypeofIs(LTypeofIsAndBranch* instr, Register input);
|
||||
|
||||
// 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,
|
||||
Label* is_not_object,
|
||||
Label* is_object);
|
||||
|
||||
// Emits optimized code for %_IsString(x). Preserves input register.
|
||||
// Returns the condition on which a final split to
|
||||
// true and false label should be made, to optimize fallthrough.
|
||||
|
@ -181,13 +181,6 @@ void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
|
||||
stream->Add("if is_object(");
|
||||
value()->PrintTo(stream);
|
||||
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
|
||||
}
|
||||
|
||||
|
||||
void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
|
||||
stream->Add("if is_string(");
|
||||
value()->PrintTo(stream);
|
||||
@ -1726,12 +1719,6 @@ LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
|
||||
DCHECK(instr->value()->representation().IsTagged());
|
||||
return new(zone()) LIsObjectAndBranch(UseRegisterAtStart(instr->value()));
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
|
||||
DCHECK(instr->value()->representation().IsTagged());
|
||||
LOperand* value = UseRegisterAtStart(instr->value());
|
||||
|
@ -91,7 +91,6 @@ class LCodeGen;
|
||||
V(Integer32ToDouble) \
|
||||
V(InvokeFunction) \
|
||||
V(IsConstructCallAndBranch) \
|
||||
V(IsObjectAndBranch) \
|
||||
V(IsStringAndBranch) \
|
||||
V(IsSmiAndBranch) \
|
||||
V(IsUndetectableAndBranch) \
|
||||
@ -983,21 +982,6 @@ class LCompareMinusZeroAndBranch final : public LControlInstruction<1, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LIsObjectAndBranch final : public LControlInstruction<1, 0> {
|
||||
public:
|
||||
explicit LIsObjectAndBranch(LOperand* value) {
|
||||
inputs_[0] = value;
|
||||
}
|
||||
|
||||
LOperand* value() { return inputs_[0]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
|
||||
DECLARE_HYDROGEN_ACCESSOR(IsObjectAndBranch)
|
||||
|
||||
void PrintDataTo(StringStream* stream) override;
|
||||
};
|
||||
|
||||
|
||||
class LIsStringAndBranch final : public LControlInstruction<1, 1> {
|
||||
public:
|
||||
explicit LIsStringAndBranch(LOperand* value, LOperand* temp) {
|
||||
|
@ -2645,40 +2645,6 @@ void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
|
||||
}
|
||||
|
||||
|
||||
Condition LCodeGen::EmitIsObject(Register input,
|
||||
Register temp1,
|
||||
Label* is_not_object,
|
||||
Label* is_object) {
|
||||
__ JumpIfSmi(input, is_not_object);
|
||||
|
||||
__ cmp(input, isolate()->factory()->null_value());
|
||||
__ j(equal, is_object);
|
||||
|
||||
__ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
|
||||
// Undetectable objects behave like undefined.
|
||||
__ test_b(FieldOperand(temp1, Map::kBitFieldOffset),
|
||||
1 << Map::kIsUndetectable);
|
||||
__ j(not_zero, is_not_object);
|
||||
|
||||
__ movzx_b(temp1, FieldOperand(temp1, Map::kInstanceTypeOffset));
|
||||
__ cmp(temp1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
||||
__ j(below, is_not_object);
|
||||
__ cmp(temp1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
|
||||
return below_equal;
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
|
||||
Register reg = ToRegister(instr->value());
|
||||
Register temp = ToRegister(instr->temp());
|
||||
|
||||
Condition true_cond = EmitIsObject(
|
||||
reg, temp, instr->FalseLabel(chunk_), instr->TrueLabel(chunk_));
|
||||
|
||||
EmitBranch(instr, true_cond);
|
||||
}
|
||||
|
||||
|
||||
Condition LCodeGen::EmitIsString(Register input,
|
||||
Register temp1,
|
||||
Label* is_not_string,
|
||||
|
@ -298,14 +298,6 @@ class LCodeGen: public LCodeGenBase {
|
||||
// true and false label should be made, to optimize fallthrough.
|
||||
Condition EmitTypeofIs(LTypeofIsAndBranch* instr, Register input);
|
||||
|
||||
// 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,
|
||||
Label* is_not_object,
|
||||
Label* is_object);
|
||||
|
||||
// Emits optimized code for %_IsString(x). Preserves input register.
|
||||
// Returns the condition on which a final split to
|
||||
// true and false label should be made, to optimize fallthrough.
|
||||
|
@ -198,13 +198,6 @@ void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
|
||||
stream->Add("if is_object(");
|
||||
value()->PrintTo(stream);
|
||||
stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
|
||||
}
|
||||
|
||||
|
||||
void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
|
||||
stream->Add("if is_string(");
|
||||
value()->PrintTo(stream);
|
||||
@ -1741,13 +1734,6 @@ LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
|
||||
DCHECK(instr->value()->representation().IsSmiOrTagged());
|
||||
LOperand* temp = TempRegister();
|
||||
return new(zone()) LIsObjectAndBranch(UseRegister(instr->value()), temp);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
|
||||
DCHECK(instr->value()->representation().IsTagged());
|
||||
LOperand* temp = TempRegister();
|
||||
|
@ -96,7 +96,6 @@ class LCodeGen;
|
||||
V(Integer32ToDouble) \
|
||||
V(InvokeFunction) \
|
||||
V(IsConstructCallAndBranch) \
|
||||
V(IsObjectAndBranch) \
|
||||
V(IsStringAndBranch) \
|
||||
V(IsSmiAndBranch) \
|
||||
V(IsUndetectableAndBranch) \
|
||||
@ -1004,22 +1003,6 @@ class LCompareMinusZeroAndBranch final : public LControlInstruction<1, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LIsObjectAndBranch final : public LControlInstruction<1, 1> {
|
||||
public:
|
||||
LIsObjectAndBranch(LOperand* value, LOperand* temp) {
|
||||
inputs_[0] = value;
|
||||
temps_[0] = temp;
|
||||
}
|
||||
|
||||
LOperand* value() { return inputs_[0]; }
|
||||
LOperand* temp() { return temps_[0]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
|
||||
|
||||
void PrintDataTo(StringStream* stream) override;
|
||||
};
|
||||
|
||||
|
||||
class LIsStringAndBranch final : public LControlInstruction<1, 1> {
|
||||
public:
|
||||
LIsStringAndBranch(LOperand* value, LOperand* temp) {
|
||||
|
@ -140,20 +140,6 @@ TEST(IsNonNegativeSmi) {
|
||||
}
|
||||
|
||||
|
||||
TEST(IsObject) {
|
||||
FunctionTester T("(function(a) { return %_IsObject(a); })", flags);
|
||||
|
||||
T.CheckFalse(T.NewObject("(function() {})"));
|
||||
T.CheckTrue(T.NewObject("([1])"));
|
||||
T.CheckTrue(T.NewObject("({})"));
|
||||
T.CheckTrue(T.NewObject("(/x/)"));
|
||||
T.CheckFalse(T.undefined());
|
||||
T.CheckTrue(T.null());
|
||||
T.CheckFalse(T.Val("x"));
|
||||
T.CheckFalse(T.Val(1));
|
||||
}
|
||||
|
||||
|
||||
TEST(IsRegExp) {
|
||||
FunctionTester T("(function(a) { return %_IsRegExp(a); })", flags);
|
||||
|
||||
|
@ -157,7 +157,7 @@ TEST(RuntimeCallJS) {
|
||||
|
||||
TEST(RuntimeCallInline) {
|
||||
FLAG_allow_natives_syntax = true;
|
||||
FunctionTester T("(function(a) { return %_IsObject(a); })");
|
||||
FunctionTester T("(function(a) { return %_IsSpecObject(a); })");
|
||||
|
||||
T.CheckCall(T.false_value(), T.Val(23), T.undefined());
|
||||
T.CheckCall(T.false_value(), T.Val(4.2), T.undefined());
|
||||
|
@ -12,12 +12,7 @@ function test() {
|
||||
assertEquals("function", typeof function() {});
|
||||
assertEquals("object", typeof null);
|
||||
assertEquals("object", typeof {});
|
||||
|
||||
assertTrue(%_IsObject({}));
|
||||
assertTrue(%_IsObject(null));
|
||||
assertTrue(%_IsObject(/regex/));
|
||||
assertFalse(%_IsObject(0));
|
||||
assertFalse(%_IsObject(""));
|
||||
assertEquals("object", typeof /regex/);
|
||||
|
||||
assertTrue(%_IsSmi(1));
|
||||
assertFalse(%_IsSmi(1.1));
|
||||
|
Loading…
Reference in New Issue
Block a user