diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index 5e2180a1b9..c3229b88a2 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -237,6 +237,13 @@ void LIsSmiAndBranch::PrintDataTo(StringStream* stream) { } +void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) { + stream->Add("if is_undetectable("); + InputAt(0)->PrintTo(stream); + stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); +} + + void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if has_instance_type("); InputAt(0)->PrintTo(stream); @@ -1081,6 +1088,12 @@ LInstruction* LChunkBuilder::DoTest(HTest* instr) { ASSERT(compare->value()->representation().IsTagged()); return new LIsSmiAndBranch(Use(compare->value())); + } else if (v->IsIsUndetectable()) { + HIsUndetectable* compare = HIsUndetectable::cast(v); + ASSERT(compare->value()->representation().IsTagged()); + + return new LIsUndetectableAndBranch(UseRegisterAtStart(compare->value()), + TempRegister()); } else if (v->IsHasInstanceType()) { HHasInstanceType* compare = HHasInstanceType::cast(v); ASSERT(compare->value()->representation().IsTagged()); @@ -1531,6 +1544,14 @@ LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) { } +LInstruction* LChunkBuilder::DoIsUndetectable(HIsUndetectable* instr) { + ASSERT(instr->value()->representation().IsTagged()); + LOperand* value = UseRegisterAtStart(instr->value()); + + return DefineAsRegister(new LIsUndetectable(value)); +} + + LInstruction* LChunkBuilder::DoHasInstanceType(HHasInstanceType* instr) { ASSERT(instr->value()->representation().IsTagged()); LOperand* value = UseRegisterAtStart(instr->value()); diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h index e04fdd6ad1..6d19c6d151 100644 --- a/src/arm/lithium-arm.h +++ b/src/arm/lithium-arm.h @@ -108,12 +108,16 @@ class LCodeGen; V(InstructionGap) \ V(Integer32ToDouble) \ V(InvokeFunction) \ + V(IsConstructCall) \ + V(IsConstructCallAndBranch) \ V(IsNull) \ V(IsNullAndBranch) \ V(IsObject) \ V(IsObjectAndBranch) \ V(IsSmi) \ V(IsSmiAndBranch) \ + V(IsUndetectable) \ + V(IsUndetectableAndBranch) \ V(JSArrayLength) \ V(Label) \ V(LazyBailout) \ @@ -165,8 +169,6 @@ class LCodeGen; V(Typeof) \ V(TypeofIs) \ V(TypeofIsAndBranch) \ - V(IsConstructCall) \ - V(IsConstructCallAndBranch) \ V(UnaryMathOperation) \ V(UnknownOSRValue) \ V(ValueOf) @@ -754,6 +756,31 @@ class LIsSmiAndBranch: public LControlInstruction<1, 0> { }; +class LIsUndetectable: public LTemplateInstruction<1, 1, 0> { + public: + explicit LIsUndetectable(LOperand* value) { + inputs_[0] = value; + } + + DECLARE_CONCRETE_INSTRUCTION(IsUndetectable, "is-undetectable") + DECLARE_HYDROGEN_ACCESSOR(IsUndetectable) +}; + + +class LIsUndetectableAndBranch: public LControlInstruction<1, 1> { + public: + explicit LIsUndetectableAndBranch(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } + + DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch, + "is-undetectable-and-branch") + + virtual void PrintDataTo(StringStream* stream); +}; + + class LHasInstanceType: public LTemplateInstruction<1, 1, 0> { public: explicit LHasInstanceType(LOperand* value) { diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 90f4f3d5fe..5830fa6f55 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -1774,6 +1774,40 @@ void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { } +void LCodeGen::DoIsUndetectable(LIsUndetectable* instr) { + Register input = ToRegister(instr->InputAt(0)); + Register result = ToRegister(instr->result()); + + ASSERT(instr->hydrogen()->value()->representation().IsTagged()); + Label false_label, done; + __ JumpIfSmi(input, &false_label); + __ ldr(result, FieldMemOperand(input, HeapObject::kMapOffset)); + __ ldrb(result, FieldMemOperand(result, Map::kBitFieldOffset)); + __ tst(result, Operand(1 << Map::kIsUndetectable)); + __ b(eq, &false_label); + __ LoadRoot(result, Heap::kTrueValueRootIndex); + __ jmp(&done); + __ bind(&false_label); + __ LoadRoot(result, Heap::kFalseValueRootIndex); + __ bind(&done); +} + + +void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { + Register input = ToRegister(instr->InputAt(0)); + Register temp = ToRegister(instr->TempAt(0)); + + int true_block = chunk_->LookupDestination(instr->true_block_id()); + int false_block = chunk_->LookupDestination(instr->false_block_id()); + + __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block)); + __ ldr(temp, FieldMemOperand(input, HeapObject::kMapOffset)); + __ ldrb(temp, FieldMemOperand(temp, Map::kBitFieldOffset)); + __ tst(temp, Operand(1 << Map::kIsUndetectable)); + EmitBranch(true_block, false_block, ne); +} + + static InstanceType TestType(HHasInstanceType* instr) { InstanceType from = instr->from(); InstanceType to = instr->to(); diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 85a06fcbb7..02830f07ff 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -110,10 +110,11 @@ class LChunkBuilder; V(InstanceOf) \ V(InstanceOfKnownGlobal) \ V(InvokeFunction) \ + V(IsConstructCall) \ V(IsNull) \ V(IsObject) \ V(IsSmi) \ - V(IsConstructCall) \ + V(IsUndetectable) \ V(JSArrayLength) \ V(LeaveInlined) \ V(LoadContextSlot) \ @@ -2469,6 +2470,17 @@ class HIsSmi: public HUnaryPredicate { }; +class HIsUndetectable: public HUnaryPredicate { + public: + explicit HIsUndetectable(HValue* value) : HUnaryPredicate(value) { } + + DECLARE_CONCRETE_INSTRUCTION(IsUndetectable) + + protected: + virtual bool DataEquals(HValue* other) { return true; } +}; + + class HIsConstructCall: public HTemplateInstruction<0> { public: HIsConstructCall() { diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 923aaa9202..12629ae6fe 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -5274,7 +5274,11 @@ void HGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) { void HGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) { - return Bailout("inlined runtime function: IsUndetectableObject"); + ASSERT(call->arguments()->length() == 1); + CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); + HValue* value = Pop(); + ast_context()->ReturnInstruction(new(zone()) HIsUndetectable(value), + call->id()); } diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 9163496140..1c802b404d 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -1702,6 +1702,44 @@ void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { } +void LCodeGen::DoIsUndetectable(LIsUndetectable* instr) { + Register input = ToRegister(instr->InputAt(0)); + Register result = ToRegister(instr->result()); + + ASSERT(instr->hydrogen()->value()->representation().IsTagged()); + Label false_label, done; + STATIC_ASSERT(kSmiTag == 0); + __ test(input, Immediate(kSmiTagMask)); + __ j(zero, &false_label, Label::kNear); + __ mov(result, FieldOperand(input, HeapObject::kMapOffset)); + __ test_b(FieldOperand(result, Map::kBitFieldOffset), + 1 << Map::kIsUndetectable); + __ j(zero, &false_label, Label::kNear); + __ mov(result, factory()->true_value()); + __ jmp(&done); + __ bind(&false_label); + __ mov(result, factory()->false_value()); + __ bind(&done); +} + + +void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { + Register input = ToRegister(instr->InputAt(0)); + Register temp = ToRegister(instr->TempAt(0)); + + int true_block = chunk_->LookupDestination(instr->true_block_id()); + int false_block = chunk_->LookupDestination(instr->false_block_id()); + + STATIC_ASSERT(kSmiTag == 0); + __ test(input, Immediate(kSmiTagMask)); + __ j(zero, chunk_->GetAssemblyLabel(false_block)); + __ mov(temp, FieldOperand(input, HeapObject::kMapOffset)); + __ test_b(FieldOperand(temp, Map::kBitFieldOffset), + 1 << Map::kIsUndetectable); + EmitBranch(true_block, false_block, not_zero); +} + + static InstanceType TestType(HHasInstanceType* instr) { InstanceType from = instr->from(); InstanceType to = instr->to(); diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index 12a951bffe..7233341429 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -239,6 +239,13 @@ void LIsSmiAndBranch::PrintDataTo(StringStream* stream) { } +void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) { + stream->Add("if is_undetectable("); + InputAt(0)->PrintTo(stream); + stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); +} + + void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if has_instance_type("); InputAt(0)->PrintTo(stream); @@ -1080,6 +1087,12 @@ LInstruction* LChunkBuilder::DoTest(HTest* instr) { ASSERT(compare->value()->representation().IsTagged()); return new LIsSmiAndBranch(Use(compare->value())); + } else if (v->IsIsUndetectable()) { + HIsUndetectable* compare = HIsUndetectable::cast(v); + ASSERT(compare->value()->representation().IsTagged()); + + return new LIsUndetectableAndBranch(UseRegisterAtStart(compare->value()), + TempRegister()); } else if (v->IsHasInstanceType()) { HHasInstanceType* compare = HHasInstanceType::cast(v); ASSERT(compare->value()->representation().IsTagged()); @@ -1564,6 +1577,14 @@ LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) { } +LInstruction* LChunkBuilder::DoIsUndetectable(HIsUndetectable* instr) { + ASSERT(instr->value()->representation().IsTagged()); + LOperand* value = UseRegisterAtStart(instr->value()); + + return DefineAsRegister(new LIsUndetectable(value)); +} + + LInstruction* LChunkBuilder::DoHasInstanceType(HHasInstanceType* instr) { ASSERT(instr->value()->representation().IsTagged()); LOperand* value = UseRegisterAtStart(instr->value()); diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h index 8a93bda4e2..4ee91434c7 100644 --- a/src/ia32/lithium-ia32.h +++ b/src/ia32/lithium-ia32.h @@ -102,14 +102,16 @@ class LCodeGen; V(InstructionGap) \ V(Integer32ToDouble) \ V(InvokeFunction) \ + V(IsConstructCall) \ + V(IsConstructCallAndBranch) \ V(IsNull) \ V(IsNullAndBranch) \ V(IsObject) \ V(IsObjectAndBranch) \ V(IsSmi) \ V(IsSmiAndBranch) \ - V(IsConstructCall) \ - V(IsConstructCallAndBranch) \ + V(IsUndetectable) \ + V(IsUndetectableAndBranch) \ V(JSArrayLength) \ V(Label) \ V(LazyBailout) \ @@ -743,6 +745,31 @@ class LIsSmiAndBranch: public LControlInstruction<1, 0> { }; +class LIsUndetectable: public LTemplateInstruction<1, 1, 0> { + public: + explicit LIsUndetectable(LOperand* value) { + inputs_[0] = value; + } + + DECLARE_CONCRETE_INSTRUCTION(IsUndetectable, "is-undetectable") + DECLARE_HYDROGEN_ACCESSOR(IsUndetectable) +}; + + +class LIsUndetectableAndBranch: public LControlInstruction<1, 1> { + public: + explicit LIsUndetectableAndBranch(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } + + DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch, + "is-undetectable-and-branch") + + virtual void PrintDataTo(StringStream* stream); +}; + + class LHasInstanceType: public LTemplateInstruction<1, 1, 0> { public: explicit LHasInstanceType(LOperand* value) { diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index fb61a6fe59..aaece75bfe 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -1723,6 +1723,40 @@ void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { } +void LCodeGen::DoIsUndetectable(LIsUndetectable* instr) { + Register input = ToRegister(instr->InputAt(0)); + Register result = ToRegister(instr->result()); + + ASSERT(instr->hydrogen()->value()->representation().IsTagged()); + Label false_label, done; + __ JumpIfSmi(input, &false_label); + __ movq(result, FieldOperand(input, HeapObject::kMapOffset)); + __ testb(FieldOperand(result, Map::kBitFieldOffset), + Immediate(1 << Map::kIsUndetectable)); + __ j(zero, &false_label); + __ LoadRoot(result, Heap::kTrueValueRootIndex); + __ jmp(&done); + __ bind(&false_label); + __ LoadRoot(result, Heap::kFalseValueRootIndex); + __ bind(&done); +} + + +void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { + Register input = ToRegister(instr->InputAt(0)); + Register temp = ToRegister(instr->TempAt(0)); + + int true_block = chunk_->LookupDestination(instr->true_block_id()); + int false_block = chunk_->LookupDestination(instr->false_block_id()); + + __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block)); + __ movq(temp, FieldOperand(input, HeapObject::kMapOffset)); + __ testb(FieldOperand(temp, Map::kBitFieldOffset), + Immediate(1 << Map::kIsUndetectable)); + EmitBranch(true_block, false_block, not_zero); +} + + static InstanceType TestType(HHasInstanceType* instr) { InstanceType from = instr->from(); InstanceType to = instr->to(); diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index a850ecf5fc..d373b0836c 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -239,6 +239,13 @@ void LIsSmiAndBranch::PrintDataTo(StringStream* stream) { } +void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) { + stream->Add("if is_undetectable("); + InputAt(0)->PrintTo(stream); + stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); +} + + void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { stream->Add("if has_instance_type("); InputAt(0)->PrintTo(stream); @@ -1079,6 +1086,12 @@ LInstruction* LChunkBuilder::DoTest(HTest* instr) { ASSERT(compare->value()->representation().IsTagged()); return new LIsSmiAndBranch(Use(compare->value())); + } else if (v->IsIsUndetectable()) { + HIsUndetectable* compare = HIsUndetectable::cast(v); + ASSERT(compare->value()->representation().IsTagged()); + + return new LIsUndetectableAndBranch(UseRegisterAtStart(compare->value()), + TempRegister()); } else if (v->IsHasInstanceType()) { HHasInstanceType* compare = HHasInstanceType::cast(v); ASSERT(compare->value()->representation().IsTagged()); @@ -1538,6 +1551,14 @@ LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) { } +LInstruction* LChunkBuilder::DoIsUndetectable(HIsUndetectable* instr) { + ASSERT(instr->value()->representation().IsTagged()); + LOperand* value = UseRegisterAtStart(instr->value()); + + return DefineAsRegister(new LIsUndetectable(value)); +} + + LInstruction* LChunkBuilder::DoHasInstanceType(HHasInstanceType* instr) { ASSERT(instr->value()->representation().IsTagged()); LOperand* value = UseRegisterAtStart(instr->value()); diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h index c56bbfeb3d..7ca7d6f859 100644 --- a/src/x64/lithium-x64.h +++ b/src/x64/lithium-x64.h @@ -108,18 +108,23 @@ class LCodeGen; V(InstructionGap) \ V(Integer32ToDouble) \ V(InvokeFunction) \ + V(IsConstructCall) \ + V(IsConstructCallAndBranch) \ V(IsNull) \ V(IsNullAndBranch) \ V(IsObject) \ V(IsObjectAndBranch) \ V(IsSmi) \ V(IsSmiAndBranch) \ + V(IsUndetectable) \ + V(IsUndetectableAndBranch) \ V(JSArrayLength) \ V(Label) \ V(LazyBailout) \ V(LoadContextSlot) \ V(LoadElements) \ V(LoadExternalArrayPointer) \ + V(LoadFunctionPrototype) \ V(LoadGlobalCell) \ V(LoadGlobalGeneric) \ V(LoadKeyedFastElement) \ @@ -128,7 +133,6 @@ class LCodeGen; V(LoadNamedField) \ V(LoadNamedFieldPolymorphic) \ V(LoadNamedGeneric) \ - V(LoadFunctionPrototype) \ V(ModI) \ V(MulI) \ V(NumberTagD) \ @@ -160,13 +164,11 @@ class LCodeGen; V(StringLength) \ V(SubI) \ V(TaggedToI) \ - V(ToFastProperties) \ V(Throw) \ + V(ToFastProperties) \ V(Typeof) \ V(TypeofIs) \ V(TypeofIsAndBranch) \ - V(IsConstructCall) \ - V(IsConstructCallAndBranch) \ V(UnaryMathOperation) \ V(UnknownOSRValue) \ V(ValueOf) @@ -738,6 +740,31 @@ class LIsSmiAndBranch: public LControlInstruction<1, 0> { }; +class LIsUndetectable: public LTemplateInstruction<1, 1, 0> { + public: + explicit LIsUndetectable(LOperand* value) { + inputs_[0] = value; + } + + DECLARE_CONCRETE_INSTRUCTION(IsUndetectable, "is-undetectable") + DECLARE_HYDROGEN_ACCESSOR(IsUndetectable) +}; + + +class LIsUndetectableAndBranch: public LControlInstruction<1, 1> { + public: + explicit LIsUndetectableAndBranch(LOperand* value, LOperand* temp) { + inputs_[0] = value; + temps_[0] = temp; + } + + DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch, + "is-undetectable-and-branch") + + virtual void PrintDataTo(StringStream* stream); +}; + + class LHasInstanceType: public LTemplateInstruction<1, 1, 0> { public: explicit LHasInstanceType(LOperand* value) { diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 17ba1813b4..88f8b2abcc 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -3940,6 +3940,38 @@ THREADED_TEST(UndetectableString) { } +TEST(UndetectableOptimized) { + i::FLAG_allow_natives_syntax = true; + v8::HandleScope scope; + LocalContext env; + + Local obj = String::NewUndetectable("foo"); + env->Global()->Set(v8_str("undetectable"), obj); + env->Global()->Set(v8_str("detectable"), v8_str("bar")); + + ExpectString( + "function testBranch() {" + " if (!%_IsUndetectableObject(undetectable)) throw 1;" + " if (%_IsUndetectableObject(detectable)) throw 2;" + "}\n" + "function testBool() {" + " var b1 = !%_IsUndetectableObject(undetectable);" + " var b2 = %_IsUndetectableObject(detectable);" + " if (b1) throw 3;" + " if (b2) throw 4;" + " return b1 == b2;" + "}\n" + "%OptimizeFunctionOnNextCall(testBranch);" + "%OptimizeFunctionOnNextCall(testBool);" + "for (var i = 0; i < 10; i++) {" + " testBranch();" + " testBool();" + "}\n" + "\"PASS\"", + "PASS"); +} + + template static void USE(T) { }