Support %_IsUndetectableObject in crankshaft.
authorvitalyr@chromium.org <vitalyr@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 11 May 2011 11:53:43 +0000 (11:53 +0000)
committervitalyr@chromium.org <vitalyr@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 11 May 2011 11:53:43 +0000 (11:53 +0000)
Review URL: http://codereview.chromium.org/6995046

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7856 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

12 files changed:
src/arm/lithium-arm.cc
src/arm/lithium-arm.h
src/arm/lithium-codegen-arm.cc
src/hydrogen-instructions.h
src/hydrogen.cc
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-ia32.cc
src/ia32/lithium-ia32.h
src/x64/lithium-codegen-x64.cc
src/x64/lithium-x64.cc
src/x64/lithium-x64.h
test/cctest/test-api.cc

index 5e2180a1b9cf94139508590b173cf16169e59b52..c3229b88a27ca09d08af7b83b8bc90e9f405a9e6 100644 (file)
@@ -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());
index e04fdd6ad18e0d2daab4360bd7e03c1254a8fa91..6d19c6d1512a9b38642e1f703b33fadbbb37cc0d 100644 (file)
@@ -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) {
index 90f4f3d5fe3982bd4aacf5f4f7ca93b2e9eb281c..5830fa6f550878ed8972b6352fefd96d64ebb8ae 100644 (file)
@@ -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();
index 85a06fcbb7b56a87a9fec6b574ea21e98273a8f2..02830f07ffea89434ad432fef297832872f31cad 100644 (file)
@@ -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() {
index 923aaa92026d7bb27292b5383cd816b14265cff1..12629ae6fe443035987f7af5a46f63e00462b9da 100644 (file)
@@ -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());
 }
 
 
index 91634961403391fc80745b8ca284f710f8629f5a..1c802b404d498094ef8886efeb698702ec022fce 100644 (file)
@@ -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();
index 12a951bffeadbfb4f95a40365a5445b5e049080e..7233341429ede51a6d90f9e6dfe8b2544061cb60 100644 (file)
@@ -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());
index 8a93bda4e2a6743147a5efcb320b66d92dcb4f85..4ee91434c7f0f8f66ab0f9429c53d3f8a759f967 100644 (file)
@@ -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) {
index fb61a6fe5918f63457337c13310642f4340d0565..aaece75bfece549265f74d8040bfc507ba12cfa9 100644 (file)
@@ -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();
index a850ecf5fcb0e785351b5166eb638160c629e5a9..d373b0836c96136d5e19062be18899d6bef84fa1 100644 (file)
@@ -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());
index c56bbfeb3d461e2a2621e3228431a51cc4db3d9c..7ca7d6f85979d6f200e46539914e3c1560f42620 100644 (file)
@@ -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) {
index 17ba1813b42f9e9210c32cbe7ed5cf15e85ca7fb..88f8b2abcc879f7ed30043ad8e953725faab3edc 100644 (file)
@@ -3940,6 +3940,38 @@ THREADED_TEST(UndetectableString) {
 }
 
 
+TEST(UndetectableOptimized) {
+  i::FLAG_allow_natives_syntax = true;
+  v8::HandleScope scope;
+  LocalContext env;
+
+  Local<String> 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 <typename T> static void USE(T) { }