[interpreter] Add constant_pool() to BytecodeArray.
authorrmcilroy <rmcilroy@chromium.org>
Thu, 27 Aug 2015 11:11:09 +0000 (04:11 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 27 Aug 2015 11:11:23 +0000 (11:11 +0000)
Adds a (currently unused) constant_pool() field to BytecodeArray objects.
This field points to a FixedArray object which will be used to hold constants.

The BytecodeArray is now a mixed values object type, with the
kConstantPoolOffset object holding a tagged pointer, but the remainder of the
object holding raw bytes (which could look like tagged pointers but are not).
Modify the BytecodeArray GC visitors to deal with this and test that the
field is migrated properly when evacuated.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#30404}

15 files changed:
src/factory.cc
src/factory.h
src/heap/heap.cc
src/heap/heap.h
src/heap/mark-compact.cc
src/heap/objects-visiting-inl.h
src/heap/objects-visiting.cc
src/heap/objects-visiting.h
src/heap/store-buffer.cc
src/interpreter/bytecode-array-builder.cc
src/objects-debug.cc
src/objects-inl.h
src/objects.cc
src/objects.h
test/cctest/test-heap.cc

index 88508614fe86c9a3e607920fe37758820524b58c..4f45be0f36253d87681c5f2274e0902bccce0929 100644 (file)
@@ -887,14 +887,13 @@ Handle<ByteArray> Factory::NewByteArray(int length, PretenureFlag pretenure) {
 }
 
 
-Handle<BytecodeArray> Factory::NewBytecodeArray(int length,
-                                                const byte* raw_bytecodes,
-                                                int frame_size,
-                                                int parameter_count) {
+Handle<BytecodeArray> Factory::NewBytecodeArray(
+    int length, const byte* raw_bytecodes, int frame_size, int parameter_count,
+    Handle<FixedArray> constant_pool) {
   DCHECK(0 <= length);
-  CALL_HEAP_FUNCTION(isolate(),
-                     isolate()->heap()->AllocateBytecodeArray(
-                         length, raw_bytecodes, frame_size, parameter_count),
+  CALL_HEAP_FUNCTION(isolate(), isolate()->heap()->AllocateBytecodeArray(
+                                    length, raw_bytecodes, frame_size,
+                                    parameter_count, *constant_pool),
                      BytecodeArray);
 }
 
index bfca11e78a826ad7aaeb3179f851361057f60837..4161f83fefdb9b10e613431bc5b4957ec54fbdff 100644 (file)
@@ -288,7 +288,8 @@ class Factory final {
                                  PretenureFlag pretenure = NOT_TENURED);
 
   Handle<BytecodeArray> NewBytecodeArray(int length, const byte* raw_bytecodes,
-                                         int frame_size, int parameter_count);
+                                         int frame_size, int parameter_count,
+                                         Handle<FixedArray> constant_pool);
 
   Handle<FixedTypedArrayBase> NewFixedTypedArrayWithExternalPointer(
       int length, ExternalArrayType array_type, void* external_pointer,
index ca50fdda2769363203fff055ac86d1ead88e0510..53f3fa21b7d0f0e273257239e4bfbd8832a2f882 100644 (file)
@@ -2924,7 +2924,8 @@ bool Heap::CreateInitialMaps() {
       set_empty_byte_array(byte_array);
 
       BytecodeArray* bytecode_array;
-      AllocationResult allocation = AllocateBytecodeArray(0, nullptr, 0, 0);
+      AllocationResult allocation =
+          AllocateBytecodeArray(0, nullptr, 0, 0, empty_fixed_array());
       if (!allocation.To(&bytecode_array)) {
         return false;
       }
@@ -3524,10 +3525,13 @@ AllocationResult Heap::AllocateByteArray(int length, PretenureFlag pretenure) {
 AllocationResult Heap::AllocateBytecodeArray(int length,
                                              const byte* const raw_bytecodes,
                                              int frame_size,
-                                             int parameter_count) {
+                                             int parameter_count,
+                                             FixedArray* constant_pool) {
   if (length < 0 || length > BytecodeArray::kMaxLength) {
     v8::internal::Heap::FatalProcessOutOfMemory("invalid array length", true);
   }
+  // Bytecode array is pretenured, so constant pool array should be to.
+  DCHECK(!InNewSpace(constant_pool));
 
   int size = BytecodeArray::SizeFor(length);
   HeapObject* result;
@@ -3541,6 +3545,7 @@ AllocationResult Heap::AllocateBytecodeArray(int length,
   instance->set_length(length);
   instance->set_frame_size(frame_size);
   instance->set_parameter_count(parameter_count);
+  instance->set_constant_pool(constant_pool);
   CopyBytes(instance->GetFirstBytecodeAddress(), raw_bytecodes, length);
 
   return result;
index ea99fd84c46fbee26e1ccb59f5422fc2fc4f09fe..8ebf21b841c71c649726d4ef144b336a38d22ed6 100644 (file)
@@ -1997,7 +1997,7 @@ class Heap {
   // Allocates a bytecode array with given contents.
   MUST_USE_RESULT AllocationResult
   AllocateBytecodeArray(int length, const byte* raw_bytecodes, int frame_size,
-                        int parameter_count);
+                        int parameter_count, FixedArray* constant_pool);
 
   // Copy the code and scope info part of the code object, but insert
   // the provided data as the relocation information.
index 738e00b09ceb6fd0a4ae804dbe3b1e27aef125c0..b5f191094c9b96f532aa3c9749eb48cf475d87d7 100644 (file)
@@ -2787,6 +2787,12 @@ void MarkCompactCollector::MigrateObjectMixed(HeapObject* dst, HeapObject* src,
     Address base_pointer_slot =
         dst->address() + FixedTypedArrayBase::kBasePointerOffset;
     RecordMigratedSlot(Memory::Object_at(base_pointer_slot), base_pointer_slot);
+  } else if (src->IsBytecodeArray()) {
+    heap()->MoveBlock(dst->address(), src->address(), size);
+    Address constant_pool_slot =
+        dst->address() + BytecodeArray::kConstantPoolOffset;
+    RecordMigratedSlot(Memory::Object_at(constant_pool_slot),
+                       constant_pool_slot);
   } else if (FLAG_unbox_double_fields) {
     Address dst_addr = dst->address();
     Address src_addr = src->address();
@@ -3210,6 +3216,9 @@ bool MarkCompactCollector::IsSlotInLiveObject(Address slot) {
         if (object->IsFixedTypedArrayBase()) {
           return static_cast<int>(slot - object->address()) ==
                  FixedTypedArrayBase::kBasePointerOffset;
+        } else if (object->IsBytecodeArray()) {
+          return static_cast<int>(slot - object->address()) ==
+                 BytecodeArray::kConstantPoolOffset;
         } else if (FLAG_unbox_double_fields) {
           // Filter out slots that happen to point to unboxed double fields.
           LayoutDescriptorHelper helper(object->map());
index 21b770d8c5a174f71b2d7fb578a29187603510b7..c250561523ce491b7584ebf6024cd312cace5b0a 100644 (file)
@@ -125,6 +125,17 @@ int StaticNewSpaceVisitor<StaticVisitor>::VisitJSDataView(Map* map,
 }
 
 
+template <typename StaticVisitor>
+int StaticNewSpaceVisitor<StaticVisitor>::VisitBytecodeArray(
+    Map* map, HeapObject* object) {
+  VisitPointers(
+      map->GetHeap(), object,
+      HeapObject::RawField(object, BytecodeArray::kConstantPoolOffset),
+      HeapObject::RawField(object, BytecodeArray::kHeaderSize));
+  return reinterpret_cast<BytecodeArray*>(object)->BytecodeArraySize();
+}
+
+
 template <typename StaticVisitor>
 void StaticMarkingVisitor<StaticVisitor>::Initialize() {
   table_.Register(kVisitShortcutCandidate,
@@ -157,7 +168,7 @@ void StaticMarkingVisitor<StaticVisitor>::Initialize() {
 
   table_.Register(kVisitByteArray, &DataObjectVisitor::Visit);
 
-  table_.Register(kVisitBytecodeArray, &DataObjectVisitor::Visit);
+  table_.Register(kVisitBytecodeArray, &VisitBytecodeArray);
 
   table_.Register(kVisitFreeSpace, &DataObjectVisitor::Visit);
 
@@ -548,6 +559,16 @@ void StaticMarkingVisitor<StaticVisitor>::VisitJSDataView(Map* map,
 }
 
 
+template <typename StaticVisitor>
+void StaticMarkingVisitor<StaticVisitor>::VisitBytecodeArray(
+    Map* map, HeapObject* object) {
+  StaticVisitor::VisitPointers(
+      map->GetHeap(), object,
+      HeapObject::RawField(object, BytecodeArray::kConstantPoolOffset),
+      HeapObject::RawField(object, BytecodeArray::kHeaderSize));
+}
+
+
 template <typename StaticVisitor>
 void StaticMarkingVisitor<StaticVisitor>::MarkMapContents(Heap* heap,
                                                           Map* map) {
index d29b99eb0572f57136486777d84167a95bfbbfae..28a68eec82e0013dd0562407df22ebdc2bbe963c 100644 (file)
@@ -269,13 +269,15 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
     case SYMBOL_TYPE:
       Symbol::BodyDescriptor::IterateBody(this, v);
       break;
+    case BYTECODE_ARRAY_TYPE:
+      reinterpret_cast<BytecodeArray*>(this)->BytecodeArrayIterateBody(v);
+      break;
 
     case HEAP_NUMBER_TYPE:
     case MUTABLE_HEAP_NUMBER_TYPE:
     case SIMD128_VALUE_TYPE:
     case FILLER_TYPE:
     case BYTE_ARRAY_TYPE:
-    case BYTECODE_ARRAY_TYPE:
     case FREE_SPACE_TYPE:
       break;
 
index 5b150cf199a561799a6f7b810d0242a4d07902e8..ff2e7df0faadb135b8b507d4d0ecb2b73faa15fb 100644 (file)
@@ -317,10 +317,6 @@ class StaticNewSpaceVisitor : public StaticVisitorBase {
     return reinterpret_cast<ByteArray*>(object)->ByteArraySize();
   }
 
-  INLINE(static int VisitBytecodeArray(Map* map, HeapObject* object)) {
-    return reinterpret_cast<BytecodeArray*>(object)->BytecodeArraySize();
-  }
-
   INLINE(static int VisitFixedDoubleArray(Map* map, HeapObject* object)) {
     int length = reinterpret_cast<FixedDoubleArray*>(object)->length();
     return FixedDoubleArray::SizeFor(length);
@@ -351,6 +347,7 @@ class StaticNewSpaceVisitor : public StaticVisitorBase {
   INLINE(static int VisitJSArrayBuffer(Map* map, HeapObject* object));
   INLINE(static int VisitJSTypedArray(Map* map, HeapObject* object));
   INLINE(static int VisitJSDataView(Map* map, HeapObject* object));
+  INLINE(static int VisitBytecodeArray(Map* map, HeapObject* object));
 
   class DataObjectVisitor {
    public:
@@ -435,6 +432,7 @@ class StaticMarkingVisitor : public StaticVisitorBase {
   INLINE(static void VisitJSTypedArray(Map* map, HeapObject* object));
   INLINE(static void VisitJSDataView(Map* map, HeapObject* object));
   INLINE(static void VisitNativeContext(Map* map, HeapObject* object));
+  INLINE(static void VisitBytecodeArray(Map* map, HeapObject* object));
 
   // Mark pointers in a Map and its TransitionArray together, possibly
   // treating transitions or back pointers weak.
index cb46edeb468ef1c605800becb1720f0d1e5a0724..8a0ee5477918a5683cc83c3dc5eab4be660acbfc 100644 (file)
@@ -494,6 +494,11 @@ void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback slot_callback) {
                         obj_address + FixedTypedArrayBase::kBasePointerOffset,
                         obj_address + FixedTypedArrayBase::kHeaderSize,
                         slot_callback);
+                  } else if (heap_object->IsBytecodeArray()) {
+                    FindPointersToNewSpaceInRegion(
+                        obj_address + BytecodeArray::kConstantPoolOffset,
+                        obj_address + BytecodeArray::kHeaderSize,
+                        slot_callback);
                   } else if (FLAG_unbox_double_fields) {
                     LayoutDescriptorHelper helper(heap_object->map());
                     DCHECK(!helper.all_fields_tagged());
index ebab9f15b14e8a5f35cd10fce8f31154d2697892..7f5799e75345b246ab64dac32eaaf389866a633e 100644 (file)
@@ -48,8 +48,10 @@ Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() {
   int bytecode_size = static_cast<int>(bytecodes_.size());
   int register_count = local_register_count_ + temporary_register_count_;
   int frame_size = register_count * kPointerSize;
-  Handle<BytecodeArray> output = isolate_->factory()->NewBytecodeArray(
-      bytecode_size, &bytecodes_.front(), frame_size, parameter_count_);
+  Factory* factory = isolate_->factory();
+  Handle<BytecodeArray> output =
+      factory->NewBytecodeArray(bytecode_size, &bytecodes_.front(), frame_size,
+                                parameter_count_, factory->empty_fixed_array());
   bytecode_generated_ = true;
   return output;
 }
index 961ad51f61bd9a05407a3b39914f15d9e8fba740..0dafe03e7a88658e5acb0698d21d15387274a221 100644 (file)
@@ -225,6 +225,8 @@ void ByteArray::ByteArrayVerify() {
 void BytecodeArray::BytecodeArrayVerify() {
   // TODO(oth): Walk bytecodes and immediate values to validate sanity.
   CHECK(IsBytecodeArray());
+  CHECK(constant_pool()->IsFixedArray());
+  VerifyHeapPointer(constant_pool());
 }
 
 
index 506e064cc6c24faa058c64b50ed8da5dc7829d53..304c6da09fb6aed02a96b7e6af881570955a07d3 100644 (file)
@@ -1477,6 +1477,8 @@ HeapObjectContents HeapObject::ContentType() {
   } else if (type == JS_FUNCTION_TYPE) {
     return HeapObjectContents::kMixedValues;
 #endif
+  } else if (type == BYTECODE_ARRAY_TYPE) {
+    return HeapObjectContents::kMixedValues;
   } else if (type >= FIRST_FIXED_TYPED_ARRAY_TYPE &&
              type <= LAST_FIXED_TYPED_ARRAY_TYPE) {
     return HeapObjectContents::kMixedValues;
@@ -4034,6 +4036,11 @@ Address ByteArray::GetDataStartAddress() {
 }
 
 
+void BytecodeArray::BytecodeArrayIterateBody(ObjectVisitor* v) {
+  IteratePointer(v, kConstantPoolOffset);
+}
+
+
 byte BytecodeArray::get(int index) {
   DCHECK(index >= 0 && index < this->length());
   return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize);
@@ -4074,6 +4081,9 @@ int BytecodeArray::parameter_count() const {
 }
 
 
+ACCESSORS(BytecodeArray, constant_pool, FixedArray, kConstantPoolOffset)
+
+
 Address BytecodeArray::GetFirstBytecodeAddress() {
   return reinterpret_cast<Address>(this) - kHeapObjectTag + kHeaderSize;
 }
index 0430f2acb053c90163b1b3ba3e5b4c12cc0d5e6d..5bc7baecddaa2a17669b0e34dfddff230fc57d13 100644 (file)
@@ -11602,6 +11602,9 @@ void BytecodeArray::Disassemble(std::ostream& os) {
     interpreter::Bytecodes::Decode(os, bytecode_start);
     os << "\n";
   }
+
+  os << "Constant pool (size = " << constant_pool()->length() << ")\n";
+  constant_pool()->Print();
 }
 
 
index f45bda2647f04a05e16979575015e891e5835bb2..202300dc4d37b1350102d0373ff2052b5537f917 100644 (file)
@@ -4120,10 +4120,14 @@ class BytecodeArray : public FixedArrayBase {
   inline int parameter_count() const;
   inline void set_parameter_count(int number_of_parameters);
 
+  // Accessors for the constant pool.
+  DECL_ACCESSORS(constant_pool, FixedArray)
+
   DECLARE_CAST(BytecodeArray)
 
   // Dispatched behavior.
   inline int BytecodeArraySize();
+  inline void BytecodeArrayIterateBody(ObjectVisitor* v);
 
   DECLARE_PRINTER(BytecodeArray)
   DECLARE_VERIFIER(BytecodeArray)
@@ -4133,7 +4137,8 @@ class BytecodeArray : public FixedArrayBase {
   // Layout description.
   static const int kFrameSizeOffset = FixedArrayBase::kHeaderSize;
   static const int kParameterSizeOffset = kFrameSizeOffset + kIntSize;
-  static const int kHeaderSize = kParameterSizeOffset + kIntSize;
+  static const int kConstantPoolOffset = kParameterSizeOffset + kIntSize;
+  static const int kHeaderSize = kConstantPoolOffset + kPointerSize;
 
   static const int kAlignedSize = OBJECT_POINTER_ALIGN(kHeaderSize);
 
index d7193dc3400105d30498669d64246049a944e6e3..9a83a82833b2567596caadd8923c22aba2a25f25 100644 (file)
@@ -713,20 +713,28 @@ TEST(BytecodeArray) {
   static const int kFrameSize = 32;
   static const int kParameterCount = 2;
 
+  i::FLAG_manual_evacuation_candidates_selection = true;
   CcTest::InitializeVM();
   Isolate* isolate = CcTest::i_isolate();
   Heap* heap = isolate->heap();
   Factory* factory = isolate->factory();
   HandleScope scope(isolate);
 
+  SimulateFullSpace(heap->old_space());
+  Handle<FixedArray> constant_pool = factory->NewFixedArray(5, TENURED);
+  for (int i = 0; i < 5; i++) {
+    constant_pool->set(i, *factory->NewHeapNumber(i));
+  }
+
   // Allocate and initialize BytecodeArray
   Handle<BytecodeArray> array = factory->NewBytecodeArray(
-      kRawBytesSize, kRawBytes, kFrameSize, kParameterCount);
+      kRawBytesSize, kRawBytes, kFrameSize, kParameterCount, constant_pool);
 
   CHECK(array->IsBytecodeArray());
   CHECK_EQ(array->length(), (int)sizeof(kRawBytes));
   CHECK_EQ(array->frame_size(), kFrameSize);
   CHECK_EQ(array->parameter_count(), kParameterCount);
+  CHECK_EQ(array->constant_pool(), *constant_pool);
   CHECK_LE(array->address(), array->GetFirstBytecodeAddress());
   CHECK_GE(array->address() + array->BytecodeArraySize(),
            array->GetFirstBytecodeAddress() + array->length());
@@ -735,17 +743,25 @@ TEST(BytecodeArray) {
     CHECK_EQ(array->get(i), kRawBytes[i]);
   }
 
-  // Full garbage collection
+  FixedArray* old_constant_pool_address = *constant_pool;
+
+  // Perform a full garbage collection and force the constant pool to be on an
+  // evacuation candidate.
+  Page* evac_page = Page::FromAddress(constant_pool->address());
+  evac_page->SetFlag(MemoryChunk::FORCE_EVACUATION_CANDIDATE_FOR_TESTING);
   heap->CollectAllGarbage();
 
-  // BytecodeArray should survive
+  // BytecodeArray should survive.
   CHECK_EQ(array->length(), kRawBytesSize);
   CHECK_EQ(array->frame_size(), kFrameSize);
-
   for (int i = 0; i < kRawBytesSize; i++) {
     CHECK_EQ(array->get(i), kRawBytes[i]);
     CHECK_EQ(array->GetFirstBytecodeAddress()[i], kRawBytes[i]);
   }
+
+  // Constant pool should have been migrated.
+  CHECK_EQ(array->constant_pool(), *constant_pool);
+  CHECK_NE(array->constant_pool(), old_constant_pool_address);
 }