Simplify and optimize ToBoolean handling.
authorsvenpanne@chromium.org <svenpanne@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 11 Aug 2011 07:22:16 +0000 (07:22 +0000)
committersvenpanne@chromium.org <svenpanne@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 11 Aug 2011 07:22:16 +0000 (07:22 +0000)
Changing our builtin JavaScript code slightly, we can make sure that we never
see internal objects as arguments for ToBoolean at runtime. Removing that case
from the stub generator and crankshaft makes things a lot easier.

Heap numbers can never be undetectable (only strings and spec objects can), so
we can leave out a useless test.

Try to re-use a non-null register value when returning 'true' in some cases.

Removed special handling of the 'handle all' case, it will very probably never
happen in real code and only makes things more complicated.

Improved naming of the ToBoolean stubs a bit, reflecting the order in which
cases are handled in the code itself.
Review URL: http://codereview.chromium.org/7497063

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

12 files changed:
src/apinatives.js
src/arm/code-stubs-arm.cc
src/arm/lithium-arm.cc
src/arm/lithium-codegen-arm.cc
src/code-stubs.cc
src/code-stubs.h
src/ia32/code-stubs-ia32.cc
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-ia32.cc
src/x64/code-stubs-x64.cc
src/x64/lithium-codegen-x64.cc
src/x64/lithium-x64.cc

index c00195d..e94da9f 100644 (file)
@@ -49,7 +49,10 @@ function Instantiate(data, name) {
       return InstantiateFunction(data, name);
     case kNewObjectTag:
       var Constructor = %GetTemplateField(data, kApiConstructorOffset);
-      var result = Constructor ? new (Instantiate(Constructor))() : {};
+      // Note: Do not directly use a function template as a condition, our
+      // internal ToBoolean doesn't handle that!
+      var result = typeof Constructor === 'undefined' ?
+          {} : new (Instantiate(Constructor))();
       ConfigureTemplateInstance(result, data);
       result = %ToFastProperties(result);
       return result;
@@ -74,13 +77,18 @@ function InstantiateFunction(data, name) {
       cache[serialNumber] = fun;
       var prototype = %GetTemplateField(data, kApiPrototypeTemplateOffset);
       var flags = %GetTemplateField(data, kApiFlagOffset);
-      fun.prototype = prototype ? Instantiate(prototype) : {};
+      // Note: Do not directly use an object template as a condition, our
+      // internal ToBoolean doesn't handle that!
+      fun.prototype = typeof prototype === 'undefined' ?
+          {} : Instantiate(prototype);
       if (flags & (1 << kReadOnlyPrototypeBit)) {
         %FunctionSetReadOnlyPrototype(fun);
       }
       %SetProperty(fun.prototype, "constructor", fun, DONT_ENUM);
       var parent = %GetTemplateField(data, kApiParentTemplateOffset);
-      if (parent) {
+      // Note: Do not directly use a function template as a condition, our
+      // internal ToBoolean doesn't handle that!
+      if (!(typeof parent === 'undefined')) {
         var parent_fun = Instantiate(parent);
         fun.prototype.__proto__ = parent_fun.prototype;
       }
index 161421e..21b05b5 100644 (file)
@@ -1613,14 +1613,14 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
   const Register map = r9.is(tos_) ? r7 : r9;
 
   // undefined -> false.
-  CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch);
+  CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
 
   // Boolean -> its value.
-  CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch);
-  CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch);
+  CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
+  CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
 
   // 'null' -> false.
-  CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch);
+  CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
 
   if (types_.Contains(SMI)) {
     // Smis: 0 -> false, all other -> true
@@ -1635,12 +1635,13 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
   if (types_.NeedsMap()) {
     __ ldr(map, FieldMemOperand(tos_, HeapObject::kMapOffset));
 
-    // Everything with a map could be undetectable, so check this now.
-    __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
-    __ tst(ip, Operand(1 << Map::kIsUndetectable));
-    // Undetectable -> false.
-    __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, ne);
-    __ Ret(ne);
+    if (types_.CanBeUndetectable()) {
+      __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
+      __ tst(ip, Operand(1 << Map::kIsUndetectable));
+      // Undetectable -> false.
+      __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, ne);
+      __ Ret(ne);
+    }
   }
 
   if (types_.Contains(SPEC_OBJECT)) {
@@ -1648,10 +1649,6 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
     __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
     // tos_ contains the correct non-zero return value already.
     __ Ret(ge);
-  } else if (types_.Contains(INTERNAL_OBJECT)) {
-    // We've seen a spec object for the first time -> patch.
-    __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
-    __ b(ge, &patch);
   }
 
   if (types_.Contains(STRING)) {
@@ -1659,10 +1656,6 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
   __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
   __ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset), lt);
   __ Ret(lt);  // the string length is OK as the return value
-  } else if (types_.Contains(INTERNAL_OBJECT)) {
-    // We've seen a string for the first time -> patch
-    __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
-    __ b(lt, &patch);
   }
 
   if (types_.Contains(HEAP_NUMBER)) {
@@ -1679,30 +1672,17 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
     __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, vs);  // for FP_NAN
     __ Ret();
     __ bind(&not_heap_number);
-  } else if (types_.Contains(INTERNAL_OBJECT)) {
-    // We've seen a heap number for the first time -> patch
-    __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
-    __ b(eq, &patch);
   }
 
-  if (types_.Contains(INTERNAL_OBJECT)) {
-    // Internal objects -> true.
-    __ mov(tos_, Operand(1, RelocInfo::NONE));
-    __ Ret();
-  }
-
-  if (!types_.IsAll()) {
-    __ bind(&patch);
-    GenerateTypeTransition(masm);
-  }
+  __ bind(&patch);
+  GenerateTypeTransition(masm);
 }
 
 
 void ToBooleanStub::CheckOddball(MacroAssembler* masm,
                                  Type type,
                                  Heap::RootListIndex value,
-                                 bool result,
-                                 Label* patch) {
+                                 bool result) {
   if (types_.Contains(type)) {
     // If we see an expected oddball, return its ToBoolean value tos_.
     __ LoadRoot(ip, value);
@@ -1713,12 +1693,6 @@ void ToBooleanStub::CheckOddball(MacroAssembler* masm,
       __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, eq);
     }
     __ Ret(eq);
-  } else if (types_.Contains(INTERNAL_OBJECT)) {
-    // If we see an unexpected oddball and handle internal objects, we must
-    // patch because the code for internal objects doesn't handle it explictly.
-    __ LoadRoot(ip, value);
-    __ cmp(tos_, ip);
-    __ b(eq, patch);
   }
 }
 
index 1eb4aff..867acdc 100644 (file)
@@ -1039,13 +1039,7 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
         : instr->SecondSuccessor();
     return new LGoto(successor->block_id());
   }
-  LInstruction* branch = new LBranch(UseRegister(v));
-  // When we handle all cases, we never deopt, so we don't need to assign the
-  // environment then. Note that we map the "empty" case to the "all" case in
-  // the code generator.
-  ToBooleanStub::Types types = instr->expected_input_types();
-  bool all_cases_handled = types.IsAll() || types.IsEmpty();
-  return all_cases_handled ? branch : AssignEnvironment(branch);
+  return AssignEnvironment(new LBranch(UseRegister(v)));
 }
 
 
index ae9046d..669d83a 100644 (file)
@@ -1583,46 +1583,18 @@ void LCodeGen::DoBranch(LBranch* instr) {
         // undefined -> false.
         __ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
         __ b(eq, false_label);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen undefined for the first time -> deopt.
-        __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
-        DeoptimizeIf(eq, instr->environment());
       }
-
       if (expected.Contains(ToBooleanStub::BOOLEAN)) {
         // Boolean -> its value.
         __ CompareRoot(reg, Heap::kTrueValueRootIndex);
         __ b(eq, true_label);
         __ CompareRoot(reg, Heap::kFalseValueRootIndex);
         __ b(eq, false_label);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen a boolean for the first time -> deopt.
-        __ CompareRoot(reg, Heap::kTrueValueRootIndex);
-        DeoptimizeIf(eq, instr->environment());
-        __ CompareRoot(reg, Heap::kFalseValueRootIndex);
-        DeoptimizeIf(eq, instr->environment());
-      }
-
-#if 0
-      if (expected.Contains(ToBooleanStub::BOOLEAN)) {
-        // false -> false.
-        __ CompareRoot(reg, Heap::kFalseValueRootIndex);
-        __ b(eq, false_label);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen a boolean for the first time -> deopt.
-        __ CompareRoot(reg, Heap::kFalseValueRootIndex);
-        DeoptimizeIf(eq, instr->environment());
       }
-#endif
-
       if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
         // 'null' -> false.
         __ CompareRoot(reg, Heap::kNullValueRootIndex);
         __ b(eq, false_label);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen null for the first time -> deopt.
-        __ CompareRoot(reg, Heap::kNullValueRootIndex);
-        DeoptimizeIf(eq, instr->environment());
       }
 
       if (expected.Contains(ToBooleanStub::SMI)) {
@@ -1639,20 +1611,19 @@ void LCodeGen::DoBranch(LBranch* instr) {
       const Register map = scratch0();
       if (expected.NeedsMap()) {
         __ ldr(map, FieldMemOperand(reg, HeapObject::kMapOffset));
-        // Everything with a map could be undetectable, so check this now.
-        __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
-        __ tst(ip, Operand(1 << Map::kIsUndetectable));
-        __ b(ne, false_label);
+
+        if (expected.CanBeUndetectable()) {
+          // Undetectable -> false.
+          __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
+          __ tst(ip, Operand(1 << Map::kIsUndetectable));
+          __ b(ne, false_label);
+        }
       }
 
       if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
         // spec object -> true.
         __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
         __ b(ge, true_label);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen a spec object for the first time -> deopt.
-        __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
-        DeoptimizeIf(ge, instr->environment());
       }
 
       if (expected.Contains(ToBooleanStub::STRING)) {
@@ -1665,10 +1636,6 @@ void LCodeGen::DoBranch(LBranch* instr) {
         __ b(ne, true_label);
         __ b(false_label);
         __ bind(&not_string);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen a string for the first time -> deopt
-        __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
-        DeoptimizeIf(lt, instr->environment());
       }
 
       if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
@@ -1683,19 +1650,10 @@ void LCodeGen::DoBranch(LBranch* instr) {
         __ b(eq, false_label);  // +0, -0 -> false.
         __ b(true_label);
         __ bind(&not_heap_number);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen a heap number for the first time -> deopt.
-        __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
-        DeoptimizeIf(eq, instr->environment());
       }
 
-      if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // internal objects -> true
-        __ b(true_label);
-      } else {
-        // We've seen something for the first time -> deopt.
-        DeoptimizeIf(al, instr->environment());
-      }
+      // We've seen something for the first time -> deopt.
+      DeoptimizeIf(al, instr->environment());
     }
   }
 }
index 0cba275..5535d17 100644 (file)
@@ -340,12 +340,11 @@ void ToBooleanStub::Types::Print(StringStream* stream) const {
   if (IsEmpty()) stream->Add("None");
   if (Contains(UNDEFINED)) stream->Add("Undefined");
   if (Contains(BOOLEAN)) stream->Add("Bool");
-  if (Contains(SMI)) stream->Add("Smi");
   if (Contains(NULL_TYPE)) stream->Add("Null");
+  if (Contains(SMI)) stream->Add("Smi");
   if (Contains(SPEC_OBJECT)) stream->Add("SpecObject");
   if (Contains(STRING)) stream->Add("String");
   if (Contains(HEAP_NUMBER)) stream->Add("HeapNumber");
-  if (Contains(INTERNAL_OBJECT)) stream->Add("InternalObject");
 }
 
 
@@ -385,12 +384,14 @@ bool ToBooleanStub::Types::Record(Handle<Object> object) {
     return !object->IsUndetectableObject() &&
         String::cast(*object)->length() != 0;
   } else if (object->IsHeapNumber()) {
+    ASSERT(!object->IsUndetectableObject());
     Add(HEAP_NUMBER);
     double value = HeapNumber::cast(*object)->value();
-    return !object->IsUndetectableObject() && value != 0 && !isnan(value);
+    return value != 0 && !isnan(value);
   } else {
-    Add(INTERNAL_OBJECT);
-    return !object->IsUndetectableObject();
+    // We should never see an internal object at runtime here!
+    UNREACHABLE();
+    return true;
   }
 }
 
@@ -398,8 +399,13 @@ bool ToBooleanStub::Types::Record(Handle<Object> object) {
 bool ToBooleanStub::Types::NeedsMap() const {
   return Contains(ToBooleanStub::SPEC_OBJECT)
       || Contains(ToBooleanStub::STRING)
-      || Contains(ToBooleanStub::HEAP_NUMBER)
-      || Contains(ToBooleanStub::INTERNAL_OBJECT);
+      || Contains(ToBooleanStub::HEAP_NUMBER);
+}
+
+
+bool ToBooleanStub::Types::CanBeUndetectable() const {
+  return Contains(ToBooleanStub::SPEC_OBJECT)
+      || Contains(ToBooleanStub::STRING);
 }
 
 
index 43b958b..89e99a8 100644 (file)
@@ -908,7 +908,6 @@ class ToBooleanStub: public CodeStub {
     SPEC_OBJECT,
     STRING,
     HEAP_NUMBER,
-    INTERNAL_OBJECT,
     NUMBER_OF_TYPES
   };
 
@@ -922,7 +921,6 @@ class ToBooleanStub: public CodeStub {
     explicit Types(byte bits) : set_(bits) {}
 
     bool IsEmpty() const { return set_.IsEmpty(); }
-    bool IsAll() const { return ToByte() == ((1 << NUMBER_OF_TYPES) - 1); }
     bool Contains(Type type) const { return set_.Contains(type); }
     void Add(Type type) { set_.Add(type); }
     byte ToByte() const { return set_.ToIntegral(); }
@@ -930,6 +928,7 @@ class ToBooleanStub: public CodeStub {
     void TraceTransition(Types to) const;
     bool Record(Handle<Object> object);
     bool NeedsMap() const;
+    bool CanBeUndetectable() const;
 
    private:
     EnumSet<Type, byte> set_;
@@ -956,8 +955,7 @@ class ToBooleanStub: public CodeStub {
   void CheckOddball(MacroAssembler* masm,
                     Type type,
                     Heap::RootListIndex value,
-                    bool result,
-                    Label* patch);
+                    bool result);
   void GenerateTypeTransition(MacroAssembler* masm);
 
   Register tos_;
index ed7e56c..e39d114 100644 (file)
@@ -249,20 +249,20 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
   }
 
   // undefined -> false
-  CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch);
+  CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
 
   // Boolean -> its value
-  CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch);
-  CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch);
+  CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
+  CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
 
   // 'null' -> false.
-  CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch);
+  CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
 
   if (types_.Contains(SMI)) {
     // Smis: 0 -> false, all other -> true
     Label not_smi;
     __ JumpIfNotSmi(argument, &not_smi, Label::kNear);
-    // argument contains the correct return value already
+    // argument contains the correct return value already.
     if (!tos_.is(argument)) {
       __ mov(tos_, argument);
     }
@@ -276,15 +276,16 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
   if (types_.NeedsMap()) {
     __ mov(map, FieldOperand(argument, HeapObject::kMapOffset));
 
-    // Everything with a map could be undetectable, so check this now.
-    __ test_b(FieldOperand(map, Map::kBitFieldOffset),
-              1 << Map::kIsUndetectable);
-    // Undetectable -> false.
-    Label not_undetectable;
-    __ j(zero, &not_undetectable, Label::kNear);
-    __ Set(tos_, Immediate(0));
-    __ ret(1 * kPointerSize);
-    __ bind(&not_undetectable);
+    if (types_.CanBeUndetectable()) {
+      __ test_b(FieldOperand(map, Map::kBitFieldOffset),
+                1 << Map::kIsUndetectable);
+      // Undetectable -> false.
+      Label not_undetectable;
+      __ j(zero, &not_undetectable, Label::kNear);
+      __ Set(tos_, Immediate(0));
+      __ ret(1 * kPointerSize);
+      __ bind(&not_undetectable);
+    }
   }
 
   if (types_.Contains(SPEC_OBJECT)) {
@@ -292,13 +293,12 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
     Label not_js_object;
     __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
     __ j(below, &not_js_object, Label::kNear);
-    __ Set(tos_, Immediate(1));
+    // argument contains the correct return value already.
+    if (!tos_.is(argument)) {
+      __ Set(tos_, Immediate(1));
+    }
     __ ret(1 * kPointerSize);
     __ bind(&not_js_object);
-  } else if (types_.Contains(INTERNAL_OBJECT)) {
-    // We've seen a spec object for the first time -> patch.
-    __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
-    __ j(above_equal, &patch, Label::kNear);
   }
 
   if (types_.Contains(STRING)) {
@@ -309,10 +309,6 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
     __ mov(tos_, FieldOperand(argument, String::kLengthOffset));
     __ ret(1 * kPointerSize);  // the string length is OK as the return value
     __ bind(&not_string);
-  } else if (types_.Contains(INTERNAL_OBJECT)) {
-    // We've seen a string for the first time -> patch
-    __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
-    __ j(below, &patch, Label::kNear);
   }
 
   if (types_.Contains(HEAP_NUMBER)) {
@@ -324,50 +320,42 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
     __ fld_d(FieldOperand(argument, HeapNumber::kValueOffset));
     __ FCmp();
     __ j(zero, &false_result, Label::kNear);
-    __ Set(tos_, Immediate(1));
+    // argument contains the correct return value already.
+    if (!tos_.is(argument)) {
+      __ Set(tos_, Immediate(1));
+    }
     __ ret(1 * kPointerSize);
     __ bind(&false_result);
     __ Set(tos_, Immediate(0));
     __ ret(1 * kPointerSize);
     __ bind(&not_heap_number);
-  } else if (types_.Contains(INTERNAL_OBJECT)) {
-    // We've seen a heap number for the first time -> patch
-    __ cmp(map, factory->heap_number_map());
-    __ j(equal, &patch, Label::kNear);
-  }
-
-  if (types_.Contains(INTERNAL_OBJECT)) {
-    // internal objects -> true
-    __ Set(tos_, Immediate(1));
-    __ ret(1 * kPointerSize);
   }
 
-  if (!types_.IsAll()) {
-    __ bind(&patch);
-    GenerateTypeTransition(masm);
-  }
+  __ bind(&patch);
+  GenerateTypeTransition(masm);
 }
 
 
 void ToBooleanStub::CheckOddball(MacroAssembler* masm,
                                  Type type,
                                  Heap::RootListIndex value,
-                                 bool result,
-                                 Label* patch) {
+                                 bool result) {
   const Register argument = eax;
   if (types_.Contains(type)) {
     // If we see an expected oddball, return its ToBoolean value tos_.
     Label different_value;
     __ CompareRoot(argument, value);
     __ j(not_equal, &different_value, Label::kNear);
-    __ Set(tos_, Immediate(result ? 1 : 0));
+    if (!result) {
+      // If we have to return zero, there is no way around clearing tos_.
+      __ Set(tos_, Immediate(0));
+    } else if (!tos_.is(argument)) {
+      // If we have to return non-zero, we can re-use the argument if it is the
+      // same register as the result, because we never see Smi-zero here.
+      __ Set(tos_, Immediate(1));
+    }
     __ ret(1 * kPointerSize);
     __ bind(&different_value);
-  } else if (types_.Contains(INTERNAL_OBJECT)) {
-    // If we see an unexpected oddball and handle internal objects, we must
-    // patch because the code for internal objects doesn't handle it explictly.
-    __ CompareRoot(argument, value);
-    __ j(equal, patch);
   }
 }
 
index 556b173..df7d489 100644 (file)
@@ -1412,40 +1412,19 @@ void LCodeGen::DoBranch(LBranch* instr) {
         // undefined -> false.
         __ cmp(reg, factory()->undefined_value());
         __ j(equal, false_label);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen undefined for the first time -> deopt.
-        __ cmp(reg, factory()->undefined_value());
-        DeoptimizeIf(equal, instr->environment());
       }
-
       if (expected.Contains(ToBooleanStub::BOOLEAN)) {
         // true -> true.
         __ cmp(reg, factory()->true_value());
         __ j(equal, true_label);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen a boolean for the first time -> deopt.
-        __ cmp(reg, factory()->true_value());
-        DeoptimizeIf(equal, instr->environment());
-      }
-
-      if (expected.Contains(ToBooleanStub::BOOLEAN)) {
         // false -> false.
         __ cmp(reg, factory()->false_value());
         __ j(equal, false_label);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen a boolean for the first time -> deopt.
-        __ cmp(reg, factory()->false_value());
-        DeoptimizeIf(equal, instr->environment());
       }
-
       if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
         // 'null' -> false.
         __ cmp(reg, factory()->null_value());
         __ j(equal, false_label);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen null for the first time -> deopt.
-        __ cmp(reg, factory()->null_value());
-        DeoptimizeIf(equal, instr->environment());
       }
 
       if (expected.Contains(ToBooleanStub::SMI)) {
@@ -1459,26 +1438,24 @@ void LCodeGen::DoBranch(LBranch* instr) {
         DeoptimizeIf(zero, instr->environment());
       }
 
-      Register map = no_reg;
+      Register map = no_reg;  // Keep the compiler happy.
       if (expected.NeedsMap()) {
         map = ToRegister(instr->TempAt(0));
         ASSERT(!map.is(reg));
         __ mov(map, FieldOperand(reg, HeapObject::kMapOffset));
-        // Everything with a map could be undetectable, so check this now.
-        __ test_b(FieldOperand(map, Map::kBitFieldOffset),
-                  1 << Map::kIsUndetectable);
-        // Undetectable -> false.
-        __ j(not_zero, false_label);
+
+        if (expected.CanBeUndetectable()) {
+          // Undetectable -> false.
+          __ test_b(FieldOperand(map, Map::kBitFieldOffset),
+                    1 << Map::kIsUndetectable);
+          __ j(not_zero, false_label);
+        }
       }
 
       if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
         // spec object -> true.
         __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
         __ j(above_equal, true_label);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen a spec object for the first time -> deopt.
-        __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
-        DeoptimizeIf(above_equal, instr->environment());
       }
 
       if (expected.Contains(ToBooleanStub::STRING)) {
@@ -1490,10 +1467,6 @@ void LCodeGen::DoBranch(LBranch* instr) {
         __ j(not_zero, true_label);
         __ jmp(false_label);
         __ bind(&not_string);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen a string for the first time -> deopt
-        __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
-        DeoptimizeIf(below, instr->environment());
       }
 
       if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
@@ -1508,20 +1481,10 @@ void LCodeGen::DoBranch(LBranch* instr) {
         __ j(zero, false_label);
         __ jmp(true_label);
         __ bind(&not_heap_number);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen a heap number for the first time -> deopt.
-        __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
-               factory()->heap_number_map());
-        DeoptimizeIf(equal, instr->environment());
       }
 
-      if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // internal objects -> true
-        __ jmp(true_label);
-      } else {
-        // We've seen something for the first time -> deopt.
-        DeoptimizeIf(no_condition, instr->environment());
-      }
+      // We've seen something for the first time -> deopt.
+      DeoptimizeIf(no_condition, instr->environment());
     }
   }
 }
index 07867c7..884c87d 100644 (file)
@@ -1047,10 +1047,7 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
   // involving maps).
   bool needs_temp = expected.NeedsMap() || expected.IsEmpty();
   LOperand* temp = needs_temp ? TempRegister() : NULL;
-  LInstruction* branch = new LBranch(UseRegister(v), temp);
-  // When we handle all cases, we never deopt, so we don't need to assign the
-  // environment then.
-  return expected.IsAll() ? branch : AssignEnvironment(branch);
+  return AssignEnvironment(new LBranch(UseRegister(v), temp));
 }
 
 
index 56fbf9a..94ed0cb 100644 (file)
@@ -242,14 +242,14 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
   }
 
   // undefined -> false
-  CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch);
+  CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false);
 
   // Boolean -> its value
-  CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch);
-  CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch);
+  CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false);
+  CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true);
 
   // 'null' -> false.
-  CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch);
+  CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false);
 
   if (types_.Contains(SMI)) {
     // Smis: 0 -> false, all other -> true
@@ -269,15 +269,16 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
   if (types_.NeedsMap()) {
     __ movq(map, FieldOperand(argument, HeapObject::kMapOffset));
 
-    // Everything with a map could be undetectable, so check this now.
-    __ testb(FieldOperand(map, Map::kBitFieldOffset),
-             Immediate(1 << Map::kIsUndetectable));
-    // Undetectable -> false.
-    Label not_undetectable;
-    __ j(zero, &not_undetectable, Label::kNear);
-    __ Set(tos_, 0);
-    __ ret(1 * kPointerSize);
-    __ bind(&not_undetectable);
+    if (types_.CanBeUndetectable()) {
+      __ testb(FieldOperand(map, Map::kBitFieldOffset),
+               Immediate(1 << Map::kIsUndetectable));
+      // Undetectable -> false.
+      Label not_undetectable;
+      __ j(zero, &not_undetectable, Label::kNear);
+      __ Set(tos_, 0);
+      __ ret(1 * kPointerSize);
+      __ bind(&not_undetectable);
+    }
   }
 
   if (types_.Contains(SPEC_OBJECT)) {
@@ -285,13 +286,12 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
     Label not_js_object;
     __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
     __ j(below, &not_js_object, Label::kNear);
-    __ Set(tos_, 1);
+    // argument contains the correct return value already.
+    if (!tos_.is(argument)) {
+      __ Set(tos_, 1);
+    }
     __ ret(1 * kPointerSize);
     __ bind(&not_js_object);
-  } else if (types_.Contains(INTERNAL_OBJECT)) {
-    // We've seen a spec object for the first time -> patch.
-    __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
-    __ j(above_equal, &patch, Label::kNear);
   }
 
   if (types_.Contains(STRING)) {
@@ -302,10 +302,6 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
     __ movq(tos_, FieldOperand(argument, String::kLengthOffset));
     __ ret(1 * kPointerSize);  // the string length is OK as the return value
     __ bind(&not_string);
-  } else if (types_.Contains(INTERNAL_OBJECT)) {
-    // We've seen a string for the first time -> patch
-    __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
-    __ j(below, &patch, Label::kNear);
   }
 
   if (types_.Contains(HEAP_NUMBER)) {
@@ -316,50 +312,42 @@ void ToBooleanStub::Generate(MacroAssembler* masm) {
     __ xorps(xmm0, xmm0);
     __ ucomisd(xmm0, FieldOperand(argument, HeapNumber::kValueOffset));
     __ j(zero, &false_result, Label::kNear);
-    __ Set(tos_, 1);
+    // argument contains the correct return value already.
+    if (!tos_.is(argument)) {
+      __ Set(tos_, 1);
+    }
     __ ret(1 * kPointerSize);
     __ bind(&false_result);
     __ Set(tos_, 0);
     __ ret(1 * kPointerSize);
     __ bind(&not_heap_number);
-  } else if (types_.Contains(INTERNAL_OBJECT)) {
-    // We've seen a heap number for the first time -> patch
-    __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
-    __ j(equal, &patch, Label::kNear);
-  }
-
-  if (types_.Contains(INTERNAL_OBJECT)) {
-    // internal objects -> true
-    __ Set(tos_, 1);
-    __ ret(1 * kPointerSize);
   }
 
-  if (!types_.IsAll()) {
-    __ bind(&patch);
-    GenerateTypeTransition(masm);
-  }
+  __ bind(&patch);
+  GenerateTypeTransition(masm);
 }
 
 
 void ToBooleanStub::CheckOddball(MacroAssembler* masm,
                                  Type type,
                                  Heap::RootListIndex value,
-                                 bool result,
-                                 Label* patch) {
+                                 bool result) {
   const Register argument = rax;
   if (types_.Contains(type)) {
     // If we see an expected oddball, return its ToBoolean value tos_.
     Label different_value;
     __ CompareRoot(argument, value);
     __ j(not_equal, &different_value, Label::kNear);
-    __ Set(tos_, result ? 1 : 0);
+    if (!result) {
+      // If we have to return zero, there is no way around clearing tos_.
+      __ Set(tos_, 0);
+    } else if (!tos_.is(argument)) {
+      // If we have to return non-zero, we can re-use the argument if it is the
+      // same register as the result, because we never see Smi-zero here.
+      __ Set(tos_, 1);
+    }
     __ ret(1 * kPointerSize);
     __ bind(&different_value);
-  } else if (types_.Contains(INTERNAL_OBJECT)) {
-    // If we see an unexpected oddball and handle internal objects, we must
-    // patch because the code for internal objects doesn't handle it explictly.
-    __ CompareRoot(argument, value);
-    __ j(equal, patch);
   }
 }
 
index 132dd36..cdea1dc 100644 (file)
@@ -1410,40 +1410,19 @@ void LCodeGen::DoBranch(LBranch* instr) {
         // undefined -> false.
         __ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
         __ j(equal, false_label);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen undefined for the first time -> deopt.
-        __ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
-        DeoptimizeIf(equal, instr->environment());
       }
-
       if (expected.Contains(ToBooleanStub::BOOLEAN)) {
         // true -> true.
         __ CompareRoot(reg, Heap::kTrueValueRootIndex);
         __ j(equal, true_label);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen a boolean for the first time -> deopt.
-        __ CompareRoot(reg, Heap::kTrueValueRootIndex);
-        DeoptimizeIf(equal, instr->environment());
-      }
-
-      if (expected.Contains(ToBooleanStub::BOOLEAN)) {
         // false -> false.
         __ CompareRoot(reg, Heap::kFalseValueRootIndex);
         __ j(equal, false_label);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen a boolean for the first time -> deopt.
-        __ CompareRoot(reg, Heap::kFalseValueRootIndex);
-        DeoptimizeIf(equal, instr->environment());
       }
-
       if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
         // 'null' -> false.
         __ CompareRoot(reg, Heap::kNullValueRootIndex);
         __ j(equal, false_label);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen null for the first time -> deopt.
-        __ CompareRoot(reg, Heap::kNullValueRootIndex);
-        DeoptimizeIf(equal, instr->environment());
       }
 
       if (expected.Contains(ToBooleanStub::SMI)) {
@@ -1460,21 +1439,19 @@ void LCodeGen::DoBranch(LBranch* instr) {
       const Register map = kScratchRegister;
       if (expected.NeedsMap()) {
         __ movq(map, FieldOperand(reg, HeapObject::kMapOffset));
-        // Everything with a map could be undetectable, so check this now.
-        __ testb(FieldOperand(map, Map::kBitFieldOffset),
-                 Immediate(1 << Map::kIsUndetectable));
-        // Undetectable -> false.
-        __ j(not_zero, false_label);
+
+        if (expected.CanBeUndetectable()) {
+          // Undetectable -> false.
+          __ testb(FieldOperand(map, Map::kBitFieldOffset),
+                   Immediate(1 << Map::kIsUndetectable));
+          __ j(not_zero, false_label);
+        }
       }
 
       if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
         // spec object -> true.
         __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
         __ j(above_equal, true_label);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen a spec object for the first time -> deopt.
-        __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
-        DeoptimizeIf(above_equal, instr->environment());
       }
 
       if (expected.Contains(ToBooleanStub::STRING)) {
@@ -1486,10 +1463,6 @@ void LCodeGen::DoBranch(LBranch* instr) {
         __ j(not_zero, true_label);
         __ jmp(false_label);
         __ bind(&not_string);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen a string for the first time -> deopt
-        __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
-        DeoptimizeIf(below, instr->environment());
       }
 
       if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
@@ -1502,19 +1475,10 @@ void LCodeGen::DoBranch(LBranch* instr) {
         __ j(zero, false_label);
         __ jmp(true_label);
         __ bind(&not_heap_number);
-      } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // We've seen a heap number for the first time -> deopt.
-        __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
-        DeoptimizeIf(equal, instr->environment());
       }
 
-      if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
-        // internal objects -> true
-        __ jmp(true_label);
-      } else {
-        // We've seen something for the first time -> deopt.
-        DeoptimizeIf(no_condition, instr->environment());
-      }
+      // We've seen something for the first time -> deopt.
+      DeoptimizeIf(no_condition, instr->environment());
     }
   }
 }
index 7f4490f..ed83a84 100644 (file)
@@ -1036,11 +1036,7 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
         : instr->SecondSuccessor();
     return new LGoto(successor->block_id());
   }
-  LInstruction* branch = new LBranch(UseRegister(v));
-  // When we handle all cases, we never deopt, so we don't need to assign the
-  // environment then.
-  bool all_cases_handled = instr->expected_input_types().IsAll();
-  return all_cases_handled ? branch : AssignEnvironment(branch);
+  return AssignEnvironment(new LBranch(UseRegister(v)));
 }