Allow smis for singleton types
authorrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 6 Jun 2013 15:40:28 +0000 (15:40 +0000)
committerrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 6 Jun 2013 15:40:28 +0000 (15:40 +0000)
To that end, introduce a generic Box struct.

R=danno@chromium.org
BUG=

Review URL: https://codereview.chromium.org/16562003

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

12 files changed:
include/v8.h
src/factory.cc
src/factory.h
src/heap.cc
src/heap.h
src/objects-debug.cc
src/objects-inl.h
src/objects-printer.cc
src/objects.h
src/types.cc
src/types.h
test/cctest/test-types.cc

index 4bb5705..b270e76 100644 (file)
@@ -5293,10 +5293,10 @@ class Internals {
   static const int kNodeIsIndependentShift = 4;
   static const int kNodeIsPartiallyDependentShift = 5;
 
-  static const int kJSObjectType = 0xae;
+  static const int kJSObjectType = 0xaf;
   static const int kFirstNonstringType = 0x80;
   static const int kOddballType = 0x83;
-  static const int kForeignType = 0x86;
+  static const int kForeignType = 0x87;
 
   static const int kUndefinedOddballKind = 5;
   static const int kNullOddballKind = 3;
index f963334..c47b57d 100644 (file)
@@ -41,6 +41,14 @@ namespace v8 {
 namespace internal {
 
 
+Handle<Box> Factory::NewBox(Handle<Object> value, PretenureFlag pretenure) {
+  CALL_HEAP_FUNCTION(
+      isolate(),
+      isolate()->heap()->AllocateBox(*value, pretenure),
+      Box);
+}
+
+
 Handle<FixedArray> Factory::NewFixedArray(int size, PretenureFlag pretenure) {
   ASSERT(0 <= size);
   CALL_HEAP_FUNCTION(
index 66304a9..d59d742 100644 (file)
@@ -39,6 +39,11 @@ namespace internal {
 
 class Factory {
  public:
+  // Allocate a new boxed value.
+  Handle<Box> NewBox(
+      Handle<Object> value,
+      PretenureFlag pretenure = NOT_TENURED);
+
   // Allocate a new uninitialized fixed array.
   Handle<FixedArray> NewFixedArray(
       int size,
index 15b1479..7e1688b 100644 (file)
@@ -2701,6 +2701,15 @@ MaybeObject* Heap::AllocateJSGlobalPropertyCell(Object* value) {
 }
 
 
+MaybeObject* Heap::AllocateBox(Object* value, PretenureFlag pretenure) {
+  Box* result;
+  MaybeObject* maybe_result = AllocateStruct(BOX_TYPE);
+  if (!maybe_result->To(&result)) return maybe_result;
+  result->set_value(value);
+  return result;
+}
+
+
 MaybeObject* Heap::CreateOddball(const char* to_string,
                                  Object* to_number,
                                  byte kind) {
index 7d204af..d3daaf7 100644 (file)
@@ -939,6 +939,10 @@ class Heap {
   // Please note this does not perform a garbage collection.
   MUST_USE_RESULT MaybeObject* AllocateJSGlobalPropertyCell(Object* value);
 
+  // Allocate Box.
+  MUST_USE_RESULT MaybeObject* AllocateBox(Object* value,
+                                           PretenureFlag pretenure);
+
   // Allocates a fixed array initialized with undefined values
   // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
   // failed.
index 1d55e26..4008181 100644 (file)
@@ -778,6 +778,12 @@ void Foreign::ForeignVerify() {
 }
 
 
+void Box::BoxVerify() {
+  CHECK(IsBox());
+  value()->Verify();
+}
+
+
 void AccessorInfo::AccessorInfoVerify() {
   VerifyPointer(name());
   VerifyPointer(flag());
index 799c960..69b1ed9 100644 (file)
@@ -4383,6 +4383,8 @@ ACCESSORS(ExecutableAccessorInfo, getter, Object, kGetterOffset)
 ACCESSORS(ExecutableAccessorInfo, setter, Object, kSetterOffset)
 ACCESSORS(ExecutableAccessorInfo, data, Object, kDataOffset)
 
+ACCESSORS(Box, value, Object, kValueOffset)
+
 ACCESSORS(AccessorPair, getter, Object, kGetterOffset)
 ACCESSORS(AccessorPair, setter, Object, kSetterOffset)
 
index 8eab562..a374c37 100644 (file)
@@ -970,6 +970,13 @@ void DeclaredAccessorDescriptor::DeclaredAccessorDescriptorPrint(FILE* out) {
 }
 
 
+void Box::BoxPrint(FILE* out) {
+  HeapObject::PrintHeader(out, "Box");
+  PrintF(out, "\n - value: ");
+  value()->ShortPrint(out);
+}
+
+
 void AccessorPair::AccessorPairPrint(FILE* out) {
   HeapObject::PrintHeader(out, "AccessorPair");
   PrintF(out, "\n - getter: ");
index 8038709..ec78d02 100644 (file)
 //       - Foreign
 //       - SharedFunctionInfo
 //       - Struct
+//         - Box
 //         - DeclaredAccessorDescriptor
 //         - AccessorInfo
 //           - DeclaredAccessorInfo
@@ -348,6 +349,7 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits;
   V(CODE_TYPE)                                                                 \
   V(ODDBALL_TYPE)                                                              \
   V(JS_GLOBAL_PROPERTY_CELL_TYPE)                                              \
+  V(BOX_TYPE)                                                                  \
                                                                                \
   V(HEAP_NUMBER_TYPE)                                                          \
   V(FOREIGN_TYPE)                                                              \
@@ -526,6 +528,7 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits;
 // type tags, elements in this list have to be added to the INSTANCE_TYPE_LIST
 // manually.
 #define STRUCT_LIST_ALL(V)                                                     \
+  V(BOX, Box, box)                                                             \
   V(DECLARED_ACCESSOR_DESCRIPTOR,                                              \
     DeclaredAccessorDescriptor,                                                \
     declared_accessor_descriptor)                                              \
@@ -667,6 +670,7 @@ enum InstanceType {
   CODE_TYPE,
   ODDBALL_TYPE,
   JS_GLOBAL_PROPERTY_CELL_TYPE,
+  BOX_TYPE,
 
   // "Data", objects that cannot contain non-map-word pointers to heap
   // objects.
@@ -5685,6 +5689,26 @@ class Struct: public HeapObject {
 };
 
 
+// A simple one-element struct, useful where smis need to be boxed.
+class Box : public Struct {
+ public:
+  // [value]: the boxed contents.
+  DECL_ACCESSORS(value, Object)
+
+  static inline Box* cast(Object* obj);
+
+  // Dispatched behavior.
+  DECLARE_PRINTER(Box)
+  DECLARE_VERIFIER(Box)
+
+  static const int kValueOffset = HeapObject::kHeaderSize;
+  static const int kSize = kValueOffset + kPointerSize;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Box);
+};
+
+
 // Script describes a script which has been added to the VM.
 class Script: public Struct {
  public:
index 2a96055..f7fbd2d 100644 (file)
@@ -42,8 +42,14 @@ int Type::LubBitset() {
     }
     return bitset;
   } else {
-    Map* map =
-        this->is_class() ? *this->as_class() : this->as_constant()->map();
+    Map* map = NULL;
+    if (this->is_class()) {
+      map = *this->as_class();
+    } else {
+      v8::internal::Object* value = this->as_constant()->value();
+      if (value->IsSmi()) return kSmi;
+      map = HeapObject::cast(value)->map();
+    }
     switch (map->instance_type()) {
       case STRING_TYPE:
       case ASCII_STRING_TYPE:
@@ -126,7 +132,8 @@ bool Type::Is(Handle<Type> that) {
     return this->is_class() && *this->as_class() == *that->as_class();
   }
   if (that->is_constant()) {
-    return this->is_constant() && *this->as_constant() == *that->as_constant();
+    return this->is_constant() &&
+        this->as_constant()->value() == that->as_constant()->value();
   }
 
   // (T1 \/ ... \/ Tn) <= T  <=>  (T1 <= T) /\ ... /\ (Tn <= T)
@@ -169,7 +176,8 @@ bool Type::Maybe(Handle<Type> that) {
     return that->is_class() && *this->as_class() == *that->as_class();
   }
   if (this->is_constant()) {
-    return that->is_constant() && *this->as_constant() == *that->as_constant();
+    return that->is_constant() &&
+        this->as_constant()->value() == that->as_constant()->value();
   }
 
   // (T1 \/ ... \/ Tn) overlaps T <=> (T1 overlaps T) \/ ... \/ (Tn overlaps T)
index 018969f..6db9bfb 100644 (file)
@@ -79,8 +79,8 @@ namespace internal {
 // existing assumptions or tests.
 //
 // Internally, all 'primitive' types, and their unions, are represented as
-// bitsets via smis. Class and Constant are heap pointers to the respective
-// argument. Only unions containing Class'es or Constant's require allocation.
+// bitsets via smis. Class is a heap pointer to the respective map. Only
+// Constant's, or unions containing Class'es or Constant's, require allocation.
 //
 // The type representation is heap-allocated, so cannot (currently) be used in
 // a parallel compilation context.
@@ -113,8 +113,10 @@ class Type : public Object {
 
   static Type* Class(Handle<Map> map) { return from_handle(map); }
   static Type* Constant(Handle<HeapObject> value) {
-    ASSERT(!value->IsMap() && !value->IsFixedArray());
-    return from_handle(value);
+    return Constant(value, value->GetIsolate());
+  }
+  static Type* Constant(Handle<v8::internal::Object> value, Isolate* isolate) {
+    return from_handle(isolate->factory()->NewBox(value));
   }
 
   static Type* Union(Handle<Type> type1, Handle<Type> type2);
@@ -159,15 +161,12 @@ class Type : public Object {
 
   bool is_bitset() { return this->IsSmi(); }
   bool is_class() { return this->IsMap(); }
-  bool is_constant() { return !(is_bitset() || is_class() || is_union()); }
+  bool is_constant() { return this->IsBox(); }
   bool is_union() { return this->IsFixedArray(); }
 
   int as_bitset() { return Smi::cast(this)->value(); }
   Handle<Map> as_class() { return Handle<Map>::cast(handle()); }
-  Handle<HeapObject> as_constant() {
-    ASSERT(is_constant());
-    return Handle<HeapObject>::cast(handle());
-  }
+  Handle<Box> as_constant() { return Handle<Box>::cast(handle()); }
   Handle<Unioned> as_union() { return Handle<Unioned>::cast(handle()); }
 
   Handle<Type> handle() { return handle_via_isolate_of(this); }
index d5852e0..3cdfdad 100644 (file)
@@ -33,14 +33,12 @@ using namespace v8::internal;
 // Testing auxiliaries (breaking the Type abstraction).
 static bool IsBitset(Type* type) { return type->IsSmi(); }
 static bool IsClass(Type* type) { return type->IsMap(); }
+static bool IsConstant(Type* type) { return type->IsBox(); }
 static bool IsUnion(Type* type) { return type->IsFixedArray(); }
-static bool IsConstant(Type* type) {
-  return !(IsBitset(type) || IsClass(type) || IsUnion(type));
-}
 
 static int AsBitset(Type* type) { return Smi::cast(type)->value(); }
 static Map* AsClass(Type* type) { return Map::cast(type); }
-static HeapObject* AsConstant(Type* type) { return HeapObject::cast(type); }
+static Object* AsConstant(Type* type) { return Box::cast(type)->value(); }
 static FixedArray* AsUnion(Type* type) { return FixedArray::cast(type); }
 
 class HandlifiedTypes {
@@ -68,11 +66,13 @@ class HandlifiedTypes {
       object_map(isolate->factory()->NewMap(JS_OBJECT_TYPE, 3 * kPointerSize)),
       array_map(isolate->factory()->NewMap(JS_ARRAY_TYPE, 4 * kPointerSize)),
       isolate_(isolate) {
+    smi = handle(Smi::FromInt(666), isolate);
     object1 = isolate->factory()->NewJSObjectFromMap(object_map);
     object2 = isolate->factory()->NewJSObjectFromMap(object_map);
     array = isolate->factory()->NewJSArray(20);
     ObjectClass = handle(Type::Class(object_map), isolate);
     ArrayClass = handle(Type::Class(array_map), isolate);
+    SmiConstant = handle(Type::Constant(smi, isolate), isolate);
     ObjectConstant1 = handle(Type::Constant(object1), isolate);
     ObjectConstant2 = handle(Type::Constant(object2), isolate);
     ArrayConstant = handle(Type::Constant(array), isolate);
@@ -100,6 +100,8 @@ class HandlifiedTypes {
 
   Handle<Type> ObjectClass;
   Handle<Type> ArrayClass;
+
+  Handle<Type> SmiConstant;
   Handle<Type> ObjectConstant1;
   Handle<Type> ObjectConstant2;
   Handle<Type> ArrayConstant;
@@ -107,6 +109,7 @@ class HandlifiedTypes {
   Handle<Map> object_map;
   Handle<Map> array_map;
 
+  Handle<v8::internal::Smi> smi;
   Handle<JSObject> object1;
   Handle<JSObject> object2;
   Handle<JSArray> array;
@@ -165,10 +168,12 @@ TEST(Constant) {
   HandleScope scope(isolate);
   HandlifiedTypes T(isolate);
 
+  CHECK(IsConstant(*T.SmiConstant));
   CHECK(IsConstant(*T.ObjectConstant1));
   CHECK(IsConstant(*T.ObjectConstant2));
   CHECK(IsConstant(*T.ArrayConstant));
 
+  CHECK(*T.smi == AsConstant(*T.SmiConstant));
   CHECK(*T.object1 == AsConstant(*T.ObjectConstant1));
   CHECK(*T.object2 == AsConstant(*T.ObjectConstant2));
   CHECK(*T.object1 != AsConstant(*T.ObjectConstant2));
@@ -250,6 +255,8 @@ TEST(Is) {
   CheckSub(T.ArrayClass, T.Object);
   CheckUnordered(T.ObjectClass, T.ArrayClass);
 
+  CheckSub(T.SmiConstant, T.Smi);
+  CheckSub(T.SmiConstant, T.Number);
   CheckSub(T.ObjectConstant1, T.Object);
   CheckSub(T.ObjectConstant2, T.Object);
   CheckSub(T.ArrayConstant, T.Object);
@@ -333,6 +340,9 @@ TEST(Maybe) {
   CheckOverlap(T.ArrayClass, T.ArrayClass);
   CheckDisjoint(T.ObjectClass, T.ArrayClass);
 
+  CheckOverlap(T.SmiConstant, T.Smi);
+  CheckOverlap(T.SmiConstant, T.Number);
+  CheckDisjoint(T.SmiConstant, T.Double);
   CheckOverlap(T.ObjectConstant1, T.Object);
   CheckOverlap(T.ObjectConstant2, T.Object);
   CheckOverlap(T.ArrayConstant, T.Object);
@@ -422,9 +432,11 @@ TEST(Union) {
   CheckDisjoint(T.Union(T.ObjectClass, T.String), T.Number);
 
   // Bitset-constant
+  CHECK(IsBitset(Type::Union(T.SmiConstant, T.Number)));
   CHECK(IsBitset(Type::Union(T.ObjectConstant1, T.Object)));
   CHECK(IsUnion(Type::Union(T.ObjectConstant2, T.Number)));
 
+  CheckEqual(T.Union(T.SmiConstant, T.Number), T.Number);
   CheckEqual(T.Union(T.ObjectConstant1, T.Object), T.Object);
   CheckSub(T.Union(T.ObjectConstant1, T.Number), T.Any);
   CheckSub(T.Union(T.ObjectConstant1, T.Smi), T.Union(T.Object, T.Number));