From 372457a79301b11a26d4d2bb3a07a2aa47e685ed Mon Sep 17 00:00:00 2001 From: "rossberg@chromium.org" Date: Thu, 6 Jun 2013 15:40:28 +0000 Subject: [PATCH] Allow smis for singleton types 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 --- include/v8.h | 4 ++-- src/factory.cc | 8 ++++++++ src/factory.h | 5 +++++ src/heap.cc | 9 +++++++++ src/heap.h | 4 ++++ src/objects-debug.cc | 6 ++++++ src/objects-inl.h | 2 ++ src/objects-printer.cc | 7 +++++++ src/objects.h | 24 ++++++++++++++++++++++++ src/types.cc | 16 ++++++++++++---- src/types.h | 17 ++++++++--------- test/cctest/test-types.cc | 20 ++++++++++++++++---- 12 files changed, 103 insertions(+), 19 deletions(-) diff --git a/include/v8.h b/include/v8.h index 4bb5705..b270e76 100644 --- a/include/v8.h +++ b/include/v8.h @@ -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; diff --git a/src/factory.cc b/src/factory.cc index f963334..c47b57d 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -41,6 +41,14 @@ namespace v8 { namespace internal { +Handle Factory::NewBox(Handle value, PretenureFlag pretenure) { + CALL_HEAP_FUNCTION( + isolate(), + isolate()->heap()->AllocateBox(*value, pretenure), + Box); +} + + Handle Factory::NewFixedArray(int size, PretenureFlag pretenure) { ASSERT(0 <= size); CALL_HEAP_FUNCTION( diff --git a/src/factory.h b/src/factory.h index 66304a9..d59d742 100644 --- a/src/factory.h +++ b/src/factory.h @@ -39,6 +39,11 @@ namespace internal { class Factory { public: + // Allocate a new boxed value. + Handle NewBox( + Handle value, + PretenureFlag pretenure = NOT_TENURED); + // Allocate a new uninitialized fixed array. Handle NewFixedArray( int size, diff --git a/src/heap.cc b/src/heap.cc index 15b1479..7e1688b 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -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) { diff --git a/src/heap.h b/src/heap.h index 7d204af..d3daaf7 100644 --- a/src/heap.h +++ b/src/heap.h @@ -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. diff --git a/src/objects-debug.cc b/src/objects-debug.cc index 1d55e26..4008181 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -778,6 +778,12 @@ void Foreign::ForeignVerify() { } +void Box::BoxVerify() { + CHECK(IsBox()); + value()->Verify(); +} + + void AccessorInfo::AccessorInfoVerify() { VerifyPointer(name()); VerifyPointer(flag()); diff --git a/src/objects-inl.h b/src/objects-inl.h index 799c960..69b1ed9 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -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) diff --git a/src/objects-printer.cc b/src/objects-printer.cc index 8eab562..a374c37 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -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: "); diff --git a/src/objects.h b/src/objects.h index 8038709..ec78d02 100644 --- a/src/objects.h +++ b/src/objects.h @@ -125,6 +125,7 @@ // - 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: diff --git a/src/types.cc b/src/types.cc index 2a96055..f7fbd2d 100644 --- a/src/types.cc +++ b/src/types.cc @@ -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 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 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) diff --git a/src/types.h b/src/types.h index 018969f..6db9bfb 100644 --- a/src/types.h +++ b/src/types.h @@ -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) { return from_handle(map); } static Type* Constant(Handle value) { - ASSERT(!value->IsMap() && !value->IsFixedArray()); - return from_handle(value); + return Constant(value, value->GetIsolate()); + } + static Type* Constant(Handle value, Isolate* isolate) { + return from_handle(isolate->factory()->NewBox(value)); } static Type* Union(Handle type1, Handle 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 as_class() { return Handle::cast(handle()); } - Handle as_constant() { - ASSERT(is_constant()); - return Handle::cast(handle()); - } + Handle as_constant() { return Handle::cast(handle()); } Handle as_union() { return Handle::cast(handle()); } Handle handle() { return handle_via_isolate_of(this); } diff --git a/test/cctest/test-types.cc b/test/cctest/test-types.cc index d5852e0..3cdfdad 100644 --- a/test/cctest/test-types.cc +++ b/test/cctest/test-types.cc @@ -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 ObjectClass; Handle ArrayClass; + + Handle SmiConstant; Handle ObjectConstant1; Handle ObjectConstant2; Handle ArrayConstant; @@ -107,6 +109,7 @@ class HandlifiedTypes { Handle object_map; Handle array_map; + Handle smi; Handle object1; Handle object2; Handle 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)); -- 2.7.4