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