Revision: 8716
Author:   [email protected]
Date:     Thu Jul 21 06:51:04 2011
Log:      Implement a type recording ToBoolean IC.

The IC records the set of types it has seen, e.g. {String} or {Boolean,
Undefined}, etc.  Note that in theory this could lead to a large number of
different ToBoolean ICs (512, to be exact, because we distinguish 9 types),
but in practice only a small handful of them are actually generated.

Currently the type recording part is only implemented on ia32, other platforms
continue to work like they did before, though.

Removed some dead code on the way.
Review URL: http://codereview.chromium.org/7473028
http://code.google.com/p/v8/source/detail?r=8716

Modified:
 /branches/bleeding_edge/src/code-stubs.cc
 /branches/bleeding_edge/src/code-stubs.h
 /branches/bleeding_edge/src/debug.cc
 /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
 /branches/bleeding_edge/src/ic.cc
 /branches/bleeding_edge/src/ic.h
 /branches/bleeding_edge/src/log.cc
 /branches/bleeding_edge/src/objects-inl.h
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/spaces.cc

=======================================
--- /branches/bleeding_edge/src/code-stubs.cc   Wed Jul 13 06:50:27 2011
+++ /branches/bleeding_edge/src/code-stubs.cc   Thu Jul 21 06:51:04 2011
@@ -328,5 +328,74 @@
   }
stream->Add("CallFunctionStub_Args%d%s%s", argc_, in_loop_name, flags_name);
 }
+
+
+void ToBooleanStub::PrintName(StringStream* stream) {
+  stream->Add("ToBooleanStub_");
+  types_.Print(stream);
+}
+
+
+void ToBooleanStub::Types::Print(StringStream* stream) {
+  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(UNDETECTABLE)) stream->Add("Undetectable");
+  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");
+}
+
+
+void ToBooleanStub::Types::TraceTransition(Types to) {
+  if (!FLAG_trace_ic) return;
+  char buffer[100];
+  NoAllocationStringAllocator allocator(buffer,
+ static_cast<unsigned>(sizeof(buffer)));
+  StringStream stream(&allocator);
+  stream.Add("[ToBooleanIC (");
+  Print(&stream);
+  stream.Add("->");
+  to.Print(&stream);
+  stream.Add(")]\n");
+  stream.OutputToStdOut();
+}
+
+
+bool ToBooleanStub::Types::Record(Handle<Object> object) {
+  if (object->IsUndefined()) {
+    Add(UNDEFINED);
+    return false;
+  } else if (object->IsBoolean()) {
+    Add(BOOLEAN);
+    return object->IsTrue();
+  } else if (object->IsNull()) {
+    Add(NULL_TYPE);
+    return false;
+  } else if (object->IsSmi()) {
+    Add(SMI);
+    return Smi::cast(*object)->value() != 0;
+  } else if (object->IsUndetectableObject()) {
+    Add(UNDETECTABLE);
+    return false;
+  } else if (object->IsSpecObject()) {
+    Add(SPEC_OBJECT);
+    return true;
+  } else if (object->IsString()) {
+    Add(STRING);
+    return String::cast(*object)->length() != 0;
+  } else if (object->IsHeapNumber()) {
+    Add(HEAP_NUMBER);
+    double value = HeapNumber::cast(*object)->value();
+    return value != 0 && !isnan(value);
+  } else {
+    Add(INTERNAL_OBJECT);
+    return true;
+  }
+}
+

 } }  // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/code-stubs.h    Wed Jul 13 04:08:25 2011
+++ /branches/bleeding_edge/src/code-stubs.h    Thu Jul 21 06:51:04 2011
@@ -900,14 +900,56 @@

 class ToBooleanStub: public CodeStub {
  public:
-  explicit ToBooleanStub(Register tos) : tos_(tos) { }
+  enum Type {
+    UNDEFINED,
+    BOOLEAN,
+    NULL_TYPE,
+    SMI,
+    UNDETECTABLE,
+    SPEC_OBJECT,
+    STRING,
+    HEAP_NUMBER,
+    INTERNAL_OBJECT,
+    NUMBER_OF_TYPES
+  };
+
+  class Types {
+   public:
+    Types() {}
+    explicit Types(int bits) : set_(bits) {}
+
+    bool IsEmpty() const { return set_.IsEmpty(); }
+    bool Contains(Type type) const { return set_.Contains(type); }
+    void Add(Type type) { set_.Add(type); }
+    int ToInt() const { return set_.ToIntegral(); }
+    void Print(StringStream* stream);
+    void TraceTransition(Types to);
+    bool Record(Handle<Object> object);
+
+   private:
+    EnumSet<Type> set_;
+  };
+
+  explicit ToBooleanStub(Register tos, Types types = Types())
+      : tos_(tos), types_(types) { }

   void Generate(MacroAssembler* masm);
+  virtual int GetCodeKind() { return Code::TO_BOOLEAN_IC; }
+  virtual void PrintName(StringStream* stream);

  private:
-  Register tos_;
   Major MajorKey() { return ToBoolean; }
-  int MinorKey() { return tos_.code(); }
+ int MinorKey() { return (tos_.code() << NUMBER_OF_TYPES) | types_.ToInt(); }
+
+  void CheckOddball(MacroAssembler* masm,
+                    Type type,
+                    Handle<Object> value,
+                    bool result,
+                    Label* patch);
+  void GenerateTypeTransition(MacroAssembler* masm);
+
+  Register tos_;
+  Types types_;
 };

 } }  // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/debug.cc        Wed Jul 20 01:09:58 2011
+++ /branches/bleeding_edge/src/debug.cc        Thu Jul 21 06:51:04 2011
@@ -169,7 +169,8 @@
       if ((code->is_inline_cache_stub() &&
            !code->is_binary_op_stub() &&
            !code->is_unary_op_stub() &&
-           !code->is_compare_ic_stub()) ||
+           !code->is_compare_ic_stub() &&
+           !code->is_to_boolean_ic_stub()) ||
           RelocInfo::IsConstructCall(rmode())) {
         break_point_++;
         return;
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Tue Jul 19 01:19:31 2011 +++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Thu Jul 21 06:51:04 2011
@@ -236,69 +236,163 @@
 }


-// The stub returns zero for false, and a non-zero value for true.
+// The stub expects its argument on the stack and returns its result in tos_:
+// zero for false, and a non-zero value for true.
 void ToBooleanStub::Generate(MacroAssembler* masm) {
-  Label false_result, true_result, not_string;
+  Label patch;
   Factory* factory = masm->isolate()->factory();
+  const Register argument = eax;
   const Register map = edx;

-  __ mov(eax, Operand(esp, 1 * kPointerSize));
+  if (!types_.IsEmpty()) {
+    __ mov(argument, Operand(esp, 1 * kPointerSize));
+  }

   // undefined -> false
-  __ cmp(eax, factory->undefined_value());
-  __ j(equal, &false_result);
+  CheckOddball(masm, UNDEFINED, factory->undefined_value(), false, &patch);

   // Boolean -> its value
-  __ cmp(eax, factory->false_value());
-  __ j(equal, &false_result);
-  __ cmp(eax, factory->true_value());
-  __ j(equal, &true_result);
-
-  // Smis: 0 -> false, all other -> true
-  __ test(eax, Operand(eax));
-  __ j(zero, &false_result);
-  __ JumpIfSmi(eax, &true_result);
+  CheckOddball(masm, BOOLEAN, factory->false_value(), false, &patch);
+  CheckOddball(masm, BOOLEAN, factory->true_value(), true, &patch);

   // 'null' -> false.
-  __ cmp(eax, factory->null_value());
-  __ j(equal, &false_result, Label::kNear);
-
-  // Get the map of the heap object.
-  __ mov(map, FieldOperand(eax, HeapObject::kMapOffset));
-
-  // Undetectable -> false.
-  __ test_b(FieldOperand(map, Map::kBitFieldOffset),
-            1 << Map::kIsUndetectable);
-  __ j(not_zero, &false_result, Label::kNear);
-
-  // JavaScript object -> true.
-  __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
-  __ j(above_equal, &true_result, Label::kNear);
-
-  // String value -> false iff empty.
-  __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
-  __ j(above_equal, &not_string, Label::kNear);
-  __ cmp(FieldOperand(eax, String::kLengthOffset), Immediate(0));
-  __ j(zero, &false_result, Label::kNear);
-  __ jmp(&true_result, Label::kNear);
-
-  __ bind(&not_string);
-  // HeapNumber -> false iff +0, -0, or NaN.
-  __ cmp(map, factory->heap_number_map());
-  __ j(not_equal, &true_result, Label::kNear);
-  __ fldz();
-  __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
-  __ FCmp();
-  __ j(zero, &false_result, Label::kNear);
-  // Fall through to |true_result|.
-
-  // Return 1/0 for true/false in tos_.
-  __ bind(&true_result);
-  __ mov(tos_, 1);
-  __ ret(1 * kPointerSize);
-  __ bind(&false_result);
-  __ mov(tos_, 0);
-  __ ret(1 * kPointerSize);
+  CheckOddball(masm, NULL_TYPE, factory->null_value(), false, &patch);
+
+  bool need_map =
+      types_.Contains(UNDETECTABLE) |
+      types_.Contains(SPEC_OBJECT) |
+      types_.Contains(STRING) |
+      types_.Contains(HEAP_NUMBER) |
+      types_.Contains(INTERNAL_OBJECT);
+
+  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
+    if (!tos_.is(argument)) {
+      __ mov(tos_, argument);
+    }
+    __ ret(1 * kPointerSize);
+    __ bind(&not_smi);
+  } else if (need_map) {
+    // If we need a map later and have a Smi -> patch.
+    __ JumpIfSmi(argument, &patch, Label::kNear);
+  }
+
+  if (need_map) {
+    __ 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);
+    if (types_.Contains(UNDETECTABLE)) {
+      // Undetectable -> false.
+      Label not_undetectable;
+      __ j(zero, &not_undetectable, Label::kNear);
+      __ Set(tos_, Immediate(0));
+      __ ret(1 * kPointerSize);
+      __ bind(&not_undetectable);
+    } else {
+      // We've seen an undetectable value for the first time -> patch.
+      __ j(not_zero, &patch, Label::kNear);
+    }
+  }
+
+  if (types_.Contains(SPEC_OBJECT)) {
+    // spec object -> true.
+    Label not_js_object;
+    __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
+    __ j(below, &not_js_object, Label::kNear);
+    __ 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)) {
+    // String value -> false iff empty.
+    Label not_string;
+    __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
+    __ j(above_equal, &not_string, Label::kNear);
+    __ 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)) {
+    // heap number -> false iff +0, -0, or NaN.
+    Label not_heap_number, false_result;
+    __ cmp(map, factory->heap_number_map());
+    __ j(not_equal, &not_heap_number, Label::kNear);
+    __ fldz();
+    __ fld_d(FieldOperand(argument, HeapNumber::kValueOffset));
+    __ FCmp();
+    __ j(zero, &false_result, Label::kNear);
+    __ 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);
+  }
+
+  __ bind(&patch);
+  GenerateTypeTransition(masm);
+}
+
+
+void ToBooleanStub::CheckOddball(MacroAssembler* masm,
+                                 Type type,
+                                 Handle<Object> value,
+                                 bool result,
+                                 Label* patch) {
+  const Register argument = eax;
+  if (types_.Contains(type)) {
+    // If we see an expected oddball, return its ToBoolean value tos_.
+    Label different_value;
+    __ cmp(argument, value);
+    __ j(not_equal, &different_value, Label::kNear);
+    __ Set(tos_, Immediate(result ? 1 : 0));
+    __ 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.
+    __ cmp(argument, value);
+    __ j(equal, patch);
+  }
+}
+
+
+void ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) {
+  __ pop(ecx);  // Get return address, operand is now on top of stack.
+  __ push(Immediate(Smi::FromInt(tos_.code())));
+  __ push(Immediate(Smi::FromInt(types_.ToInt())));
+  __ push(ecx);  // Push return address.
+  // Patch the caller to an appropriate specialized stub and return the
+  // operation result to the caller of the stub.
+  __ TailCallExternalReference(
+      ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()),
+      3,
+      1);
 }


=======================================
--- /branches/bleeding_edge/src/ic.cc   Fri Jul  8 03:46:10 2011
+++ /branches/bleeding_edge/src/ic.cc   Thu Jul 21 06:51:04 2011
@@ -309,6 +309,7 @@
     case Code::UNARY_OP_IC:
     case Code::BINARY_OP_IC:
     case Code::COMPARE_IC:
+    case Code::TO_BOOLEAN_IC:
       // Clearing these is tricky and does not
       // make any performance difference.
       return;
@@ -840,14 +841,6 @@

   return TypeError("property_not_function", object, key);
 }
-
-
-#ifdef DEBUG
-#define TRACE_IC_NAMED(msg, name) \
-  if (FLAG_trace_ic) PrintF(msg, *(name)->ToCString())
-#else
-#define TRACE_IC_NAMED(msg, name)
-#endif


 MaybeObject* LoadIC::Load(State state,
@@ -2504,6 +2497,31 @@
   ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
   return ic.target();
 }
+
+
+RUNTIME_FUNCTION(MaybeObject*, ToBoolean_Patch) {
+  ASSERT(args.length() == 3);
+
+  HandleScope scope(isolate);
+  Handle<Object> object = args.at<Object>(0);
+  Register tos = Register::from_code(args.smi_at(1));
+  ToBooleanStub::Types old_types(args.smi_at(2));
+
+  ToBooleanStub::Types new_types(old_types);
+  bool to_boolean_value = new_types.Record(object);
+  old_types.TraceTransition(new_types);
+
+  ToBooleanStub stub(tos, new_types);
+  Handle<Code> code = stub.GetCode();
+  ToBooleanIC ic(isolate);
+  ic.patch(*code);
+  return Smi::FromInt(to_boolean_value ? 1 : 0);
+}
+
+
+void ToBooleanIC::patch(Code* code) {
+  set_target(code);
+}


 static const Address IC_utilities[] = {
=======================================
--- /branches/bleeding_edge/src/ic.h    Fri Jul  8 03:46:10 2011
+++ /branches/bleeding_edge/src/ic.h    Thu Jul 21 06:51:04 2011
@@ -59,7 +59,8 @@
   ICU(StoreInterceptorProperty)                       \
   ICU(UnaryOp_Patch)                                  \
   ICU(BinaryOp_Patch)                                 \
-  ICU(CompareIC_Miss)
+  ICU(CompareIC_Miss)                                 \
+  ICU(ToBoolean_Patch)
 //
 // IC is the base class for LoadIC, StoreIC, CallIC, KeyedLoadIC,
 // and KeyedStoreIC.
@@ -720,6 +721,15 @@
   Token::Value op_;
 };

+
+class ToBooleanIC: public IC {
+ public:
+  explicit ToBooleanIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { }
+
+  void patch(Code* code);
+};
+
+
 // Helper for BinaryOpIC and CompareIC.
 void PatchInlinedSmiCode(Address address);

=======================================
--- /branches/bleeding_edge/src/log.cc  Wed Jul 13 04:31:22 2011
+++ /branches/bleeding_edge/src/log.cc  Thu Jul 21 06:51:04 2011
@@ -1400,6 +1400,7 @@
       case Code::UNARY_OP_IC:   // fall through
       case Code::BINARY_OP_IC:   // fall through
       case Code::COMPARE_IC:  // fall through
+      case Code::TO_BOOLEAN_IC:  // fall through
       case Code::STUB:
         description =
             CodeStub::MajorName(CodeStub::GetMajorKey(code_object), true);
=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Wed Jul 20 02:11:38 2011
+++ /branches/bleeding_edge/src/objects-inl.h   Thu Jul 21 06:51:04 2011
@@ -156,6 +156,12 @@
   return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() < FIRST_NONSTRING_TYPE;
 }
+
+
+bool Object::IsSpecObject() {
+  return Object::IsHeapObject()
+ && HeapObject::cast(this)->map()->instance_type() >= FIRST_SPEC_OBJECT_TYPE;
+}


 bool Object::IsSymbol() {
@@ -2757,7 +2763,8 @@
   ASSERT(kind() == STUB ||
          kind() == UNARY_OP_IC ||
          kind() == BINARY_OP_IC ||
-         kind() == COMPARE_IC);
+         kind() == COMPARE_IC ||
+         kind() == TO_BOOLEAN_IC);
   return READ_BYTE_FIELD(this, kStubMajorKeyOffset);
 }

@@ -2766,7 +2773,8 @@
   ASSERT(kind() == STUB ||
          kind() == UNARY_OP_IC ||
          kind() == BINARY_OP_IC ||
-         kind() == COMPARE_IC);
+         kind() == COMPARE_IC ||
+         kind() == TO_BOOLEAN_IC);
   ASSERT(0 <= major && major < 256);
   WRITE_BYTE_FIELD(this, kStubMajorKeyOffset, major);
 }
@@ -2908,6 +2916,17 @@
 }


+byte Code::to_boolean_state() {
+  ASSERT(is_to_boolean_ic_stub());
+  return READ_BYTE_FIELD(this, kToBooleanTypeOffset);
+}
+
+
+void Code::set_to_boolean_state(byte value) {
+  ASSERT(is_to_boolean_ic_stub());
+  WRITE_BYTE_FIELD(this, kToBooleanTypeOffset, value);
+}
+
 bool Code::is_inline_cache_stub() {
   Kind kind = this->kind();
   return kind >= FIRST_IC_KIND && kind <= LAST_IC_KIND;
=======================================
--- /branches/bleeding_edge/src/objects.cc      Thu Jul 21 04:28:18 2011
+++ /branches/bleeding_edge/src/objects.cc      Thu Jul 21 06:51:04 2011
@@ -7209,6 +7209,7 @@
     case UNARY_OP_IC: return "UNARY_OP_IC";
     case BINARY_OP_IC: return "BINARY_OP_IC";
     case COMPARE_IC: return "COMPARE_IC";
+    case TO_BOOLEAN_IC: return "TO_BOOLEAN_IC";
   }
   UNREACHABLE();
   return NULL;
=======================================
--- /branches/bleeding_edge/src/objects.h       Wed Jul 20 02:11:38 2011
+++ /branches/bleeding_edge/src/objects.h       Thu Jul 21 06:51:04 2011
@@ -790,6 +790,8 @@
   STRUCT_LIST(DECLARE_STRUCT_PREDICATE)
 #undef DECLARE_STRUCT_PREDICATE

+  INLINE(bool IsSpecObject());
+
   // Oddball testing.
   INLINE(bool IsUndefined());
   INLINE(bool IsNull());
@@ -3480,13 +3482,14 @@
     UNARY_OP_IC,
     BINARY_OP_IC,
     COMPARE_IC,
+    TO_BOOLEAN_IC,
     // No more than 16 kinds. The value currently encoded in four bits in
     // Flags.

     // Pseudo-kinds.
     REGEXP = BUILTIN,
     FIRST_IC_KIND = LOAD_IC,
-    LAST_IC_KIND = COMPARE_IC
+    LAST_IC_KIND = TO_BOOLEAN_IC
   };

   enum {
@@ -3552,13 +3555,10 @@
   inline bool is_keyed_store_stub() { return kind() == KEYED_STORE_IC; }
   inline bool is_call_stub() { return kind() == CALL_IC; }
   inline bool is_keyed_call_stub() { return kind() == KEYED_CALL_IC; }
-  inline bool is_unary_op_stub() {
-    return kind() == UNARY_OP_IC;
-  }
-  inline bool is_binary_op_stub() {
-    return kind() == BINARY_OP_IC;
-  }
+  inline bool is_unary_op_stub() { return kind() == UNARY_OP_IC; }
+  inline bool is_binary_op_stub() { return kind() == BINARY_OP_IC; }
   inline bool is_compare_ic_stub() { return kind() == COMPARE_IC; }
+  inline bool is_to_boolean_ic_stub() { return kind() == TO_BOOLEAN_IC; }

   // [major_key]: For kind STUB or BINARY_OP_IC, the major key.
   inline int major_key();
@@ -3600,21 +3600,24 @@
   inline CheckType check_type();
   inline void set_check_type(CheckType value);

-  // [type-recording unary op type]: For all UNARY_OP_IC.
+  // [type-recording unary op type]: For kind UNARY_OP_IC.
   inline byte unary_op_type();
   inline void set_unary_op_type(byte value);

-  // [type-recording binary op type]: For all TYPE_RECORDING_BINARY_OP_IC.
+  // [type-recording binary op type]: For kind BINARY_OP_IC.
   inline byte binary_op_type();
   inline void set_binary_op_type(byte value);
   inline byte binary_op_result_type();
   inline void set_binary_op_result_type(byte value);

-  // [compare state]: For kind compare IC stubs, tells what state the
-  // stub is in.
+  // [compare state]: For kind COMPARE_IC, tells what state the stub is in.
   inline byte compare_state();
   inline void set_compare_state(byte value);

+ // [to_boolean_foo]: For kind TO_BOOLEAN_IC tells what state the stub is in.
+  inline byte to_boolean_state();
+  inline void set_to_boolean_state(byte value);
+
   // Get the safepoint entry for the given pc.
   SafepointEntry GetSafepointEntry(Address pc);

@@ -3756,9 +3759,10 @@
   static const int kStackSlotsOffset = kKindSpecificFlagsOffset;
   static const int kCheckTypeOffset = kKindSpecificFlagsOffset;

-  static const int kCompareStateOffset = kStubMajorKeyOffset + 1;
   static const int kUnaryOpTypeOffset = kStubMajorKeyOffset + 1;
   static const int kBinaryOpTypeOffset = kStubMajorKeyOffset + 1;
+  static const int kCompareStateOffset = kStubMajorKeyOffset + 1;
+  static const int kToBooleanTypeOffset = kStubMajorKeyOffset + 1;
static const int kHasDeoptimizationSupportOffset = kOptimizableOffset + 1;

   static const int kBinaryOpReturnTypeOffset = kBinaryOpTypeOffset + 1;
=======================================
--- /branches/bleeding_edge/src/spaces.cc       Wed Jul 20 01:06:43 2011
+++ /branches/bleeding_edge/src/spaces.cc       Thu Jul 21 06:51:04 2011
@@ -1542,6 +1542,7 @@
       CASE(UNARY_OP_IC);
       CASE(BINARY_OP_IC);
       CASE(COMPARE_IC);
+      CASE(TO_BOOLEAN_IC);
     }
   }

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to