Revision: 3686
Author: [email protected]
Date: Mon Jan 25 03:02:06 2010
Log: Merge r3655, r3657, and r3672 from bleeding_edge to
trunk to fix issues with the new map space compaction
code.

Merge r3680 from bleeding_edge to trunk to fix issue 589.
Review URL: http://codereview.chromium.org/548136
http://code.google.com/p/v8/source/detail?r=3686

Modified:
 /trunk/src/arm/ic-arm.cc
 /trunk/src/flag-definitions.h
 /trunk/src/heap.cc
 /trunk/src/ia32/ic-ia32.cc
 /trunk/src/ic.h
 /trunk/src/mark-compact.cc
 /trunk/src/spaces.h
 /trunk/src/version.cc
 /trunk/src/x64/ic-x64.cc
 /trunk/test/cctest/test-api.cc
 /trunk/test/cctest/test-mark-compact.cc

=======================================
--- /trunk/src/arm/ic-arm.cc    Thu Jan 14 07:28:53 2010
+++ /trunk/src/arm/ic-arm.cc    Mon Jan 25 03:02:06 2010
@@ -569,11 +569,10 @@

   // Get the map of the receiver.
   __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
-  // Check that the receiver does not require access checks.  We need
-  // to check this explicitly since this generic stub does not perform
-  // map checks.
+
+  // Check bit field.
   __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
-  __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
+  __ tst(r3, Operand(kSlowCaseBitFieldMask));
   __ b(ne, &slow);
   // Check that the object is some kind of JS object EXCEPT JS Value type.
   // In the case that the object is a value-wrapper object,
=======================================
--- /trunk/src/flag-definitions.h       Thu Jan 14 07:28:53 2010
+++ /trunk/src/flag-definitions.h       Mon Jan 25 03:02:06 2010
@@ -201,6 +201,11 @@
 DEFINE_bool(use_big_map_space, true,
             "Use big map space, but don't compact if it grew too big.")

+DEFINE_int(max_map_space_pages, MapSpace::kMaxMapPageIndex - 1,
+ "Maximum number of pages in map space which still allows to encode " + "forwarding pointers. That's actually a constant, but it's useful "
+           "to control it with a flag for better testing.")
+
 // mksnapshot.cc
 DEFINE_bool(h, false, "print this message")
 DEFINE_bool(new_snapshot, true, "use new snapshot implementation")
=======================================
--- /trunk/src/heap.cc  Thu Jan 14 07:28:53 2010
+++ /trunk/src/heap.cc  Mon Jan 25 03:02:06 2010
@@ -3544,7 +3544,8 @@
   // Initialize map space.
   map_space_ = new MapSpace(FLAG_use_big_map_space
       ? max_old_generation_size_
-      : (MapSpace::kMaxMapPageIndex + 1) * Page::kPageSize,
+      : MapSpace::kMaxMapPageIndex * Page::kPageSize,
+      FLAG_max_map_space_pages,
       MAP_SPACE);
   if (map_space_ == NULL) return false;
   if (!map_space_->Setup(NULL, 0)) return false;
=======================================
--- /trunk/src/ia32/ic-ia32.cc  Thu Jan 14 07:28:53 2010
+++ /trunk/src/ia32/ic-ia32.cc  Mon Jan 25 03:02:06 2010
@@ -244,11 +244,10 @@

   // Get the map of the receiver.
   __ mov(edx, FieldOperand(ecx, HeapObject::kMapOffset));
-  // Check that the receiver does not require access checks.  We need
-  // to check this explicitly since this generic stub does not perform
-  // map checks.
+
+  // Check bit field.
   __ movzx_b(ebx, FieldOperand(edx, Map::kBitFieldOffset));
-  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
+  __ test(ebx, Immediate(kSlowCaseBitFieldMask));
   __ j(not_zero, &slow, not_taken);
   // Check that the object is some kind of JS object EXCEPT JS Value type.
   // In the case that the object is a value-wrapper object,
=======================================
--- /trunk/src/ic.h     Thu Jan 14 07:28:53 2010
+++ /trunk/src/ic.h     Mon Jan 25 03:02:06 2010
@@ -293,6 +293,13 @@
   static void ClearInlinedVersion(Address address);

  private:
+  // Bit mask to be tested against bit field for the cases when
+  // generic stub should go into slow case.
+ // Access check is necessary explicitly since generic stub does not perform
+  // map checks.
+  static const int kSlowCaseBitFieldMask =
+ (1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor);
+
   static void Generate(MacroAssembler* masm, const ExternalReference& f);

   // Update the inline cache.
=======================================
--- /trunk/src/mark-compact.cc  Thu Jan 14 07:28:53 2010
+++ /trunk/src/mark-compact.cc  Mon Jan 25 03:02:06 2010
@@ -1291,6 +1291,8 @@
     MapIterator it;
     HeapObject* o = it.next();
     for (; o != first_map_to_evacuate_; o = it.next()) {
+      it.has_next();  // Must be called for side-effects, see bug 586.
+      ASSERT(it.has_next());
       Map* map = reinterpret_cast<Map*>(o);
       ASSERT(!map->IsMarked());
       ASSERT(!map->IsOverflowed());
@@ -1362,6 +1364,7 @@

   static Map* NextMap(MapIterator* it, HeapObject* last, bool live) {
     while (true) {
+      it->has_next();  // Must be called for side-effects, see bug 586.
       ASSERT(it->has_next());
       HeapObject* next = it->next();
       if (next == last)
=======================================
--- /trunk/src/spaces.h Thu Jan 14 07:28:53 2010
+++ /trunk/src/spaces.h Mon Jan 25 03:02:06 2010
@@ -981,6 +981,18 @@
   static Page* TopPageOf(AllocationInfo alloc_info) {
     return Page::FromAllocationTop(alloc_info.limit);
   }
+
+  int CountPagesToTop() {
+    Page* p = Page::FromAllocationTop(allocation_info_.top);
+    PageIterator it(this, PageIterator::ALL_PAGES);
+    int counter = 1;
+    while (it.has_next()) {
+      if (it.next() == p) return counter;
+      counter++;
+    }
+    UNREACHABLE();
+    return -1;
+  }

// Expands the space by allocating a fixed number of pages. Returns false if
   // it cannot allocate requested number of pages from OS. Newly allocated
@@ -1753,8 +1765,11 @@
 class MapSpace : public FixedSpace {
  public:
   // Creates a map space object with a maximum capacity.
-  MapSpace(int max_capacity, AllocationSpace id)
-      : FixedSpace(max_capacity, id, Map::kSize, "map") {}
+  MapSpace(int max_capacity, int max_map_space_pages, AllocationSpace id)
+      : FixedSpace(max_capacity, id, Map::kSize, "map"),
+        max_map_space_pages_(max_map_space_pages) {
+    ASSERT(max_map_space_pages < kMaxMapPageIndex);
+  }

   // Prepares for a mark-compact GC.
   virtual void PrepareForMarkCompact(bool will_compact);
@@ -1762,24 +1777,21 @@
   // Given an index, returns the page address.
Address PageAddress(int page_index) { return page_addresses_[page_index]; }

-  // Constants.
- static const int kMaxMapPageIndex = (1 << MapWord::kMapPageIndexBits) - 1;
+  static const int kMaxMapPageIndex = 1 << MapWord::kMapPageIndexBits;

   // Are map pointers encodable into map word?
   bool MapPointersEncodable() {
     if (!FLAG_use_big_map_space) {
-      ASSERT(CountTotalPages() <= kMaxMapPageIndex);
+      ASSERT(CountPagesToTop() <= kMaxMapPageIndex);
       return true;
     }
-    int n_of_pages = Capacity() / Page::kObjectAreaSize;
-    ASSERT(n_of_pages == CountTotalPages());
-    return n_of_pages <= kMaxMapPageIndex;
+    return CountPagesToTop() <= max_map_space_pages_;
   }

   // Should be called after forced sweep to find out if map space needs
   // compaction.
   bool NeedsCompaction(int live_maps) {
-    return !MapPointersEncodable() && live_maps <= kCompactionThreshold;
+    return !MapPointersEncodable() && live_maps <= CompactionThreshold();
   }

   Address TopAfterCompaction(int live_maps) {
@@ -1788,9 +1800,11 @@
     int pages_left = live_maps / kMapsPerPage;
     PageIterator it(this, PageIterator::ALL_PAGES);
     while (pages_left-- > 0) {
+      it.has_next();  // Must be called for side-effects, see bug 586.
       ASSERT(it.has_next());
       it.next()->ClearRSet();
     }
+    it.has_next();  // Must be called for side-effects, see bug 586.
     ASSERT(it.has_next());
     Page* top_page = it.next();
     top_page->ClearRSet();
@@ -1838,10 +1852,14 @@
   static const int kMapsPerPage = Page::kObjectAreaSize / Map::kSize;

   // Do map space compaction if there is a page gap.
- static const int kCompactionThreshold = kMapsPerPage * (kMaxMapPageIndex - 1);
+  int CompactionThreshold() {
+    return kMapsPerPage * (max_map_space_pages_ - 1);
+  }
+
+  const int max_map_space_pages_;

   // An array of page start address in a map space.
-  Address page_addresses_[kMaxMapPageIndex + 1];
+  Address page_addresses_[kMaxMapPageIndex];

  public:
   TRACK_MEMORY("MapSpace")
=======================================
--- /trunk/src/version.cc       Mon Jan 25 02:15:52 2010
+++ /trunk/src/version.cc       Mon Jan 25 03:02:06 2010
@@ -35,7 +35,7 @@
 #define MAJOR_VERSION     2
 #define MINOR_VERSION     0
 #define BUILD_NUMBER      6
-#define PATCH_LEVEL       2
+#define PATCH_LEVEL       3
 #define CANDIDATE_VERSION false

 // Define SONAME to have the SCons build the put a specific SONAME into the
=======================================
--- /trunk/src/x64/ic-x64.cc    Thu Jan 14 07:28:53 2010
+++ /trunk/src/x64/ic-x64.cc    Mon Jan 25 03:02:06 2010
@@ -271,11 +271,10 @@
   ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
   __ CmpObjectType(rcx, JS_OBJECT_TYPE, rdx);
   __ j(below, &slow);
-  // Check that the receiver does not require access checks.  We need
-  // to check this explicitly since this generic stub does not perform
-  // map checks.  The map is already in rdx.
+
+  // Check bit field.
   __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
-           Immediate(1 << Map::kIsAccessCheckNeeded));
+           Immediate(kSlowCaseBitFieldMask));
   __ j(not_zero, &slow);

   // Check that the key is a smi.
=======================================
--- /trunk/test/cctest/test-api.cc      Thu Jan 14 07:28:53 2010
+++ /trunk/test/cctest/test-api.cc      Mon Jan 25 03:02:06 2010
@@ -61,6 +61,27 @@
 namespace i = ::v8::internal;


+static void ExpectString(const char* code, const char* expected) {
+  Local<Value> result = CompileRun(code);
+  CHECK(result->IsString());
+  String::AsciiValue ascii(result);
+  CHECK_EQ(expected, *ascii);
+}
+
+
+static void ExpectBoolean(const char* code, bool expected) {
+  Local<Value> result = CompileRun(code);
+  CHECK(result->IsBoolean());
+  CHECK_EQ(expected, result->BooleanValue());
+}
+
+
+static void ExpectObject(const char* code, Local<Value> expected) {
+  Local<Value> result = CompileRun(code);
+  CHECK(result->Equals(expected));
+}
+
+
 static int signature_callback_count;
 static v8::Handle<Value> IncrementingSignatureCallback(
     const v8::Arguments& args) {
@@ -2379,6 +2400,36 @@
   result = interceptor_getter_script->Run();
   CHECK_EQ(v8_num(625), result);
 }
+
+
+static v8::Handle<Value> IdentityIndexedPropertyGetter(
+    uint32_t index,
+    const AccessorInfo& info) {
+  return v8::Integer::New(index);
+}
+
+
+THREADED_TEST(IndexedInterceptorWithNoSetter) {
+  v8::HandleScope scope;
+  Local<ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+
+  LocalContext context;
+  context->Global()->Set(v8_str("obj"), templ->NewInstance());
+
+  const char* code =
+      "try {"
+      "  obj[0] = 239;"
+      "  for (var i = 0; i < 100; i++) {"
+      "    var v = obj[0];"
+      "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
+      "  }"
+      "  'PASSED'"
+      "} catch(e) {"
+      "  e"
+      "}";
+  ExpectString(code, "PASSED");
+}


 THREADED_TEST(MultiContexts) {
@@ -2465,27 +2516,6 @@
   Local<Script> script1 = Script::Compile(source);
   CHECK_EQ(8901.0, script1->Run()->NumberValue());
 }
-
-
-static void ExpectString(const char* code, const char* expected) {
-  Local<Value> result = CompileRun(code);
-  CHECK(result->IsString());
-  String::AsciiValue ascii(result);
-  CHECK_EQ(0, strcmp(*ascii, expected));
-}
-
-
-static void ExpectBoolean(const char* code, bool expected) {
-  Local<Value> result = CompileRun(code);
-  CHECK(result->IsBoolean());
-  CHECK_EQ(expected, result->BooleanValue());
-}
-
-
-static void ExpectObject(const char* code, Local<Value> expected) {
-  Local<Value> result = CompileRun(code);
-  CHECK(result->Equals(expected));
-}


 THREADED_TEST(UndetectableObject) {
=======================================
--- /trunk/test/cctest/test-mark-compact.cc     Wed Oct 28 07:53:37 2009
+++ /trunk/test/cctest/test-mark-compact.cc     Mon Jan 25 03:02:06 2010
@@ -205,6 +205,36 @@
   prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
   CHECK(obj->GetProperty(prop_name) == Smi::FromInt(23));
 }
+
+
+static Handle<Map> CreateMap() {
+  return Factory::NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+}
+
+
+TEST(MapCompact) {
+  FLAG_max_map_space_pages = 16;
+  InitializeVM();
+
+  {
+    v8::HandleScope sc;
+    // keep allocating maps while pointers are still encodable and thus
+    // mark compact is permitted.
+    Handle<JSObject> root = Factory::NewJSObjectFromMap(CreateMap());
+    do {
+      Handle<Map> map = CreateMap();
+      map->set_prototype(*root);
+      root = Factory::NewJSObjectFromMap(map);
+    } while (Heap::map_space()->MapPointersEncodable());
+  }
+  // Now, as we don't have any handles to just allocated maps, we should
+  // be able to trigger map compaction.
+  // To give an additional chance to fail, try to force compaction which
+  // should be impossible right now.
+  Heap::CollectAllGarbage(true);
+  // And now map pointers should be encodable again.
+  CHECK(Heap::map_space()->MapPointersEncodable());
+}


 static int gc_starts = 0;

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

Reply via email to