Version 2.0.4

Added ECMAScript 5 Object.create.

Improved performance of Math.max and Math.min.

Optimized adding of strings on 64-bit platforms.

Improved handling of external strings by using a separate table instead of weak handles.  This improves garbage collection performance and uses less memory.

Changed code generation for object and array literals in toplevel code to be more compact by doing more work in the runtime.

Fixed a crash bug triggered when garbage collection happened during generation of a callback load inline cache stub.

Fixed crash bug sometimes triggered when local variables shadowed parameters in functions that used the arguments object.


git-svn-id: http://v8.googlecode.com/svn/trunk@3475 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/heap.cc b/src/heap.cc
index 4e4cd1c..b9aa95c 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -733,7 +733,7 @@
 
   ScavengeVisitor scavenge_visitor;
   // Copy roots.
-  IterateRoots(&scavenge_visitor, VISIT_ALL);
+  IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE);
 
   // Copy objects reachable from the old generation.  By definition,
   // there are no intergenerational pointers in code or data spaces.
@@ -753,6 +753,63 @@
     }
   }
 
+  new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
+
+  ScavengeExternalStringTable();
+  ASSERT(new_space_front == new_space_.top());
+
+  // Set age mark.
+  new_space_.set_age_mark(new_space_.top());
+
+  // Update how much has survived scavenge.
+  survived_since_last_expansion_ +=
+      (PromotedSpaceSize() - survived_watermark) + new_space_.Size();
+
+  LOG(ResourceEvent("scavenge", "end"));
+
+  gc_state_ = NOT_IN_GC;
+}
+
+
+void Heap::ScavengeExternalStringTable() {
+  ExternalStringTable::Verify();
+
+  if (ExternalStringTable::new_space_strings_.is_empty()) return;
+
+  Object** start = &ExternalStringTable::new_space_strings_[0];
+  Object** end = start + ExternalStringTable::new_space_strings_.length();
+  Object** last = start;
+
+  for (Object** p = start; p < end; ++p) {
+    ASSERT(Heap::InFromSpace(*p));
+    MapWord first_word = HeapObject::cast(*p)->map_word();
+
+    if (!first_word.IsForwardingAddress()) {
+      // Unreachable external string can be finalized.
+      FinalizeExternalString(String::cast(*p));
+      continue;
+    }
+
+    // String is still reachable.
+    String* target = String::cast(first_word.ToForwardingAddress());
+    ASSERT(target->IsExternalString());
+
+    if (Heap::InNewSpace(target)) {
+      // String is still in new space.  Update the table entry.
+      *last = target;
+      ++last;
+    } else {
+      // String got promoted.  Move it to the old string list.
+      ExternalStringTable::AddOldString(target);
+    }
+  }
+
+  ExternalStringTable::ShrinkNewStrings(last - start);
+}
+
+
+Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor,
+                         Address new_space_front) {
   do {
     ASSERT(new_space_front <= new_space_.top());
 
@@ -761,7 +818,7 @@
     // queue is empty.
     while (new_space_front < new_space_.top()) {
       HeapObject* object = HeapObject::FromAddress(new_space_front);
-      object->Iterate(&scavenge_visitor);
+      object->Iterate(scavenge_visitor);
       new_space_front += object->Size();
     }
 
@@ -783,7 +840,7 @@
       RecordCopiedObject(target);
 #endif
       // Visit the newly copied object for pointers to new space.
-      target->Iterate(&scavenge_visitor);
+      target->Iterate(scavenge_visitor);
       UpdateRSet(target);
     }
 
@@ -791,16 +848,7 @@
     // (there are currently no more unswept promoted objects).
   } while (new_space_front < new_space_.top());
 
-  // Set age mark.
-  new_space_.set_age_mark(new_space_.top());
-
-  // Update how much has survived scavenge.
-  survived_since_last_expansion_ +=
-      (PromotedSpaceSize() - survived_watermark) + new_space_.Size();
-
-  LOG(ResourceEvent("scavenge", "end"));
-
-  gc_state_ = NOT_IN_GC;
+  return new_space_front;
 }
 
 
@@ -3175,6 +3223,11 @@
   IterateStrongRoots(v, mode);
   v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex]));
   v->Synchronize("symbol_table");
+  if (mode != VISIT_ALL_IN_SCAVENGE) {
+    // Scavenge collections have special processing for this.
+    ExternalStringTable::Iterate(v);
+  }
+  v->Synchronize("external_string_table");
 }
 
 
@@ -3203,11 +3256,12 @@
   HandleScopeImplementer::Iterate(v);
   v->Synchronize("handlescope");
 
-  // Iterate over the builtin code objects and code stubs in the heap. Note
-  // that it is not strictly necessary to iterate over code objects on
-  // scavenge collections.  We still do it here because this same function
-  // is used by the mark-sweep collector and the deserializer.
-  Builtins::IterateBuiltins(v);
+  // Iterate over the builtin code objects and code stubs in the
+  // heap. Note that it is not necessary to iterate over code objects
+  // on scavenge collections.
+  if (mode != VISIT_ALL_IN_SCAVENGE) {
+    Builtins::IterateBuiltins(v);
+  }
   v->Synchronize("builtins");
 
   // Iterate over global handles.
@@ -3424,6 +3478,8 @@
 void Heap::TearDown() {
   GlobalHandles::TearDown();
 
+  ExternalStringTable::TearDown();
+
   new_space_.TearDown();
 
   if (old_pointer_space_ != NULL) {
@@ -3839,8 +3895,8 @@
 
 // Triggers a depth-first traversal of reachable objects from roots
 // and finds a path to a specific heap object and prints it.
-void Heap::TracePathToObject() {
-  search_target = NULL;
+void Heap::TracePathToObject(Object* target) {
+  search_target = target;
   search_for_any_global = false;
 
   MarkRootVisitor root_visitor;
@@ -3907,8 +3963,8 @@
 int KeyedLookupCache::Hash(Map* map, String* name) {
   // Uses only lower 32 bits if pointers are larger.
   uintptr_t addr_hash =
-      static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> 2;
-  return (addr_hash ^ name->Hash()) % kLength;
+      static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift;
+  return (addr_hash ^ name->Hash()) & kCapacityMask;
 }
 
 
@@ -3991,4 +4047,35 @@
 }
 
 
+void ExternalStringTable::CleanUp() {
+  int last = 0;
+  for (int i = 0; i < new_space_strings_.length(); ++i) {
+    if (new_space_strings_[i] == Heap::raw_unchecked_null_value()) continue;
+    if (Heap::InNewSpace(new_space_strings_[i])) {
+      new_space_strings_[last++] = new_space_strings_[i];
+    } else {
+      old_space_strings_.Add(new_space_strings_[i]);
+    }
+  }
+  new_space_strings_.Rewind(last);
+  last = 0;
+  for (int i = 0; i < old_space_strings_.length(); ++i) {
+    if (old_space_strings_[i] == Heap::raw_unchecked_null_value()) continue;
+    ASSERT(!Heap::InNewSpace(old_space_strings_[i]));
+    old_space_strings_[last++] = old_space_strings_[i];
+  }
+  old_space_strings_.Rewind(last);
+  Verify();
+}
+
+
+void ExternalStringTable::TearDown() {
+  new_space_strings_.Free();
+  old_space_strings_.Free();
+}
+
+
+List<Object*> ExternalStringTable::new_space_strings_;
+List<Object*> ExternalStringTable::old_space_strings_;
+
 } }  // namespace v8::internal