Fixed a number of build issues.

Fixed problem with missing I-cache flusing on ARM.

Changed space layout in memory management by splitting up code space into old data space and code space.

Added utf-8 conversion support to the API (issue 57).

Optimized repeated calls to eval with the same strings.  These repeated calls are common in web applications.

Added Xcode project file.

Optimized a couple of Array operation.

Fixed parser bug by checking for end-of-string when parsing break and continue (issue 35).

Fixed problem where asian characters were not categorized as letters.

Fixed bug that disallowed calling functions fetched from an array using a string as an array index (issue 32).

Fixed bug where the internal field count on object templates were sometimes ignored (issue 54).

Added -f option to the shell sample for compatibility with other engines (issue 18).

Added source info to TryCatches in the API.

Fixed problem where the seed for the random number generator was clipped in a double to unsigned int conversion.

Fixed bug where cons string symbols were sometimes converted to non-symbol flat strings during GC.

Fixed bug in error reporting when attempting to convert null to an object.


git-svn-id: http://v8.googlecode.com/svn/trunk@267 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/heap.cc b/src/heap.cc
index b04b4c1..5548fe9 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 Google Inc. All Rights Reserved.
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -83,7 +83,8 @@
 
 
 NewSpace* Heap::new_space_ = NULL;
-OldSpace* Heap::old_space_ = NULL;
+OldSpace* Heap::old_pointer_space_ = NULL;
+OldSpace* Heap::old_data_space_ = NULL;
 OldSpace* Heap::code_space_ = NULL;
 MapSpace* Heap::map_space_ = NULL;
 LargeObjectSpace* Heap::lo_space_ = NULL;
@@ -127,7 +128,8 @@
   if (!HasBeenSetup()) return 0;
 
   return new_space_->Capacity() +
-      old_space_->Capacity() +
+      old_pointer_space_->Capacity() +
+      old_data_space_->Capacity() +
       code_space_->Capacity() +
       map_space_->Capacity();
 }
@@ -137,7 +139,8 @@
   if (!HasBeenSetup()) return 0;
 
   return new_space_->Available() +
-      old_space_->Available() +
+      old_pointer_space_->Available() +
+      old_data_space_->Available() +
       code_space_->Available() +
       map_space_->Available();
 }
@@ -145,10 +148,11 @@
 
 bool Heap::HasBeenSetup() {
   return new_space_ != NULL &&
-      old_space_ != NULL &&
-      code_space_ != NULL &&
-      map_space_ != NULL &&
-      lo_space_ != NULL;
+         old_pointer_space_ != NULL &&
+         old_data_space_ != NULL &&
+         code_space_ != NULL &&
+         map_space_ != NULL &&
+         lo_space_ != NULL;
 }
 
 
@@ -175,13 +179,13 @@
   // Is there enough space left in OLD to guarantee that a scavenge can
   // succeed?
   //
-  // Note that old_space_->MaxAvailable() undercounts the memory available
+  // Note that MemoryAllocator->MaxAvailable() undercounts the memory available
   // for object promotion. It counts only the bytes that the memory
   // allocator has not yet allocated from the OS and assigned to any space,
   // and does not count available bytes already in the old space or code
   // space.  Undercounting is safe---we may get an unrequested full GC when
   // a scavenge would have succeeded.
-  if (old_space_->MaxAvailable() <= new_space_->Size()) {
+  if (MemoryAllocator::MaxAvailable() <= new_space_->Size()) {
     Counters::gc_compactor_caused_by_oldspace_exhaustion.Increment();
     return MARK_COMPACTOR;
   }
@@ -256,9 +260,8 @@
   if (FLAG_gc_verbose) Print();
 
   if (FLAG_print_rset) {
-    // By definition, code space does not have remembered set bits that we
-    // care about.
-    old_space_->PrintRSet();
+    // Not all spaces have remembered set bits that we care about.
+    old_pointer_space_->PrintRSet();
     map_space_->PrintRSet();
     lo_space_->PrintRSet();
   }
@@ -270,11 +273,10 @@
 }
 
 int Heap::SizeOfObjects() {
-  return new_space_->Size() +
-      old_space_->Size() +
-      code_space_->Size() +
-      map_space_->Size() +
-      lo_space_->Size();
+  int total = 0;
+  AllSpaces spaces;
+  while (Space* space = spaces.next()) total += space->Size();
+  return total;
 }
 
 void Heap::GarbageCollectionEpilogue() {
@@ -303,6 +305,14 @@
 }
 
 
+void Heap::CollectAllGarbage() {
+  // Since we are ignoring the return value, the exact choice of space does
+  // not matter, so long as we do not specify NEW_SPACE, which would not
+  // cause a full GC.
+  CollectGarbage(0, OLD_POINTER_SPACE);
+}
+
+
 bool Heap::CollectGarbage(int requested_size, AllocationSpace space) {
   // The VM is in the GC state until exiting this function.
   VMState state(GC);
@@ -344,8 +354,10 @@
   switch (space) {
     case NEW_SPACE:
       return new_space_->Available() >= requested_size;
-    case OLD_SPACE:
-      return old_space_->Available() >= requested_size;
+    case OLD_POINTER_SPACE:
+      return old_pointer_space_->Available() >= requested_size;
+    case OLD_DATA_SPACE:
+      return old_data_space_->Available() >= requested_size;
     case CODE_SPACE:
       return code_space_->Available() >= requested_size;
     case MAP_SPACE:
@@ -381,7 +393,7 @@
 
     // If we have used the mark-compact collector to collect the new
     // space, and it has not compacted the new space, we force a
-    // separate scavenge collection.  THIS IS A HACK.  It covers the
+    // separate scavenge collection.  This is a hack.  It covers the
     // case where (1) a new space collection was requested, (2) the
     // collector selection policy selected the mark-compact collector,
     // and (3) the mark-compact collector policy selected not to
@@ -435,6 +447,10 @@
 
 
 void Heap::MarkCompactPrologue() {
+  // Empty eval caches
+  Heap::eval_cache_global_ = Heap::null_value();
+  Heap::eval_cache_non_global_ = Heap::null_value();
+
   RegExpImpl::OldSpaceCollectionPrologue();
   Top::MarkCompactPrologue();
   ThreadManager::MarkCompactPrologue();
@@ -483,9 +499,9 @@
 
 
 #ifdef DEBUG
-// Visitor class to verify pointers in code space do not point into
+// Visitor class to verify pointers in code or data space do not point into
 // new space.
-class VerifyCodeSpacePointersVisitor: public ObjectVisitor {
+class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor {
  public:
   void VisitPointers(Object** start, Object**end) {
     for (Object** current = start; current < end; current++) {
@@ -500,7 +516,7 @@
 void Heap::Scavenge() {
 #ifdef DEBUG
   if (FLAG_enable_slow_asserts) {
-    VerifyCodeSpacePointersVisitor v;
+    VerifyNonPointerSpacePointersVisitor v;
     HeapObjectIterator it(code_space_);
     while (it.has_next()) {
       HeapObject* object = it.next();
@@ -560,8 +576,8 @@
   IterateRoots(&copy_visitor);
 
   // Copy objects reachable from the old generation.  By definition, there
-  // are no intergenerational pointers in code space.
-  IterateRSet(old_space_, &CopyObject);
+  // are no intergenerational pointers in code or data spaces.
+  IterateRSet(old_pointer_space_, &CopyObject);
   IterateRSet(map_space_, &CopyObject);
   lo_space_->IterateRSet(&CopyObject);
 
@@ -694,12 +710,13 @@
 
 
 void Heap::RebuildRSets() {
-  // By definition, we do not care about remembered set bits in code space.
+  // By definition, we do not care about remembered set bits in code or data
+  // spaces.
   map_space_->ClearRSet();
   RebuildRSets(map_space_);
 
-  old_space_->ClearRSet();
-  RebuildRSets(old_space_);
+  old_pointer_space_->ClearRSet();
+  RebuildRSets(old_pointer_space_);
 
   Heap::lo_space_->ClearRSet();
   RebuildRSets(lo_space_);
@@ -767,7 +784,7 @@
 
   // We use the first word (where the map pointer usually is) of a heap
   // object to record the forwarding pointer.  A forwarding pointer can
-  // point to the old space, the code space, or the to space of the new
+  // point to an old space, the code space, or the to space of the new
   // generation.
   MapWord first_word = object->map_word();
 
@@ -802,26 +819,23 @@
   Object* result;
   // If the object should be promoted, we try to copy it to old space.
   if (ShouldBePromoted(object->address(), object_size)) {
-    AllocationSpace target_space = Heap::TargetSpace(object);
-    if (target_space == OLD_SPACE) {
-      result = old_space_->AllocateRaw(object_size);
-    } else {
-      ASSERT(target_space == CODE_SPACE);
-      result = code_space_->AllocateRaw(object_size);
-    }
+    OldSpace* target_space = Heap::TargetSpace(object);
+    ASSERT(target_space == Heap::old_pointer_space_ ||
+           target_space == Heap::old_data_space_);
+    result = target_space->AllocateRaw(object_size);
 
     if (!result->IsFailure()) {
       *p = MigrateObject(p, HeapObject::cast(result), object_size);
-      if (target_space == OLD_SPACE) {
+      if (target_space == Heap::old_pointer_space_) {
         // Record the object's address at the top of the to space, to allow
         // it to be swept by the scavenger.
         promoted_top -= kPointerSize;
         Memory::Object_at(promoted_top) = *p;
       } else {
 #ifdef DEBUG
-        // Objects promoted to the code space should not have pointers to
+        // Objects promoted to the data space should not have pointers to
         // new space.
-        VerifyCodeSpacePointersVisitor v;
+        VerifyNonPointerSpacePointersVisitor v;
         (*p)->Iterate(&v);
 #endif
       }
@@ -890,7 +904,7 @@
   if (obj->IsFailure()) return false;
   empty_fixed_array_ = FixedArray::cast(obj);
 
-  obj = Allocate(oddball_map(), CODE_SPACE);
+  obj = Allocate(oddball_map(), OLD_DATA_SPACE);
   if (obj->IsFailure()) return false;
   null_value_ = obj;
 
@@ -1016,7 +1030,7 @@
   // Statically ensure that it is safe to allocate heap numbers in paged
   // spaces.
   STATIC_ASSERT(HeapNumber::kSize <= Page::kMaxHeapObjectSize);
-  AllocationSpace space = (pretenure == TENURED) ? CODE_SPACE : NEW_SPACE;
+  AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
   Object* result = AllocateRaw(HeapNumber::kSize, space);
   if (result->IsFailure()) return result;
 
@@ -1042,7 +1056,7 @@
 Object* Heap::CreateOddball(Map* map,
                             const char* to_string,
                             Object* to_number) {
-  Object* result = Allocate(map, CODE_SPACE);
+  Object* result = Allocate(map, OLD_DATA_SPACE);
   if (result->IsFailure()) return result;
   return Oddball::cast(result)->Initialize(to_string, to_number);
 }
@@ -1112,7 +1126,7 @@
   if (obj->IsFailure()) return false;
   nan_value_ = obj;
 
-  obj = Allocate(oddball_map(), CODE_SPACE);
+  obj = Allocate(oddball_map(), OLD_DATA_SPACE);
   if (obj->IsFailure()) return false;
   undefined_value_ = obj;
   ASSERT(!InNewSpace(undefined_value()));
@@ -1194,6 +1208,10 @@
   if (obj->IsFailure()) return false;
   natives_source_cache_ = FixedArray::cast(obj);
 
+  // Initialized eval cache to null value.
+  eval_cache_global_ = null_value();
+  eval_cache_non_global_ = null_value();
+
   return true;
 }
 
@@ -1295,7 +1313,8 @@
 Object* Heap::AllocateProxy(Address proxy, PretenureFlag pretenure) {
   // Statically ensure that it is safe to allocate proxies in paged spaces.
   STATIC_ASSERT(Proxy::kSize <= Page::kMaxHeapObjectSize);
-  AllocationSpace space = (pretenure == TENURED) ? OLD_SPACE : NEW_SPACE;
+  AllocationSpace space =
+      (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
   Object* result = Allocate(proxy_map(), space);
   if (result->IsFailure()) return result;
 
@@ -1491,9 +1510,11 @@
 
 Object* Heap::AllocateByteArray(int length) {
   int size = ByteArray::SizeFor(length);
-  AllocationSpace space = size > MaxHeapObjectSize() ? LO_SPACE : NEW_SPACE;
+  AllocationSpace space =
+      size > MaxHeapObjectSize() ? LO_SPACE : NEW_SPACE;
 
   Object* result = AllocateRaw(size, space);
+
   if (result->IsFailure()) return result;
 
   reinterpret_cast<Array*>(result)->set_map(byte_array_map());
@@ -1510,10 +1531,13 @@
   int sinfo_size = 0;
   if (sinfo != NULL) sinfo_size = sinfo->Serialize(NULL);
   int obj_size = Code::SizeFor(body_size, sinfo_size);
-  AllocationSpace space =
-      (obj_size > MaxHeapObjectSize()) ? LO_SPACE : CODE_SPACE;
+  Object* result;
+  if (obj_size > MaxHeapObjectSize()) {
+    result = lo_space_->AllocateRawCode(obj_size);
+  } else {
+    result = code_space_->AllocateRaw(obj_size);
+  }
 
-  Object* result = AllocateRaw(obj_size, space);
   if (result->IsFailure()) return result;
 
   // Initialize the object
@@ -1530,9 +1554,6 @@
 #ifdef DEBUG
   code->Verify();
 #endif
-
-  CPU::FlushICache(code->instruction_start(), code->instruction_size());
-
   return code;
 }
 
@@ -1540,9 +1561,13 @@
 Object* Heap::CopyCode(Code* code) {
   // Allocate an object the same size as the code object.
   int obj_size = code->Size();
-  AllocationSpace space =
-      (obj_size > MaxHeapObjectSize()) ? LO_SPACE : CODE_SPACE;
-  Object* result = AllocateRaw(obj_size, space);
+  Object* result;
+  if (obj_size > MaxHeapObjectSize()) {
+    result = lo_space_->AllocateRawCode(obj_size);
+  } else {
+    result = code_space_->AllocateRaw(obj_size);
+  }
+
   if (result->IsFailure()) return result;
 
   // Copy code object.
@@ -1553,9 +1578,6 @@
   // Relocate the copy.
   Code* new_code = Code::cast(result);
   new_code->Relocate(new_addr - old_addr);
-
-  CPU::FlushICache(new_code->instruction_start(), new_code->instruction_size());
-
   return new_code;
 }
 
@@ -1603,7 +1625,7 @@
 Object* Heap::AllocateFunction(Map* function_map,
                                SharedFunctionInfo* shared,
                                Object* prototype) {
-  Object* result = Allocate(function_map, OLD_SPACE);
+  Object* result = Allocate(function_map, OLD_POINTER_SPACE);
   if (result->IsFailure()) return result;
   return InitializeFunction(JSFunction::cast(result), shared, prototype);
 }
@@ -1687,7 +1709,8 @@
   if (properties->IsFailure()) return properties;
 
   // Allocate the JSObject.
-  AllocationSpace space = (pretenure == TENURED) ? OLD_SPACE : NEW_SPACE;
+  AllocationSpace space =
+      (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
   if (map->instance_size() > MaxHeapObjectSize()) space = LO_SPACE;
   Object* obj = Allocate(map, space);
   if (obj->IsFailure()) return obj;
@@ -1912,7 +1935,8 @@
   }
 
   // Allocate string.
-  AllocationSpace space = (size > MaxHeapObjectSize()) ? LO_SPACE : CODE_SPACE;
+  AllocationSpace space =
+      (size > MaxHeapObjectSize()) ? LO_SPACE : OLD_DATA_SPACE;
   Object* result = AllocateRaw(size, space);
   if (result->IsFailure()) return result;
 
@@ -1931,7 +1955,7 @@
 
 
 Object* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) {
-  AllocationSpace space = (pretenure == TENURED) ? CODE_SPACE : NEW_SPACE;
+  AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
   int size = AsciiString::SizeFor(length);
   if (size > MaxHeapObjectSize()) {
     space = LO_SPACE;
@@ -1961,7 +1985,7 @@
 
 
 Object* Heap::AllocateRawTwoByteString(int length, PretenureFlag pretenure) {
-  AllocationSpace space = (pretenure == TENURED) ? CODE_SPACE : NEW_SPACE;
+  AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
   int size = TwoByteString::SizeFor(length);
   if (size > MaxHeapObjectSize()) {
     space = LO_SPACE;
@@ -1992,7 +2016,7 @@
 
 Object* Heap::AllocateEmptyFixedArray() {
   int size = FixedArray::SizeFor(0);
-  Object* result = AllocateRaw(size, CODE_SPACE);
+  Object* result = AllocateRaw(size, OLD_DATA_SPACE);
   if (result->IsFailure()) return result;
   // Initialize the object.
   reinterpret_cast<Array*>(result)->set_map(fixed_array_map());
@@ -2010,7 +2034,8 @@
   if (size > MaxHeapObjectSize()) {
     result = lo_space_->AllocateRawFixedArray(size);
   } else {
-    AllocationSpace space = (pretenure == TENURED) ? OLD_SPACE : NEW_SPACE;
+    AllocationSpace space =
+        (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
     result = AllocateRaw(size, space);
   }
   if (result->IsFailure()) return result;
@@ -2108,7 +2133,7 @@
   }
   int size = map->instance_size();
   AllocationSpace space =
-      (size > MaxHeapObjectSize()) ? LO_SPACE : OLD_SPACE;
+      (size > MaxHeapObjectSize()) ? LO_SPACE : OLD_POINTER_SPACE;
   Object* result = Heap::Allocate(map, space);
   if (result->IsFailure()) return result;
   Struct::cast(result)->InitializeBody(size);
@@ -2121,11 +2146,8 @@
 void Heap::Print() {
   if (!HasBeenSetup()) return;
   Top::PrintStack();
-  new_space_->Print();
-  old_space_->Print();
-  code_space_->Print();
-  map_space_->Print();
-  lo_space_->Print();
+  AllSpaces spaces;
+  while (Space* space = spaces.next()) space->Print();
 }
 
 
@@ -2159,8 +2181,10 @@
   MemoryAllocator::ReportStatistics();
   PrintF("To space : ");
   new_space_->ReportStatistics();
-  PrintF("Old space : ");
-  old_space_->ReportStatistics();
+  PrintF("Old pointer space : ");
+  old_pointer_space_->ReportStatistics();
+  PrintF("Old data space : ");
+  old_data_space_->ReportStatistics();
   PrintF("Code space : ");
   code_space_->ReportStatistics();
   PrintF("Map space : ");
@@ -2181,7 +2205,8 @@
   if (OS::IsOutsideAllocatedSpace(addr)) return false;
   return HasBeenSetup() &&
     (new_space_->ToSpaceContains(addr) ||
-     old_space_->Contains(addr) ||
+     old_pointer_space_->Contains(addr) ||
+     old_data_space_->Contains(addr) ||
      code_space_->Contains(addr) ||
      map_space_->Contains(addr) ||
      lo_space_->SlowContains(addr));
@@ -2200,8 +2225,10 @@
   switch (space) {
     case NEW_SPACE:
       return new_space_->ToSpaceContains(addr);
-    case OLD_SPACE:
-      return old_space_->Contains(addr);
+    case OLD_POINTER_SPACE:
+      return old_pointer_space_->Contains(addr);
+    case OLD_DATA_SPACE:
+      return old_data_space_->Contains(addr);
     case CODE_SPACE:
       return code_space_->Contains(addr);
     case MAP_SPACE:
@@ -2221,11 +2248,10 @@
   VerifyPointersVisitor visitor;
   Heap::IterateRoots(&visitor);
 
-  Heap::new_space_->Verify();
-  Heap::old_space_->Verify();
-  Heap::code_space_->Verify();
-  Heap::map_space_->Verify();
-  Heap::lo_space_->Verify();
+  AllSpaces spaces;
+  while (Space* space = spaces.next()) {
+    space->Verify();
+  }
 }
 #endif  // DEBUG
 
@@ -2253,6 +2279,34 @@
 }
 
 
+Object* Heap::LookupEvalCache(bool is_global_context, String* src) {
+  Object* cache = is_global_context ?
+      eval_cache_global_ : eval_cache_non_global_;
+  return cache == null_value() ?
+      null_value() : EvalCache::cast(cache)->Lookup(src);
+}
+
+
+Object* Heap::PutInEvalCache(bool is_global_context, String* src,
+                             JSFunction* value) {
+  Object** cache_ptr = is_global_context ?
+      &eval_cache_global_ : &eval_cache_non_global_;
+
+  if (*cache_ptr == null_value()) {
+    Object* obj = EvalCache::Allocate(kInitialEvalCacheSize);
+    if (obj->IsFailure()) return false;
+    *cache_ptr = obj;
+  }
+
+  Object* new_cache =
+      EvalCache::cast(*cache_ptr)->Put(src, value);
+  if (new_cache->IsFailure()) return new_cache;
+  *cache_ptr = new_cache;
+
+  return value;
+}
+
+
 #ifdef DEBUG
 void Heap::ZapFromSpace() {
   ASSERT(HAS_HEAP_OBJECT_TAG(kFromSpaceZapValue));
@@ -2314,7 +2368,7 @@
 
 void Heap::IterateRSet(PagedSpace* space, ObjectSlotCallback copy_object_func) {
   ASSERT(Page::is_rset_in_use());
-  ASSERT(space == old_space_ || space == map_space_);
+  ASSERT(space == old_pointer_space_ || space == map_space_);
 
   PageIterator it(space, PageIterator::PAGES_IN_USE);
   while (it.has_next()) {
@@ -2419,7 +2473,8 @@
 
 
 int Heap::PromotedSpaceSize() {
-  return old_space_->Size()
+  return old_pointer_space_->Size()
+      + old_data_space_->Size()
       + code_space_->Size()
       + map_space_->Size()
       + lo_space_->Size();
@@ -2466,23 +2521,33 @@
   int old_space_size = new_space_start - old_space_start;
   int code_space_size = young_generation_size_ - old_space_size;
 
-  // Initialize new space. It will not contain code.
+  // Initialize new space.
   new_space_ = new NewSpace(initial_semispace_size_,
                             semispace_size_,
-                            NEW_SPACE,
-                            false);
+                            NEW_SPACE);
   if (new_space_ == NULL) return false;
   if (!new_space_->Setup(new_space_start, young_generation_size_)) return false;
 
   // Initialize old space, set the maximum capacity to the old generation
   // size. It will not contain code.
-  old_space_ = new OldSpace(old_generation_size_, OLD_SPACE, false);
-  if (old_space_ == NULL) return false;
-  if (!old_space_->Setup(old_space_start, old_space_size)) return false;
+  old_pointer_space_ =
+      new OldSpace(old_generation_size_, OLD_POINTER_SPACE, NOT_EXECUTABLE);
+  if (old_pointer_space_ == NULL) return false;
+  if (!old_pointer_space_->Setup(old_space_start, old_space_size >> 1)) {
+    return false;
+  }
+  old_data_space_ =
+      new OldSpace(old_generation_size_, OLD_DATA_SPACE, NOT_EXECUTABLE);
+  if (old_data_space_ == NULL) return false;
+  if (!old_data_space_->Setup(old_space_start + (old_space_size >> 1),
+                              old_space_size >> 1)) {
+    return false;
+  }
 
   // Initialize the code space, set its maximum capacity to the old
   // generation size. It needs executable memory.
-  code_space_ = new OldSpace(old_generation_size_, CODE_SPACE, true);
+  code_space_ =
+      new OldSpace(old_generation_size_, CODE_SPACE, EXECUTABLE);
   if (code_space_ == NULL) return false;
   if (!code_space_->Setup(code_space_start, code_space_size)) return false;
 
@@ -2493,8 +2558,10 @@
   // enough to hold at least a page will cause it to allocate.
   if (!map_space_->Setup(NULL, 0)) return false;
 
-  // The large object space may contain code, so it needs executable memory.
-  lo_space_ = new LargeObjectSpace(LO_SPACE, true);
+  // The large object code space may contain code or data.  We set the memory
+  // to be non-executable here for safety, but this means we need to enable it
+  // explicitly when allocating large code objects.
+  lo_space_ = new LargeObjectSpace(LO_SPACE);
   if (lo_space_ == NULL) return false;
   if (!lo_space_->Setup()) return false;
 
@@ -2523,10 +2590,16 @@
     new_space_ = NULL;
   }
 
-  if (old_space_ != NULL) {
-    old_space_->TearDown();
-    delete old_space_;
-    old_space_ = NULL;
+  if (old_pointer_space_ != NULL) {
+    old_pointer_space_->TearDown();
+    delete old_pointer_space_;
+    old_pointer_space_ = NULL;
+  }
+
+  if (old_data_space_ != NULL) {
+    old_data_space_->TearDown();
+    delete old_data_space_;
+    old_data_space_ = NULL;
   }
 
   if (code_space_ != NULL) {
@@ -2554,7 +2627,8 @@
 void Heap::Shrink() {
   // Try to shrink map, old, and code spaces.
   map_space_->Shrink();
-  old_space_->Shrink();
+  old_pointer_space_->Shrink();
+  old_data_space_->Shrink();
   code_space_->Shrink();
 }
 
@@ -2578,6 +2652,57 @@
 #endif
 
 
+Space* AllSpaces::next() {
+  switch (counter_++) {
+    case NEW_SPACE:
+      return Heap::new_space();
+    case OLD_POINTER_SPACE:
+      return Heap::old_pointer_space();
+    case OLD_DATA_SPACE:
+      return Heap::old_data_space();
+    case CODE_SPACE:
+      return Heap::code_space();
+    case MAP_SPACE:
+      return Heap::map_space();
+    case LO_SPACE:
+      return Heap::lo_space();
+    default:
+      return NULL;
+  }
+}
+
+
+PagedSpace* PagedSpaces::next() {
+  switch (counter_++) {
+    case OLD_POINTER_SPACE:
+      return Heap::old_pointer_space();
+    case OLD_DATA_SPACE:
+      return Heap::old_data_space();
+    case CODE_SPACE:
+      return Heap::code_space();
+    case MAP_SPACE:
+      return Heap::map_space();
+    default:
+      return NULL;
+  }
+}
+
+
+
+OldSpace* OldSpaces::next() {
+  switch (counter_++) {
+    case OLD_POINTER_SPACE:
+      return Heap::old_pointer_space();
+    case OLD_DATA_SPACE:
+      return Heap::old_data_space();
+    case CODE_SPACE:
+      return Heap::code_space();
+    default:
+      return NULL;
+  }
+}
+
+
 SpaceIterator::SpaceIterator() : current_space_(FIRST_SPACE), iterator_(NULL) {
 }
 
@@ -2618,8 +2743,11 @@
     case NEW_SPACE:
       iterator_ = new SemiSpaceIterator(Heap::new_space());
       break;
-    case OLD_SPACE:
-      iterator_ = new HeapObjectIterator(Heap::old_space());
+    case OLD_POINTER_SPACE:
+      iterator_ = new HeapObjectIterator(Heap::old_pointer_space());
+      break;
+    case OLD_DATA_SPACE:
+      iterator_ = new HeapObjectIterator(Heap::old_data_space());
       break;
     case CODE_SPACE:
       iterator_ = new HeapObjectIterator(Heap::code_space());