Version 3.17.7

Limited recursion in regexp compilation by a budget. (Chromium issue 178790)

ES6 symbols: Implemented Symbol intrinsic and basic functionality (issue 2158)

Performance and stability improvements on all platforms.

git-svn-id: http://v8.googlecode.com/svn/trunk@13808 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/heap.cc b/src/heap.cc
index a698339..7ce9263 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -127,7 +127,7 @@
       amount_of_external_allocated_memory_at_last_global_gc_(0),
       old_gen_exhausted_(false),
       store_buffer_rebuilder_(store_buffer()),
-      hidden_symbol_(NULL),
+      hidden_string_(NULL),
       global_gc_prologue_callback_(NULL),
       global_gc_epilogue_callback_(NULL),
       gc_safe_size_of_old_object_(NULL),
@@ -492,10 +492,10 @@
   isolate_->counters()->alive_after_last_gc()->Set(
       static_cast<int>(SizeOfObjects()));
 
-  isolate_->counters()->symbol_table_capacity()->Set(
-      symbol_table()->Capacity());
+  isolate_->counters()->string_table_capacity()->Set(
+      string_table()->Capacity());
   isolate_->counters()->number_of_symbols()->Set(
-      symbol_table()->NumberOfElements());
+      string_table()->NumberOfElements());
 
   if (CommittedMemory() > 0) {
     isolate_->counters()->external_fragmentation_total()->AddSample(
@@ -704,24 +704,25 @@
 
 
 #ifdef VERIFY_HEAP
-// Helper class for verifying the symbol table.
-class SymbolTableVerifier : public ObjectVisitor {
+// Helper class for verifying the string table.
+class StringTableVerifier : public ObjectVisitor {
  public:
   void VisitPointers(Object** start, Object** end) {
     // Visit all HeapObject pointers in [start, end).
     for (Object** p = start; p < end; p++) {
       if ((*p)->IsHeapObject()) {
-        // Check that the symbol is actually a symbol.
-        CHECK((*p)->IsTheHole() || (*p)->IsUndefined() || (*p)->IsSymbol());
+        // Check that the string is actually internalized.
+        CHECK((*p)->IsTheHole() || (*p)->IsUndefined() ||
+              (*p)->IsInternalizedString());
       }
     }
   }
 };
 
 
-static void VerifySymbolTable() {
-  SymbolTableVerifier verifier;
-  HEAP->symbol_table()->IterateElements(&verifier);
+static void VerifyStringTable() {
+  StringTableVerifier verifier;
+  HEAP->string_table()->IterateElements(&verifier);
 }
 #endif  // VERIFY_HEAP
 
@@ -876,7 +877,7 @@
 
 #ifdef VERIFY_HEAP
   if (FLAG_verify_heap) {
-    VerifySymbolTable();
+    VerifyStringTable();
   }
 #endif
 
@@ -1001,7 +1002,7 @@
 
 #ifdef VERIFY_HEAP
   if (FLAG_verify_heap) {
-    VerifySymbolTable();
+    VerifyStringTable();
   }
 #endif
 
@@ -1618,10 +1619,11 @@
 void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) {
   AssertNoAllocation no_allocation;
 
-  // Both the external string table and the symbol table may contain
+  // Both the external string table and the string table may contain
   // external strings, but neither lists them exhaustively, nor is the
   // intersection set empty.  Therefore we iterate over the external string
-  // table first, ignoring symbols, and then over the symbol table.
+  // table first, ignoring internalized strings, and then over the
+  // internalized string table.
 
   class ExternalStringTableVisitorAdapter : public ObjectVisitor {
    public:
@@ -1629,9 +1631,9 @@
         v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {}
     virtual void VisitPointers(Object** start, Object** end) {
       for (Object** p = start; p < end; p++) {
-        // Visit non-symbol external strings,
-        // since symbols are listed in the symbol table.
-        if (!(*p)->IsSymbol()) {
+        // Visit non-internalized external strings,
+        // since internalized strings are listed in the string table.
+        if (!(*p)->IsInternalizedString()) {
           ASSERT((*p)->IsExternalString());
           visitor_->VisitExternalString(Utils::ToLocal(
               Handle<String>(String::cast(*p))));
@@ -1644,14 +1646,14 @@
 
   external_string_table_.Iterate(&external_string_table_visitor);
 
-  class SymbolTableVisitorAdapter : public ObjectVisitor {
+  class StringTableVisitorAdapter : public ObjectVisitor {
    public:
-    explicit SymbolTableVisitorAdapter(
+    explicit StringTableVisitorAdapter(
         v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {}
     virtual void VisitPointers(Object** start, Object** end) {
       for (Object** p = start; p < end; p++) {
         if ((*p)->IsExternalString()) {
-          ASSERT((*p)->IsSymbol());
+          ASSERT((*p)->IsInternalizedString());
           visitor_->VisitExternalString(Utils::ToLocal(
               Handle<String>(String::cast(*p))));
         }
@@ -1659,9 +1661,9 @@
     }
    private:
     v8::ExternalResourceVisitor* visitor_;
-  } symbol_table_visitor(visitor);
+  } string_table_visitor(visitor);
 
-  symbol_table()->IterateElements(&symbol_table_visitor);
+  string_table()->IterateElements(&string_table_visitor);
 }
 
 
@@ -2271,11 +2273,11 @@
 };
 
 
-const Heap::ConstantSymbolTable Heap::constant_symbol_table[] = {
-#define CONSTANT_SYMBOL_ELEMENT(name, contents)                                \
+const Heap::ConstantStringTable Heap::constant_string_table[] = {
+#define CONSTANT_STRING_ELEMENT(name, contents)                                \
   {contents, k##name##RootIndex},
-  SYMBOL_LIST(CONSTANT_SYMBOL_ELEMENT)
-#undef CONSTANT_SYMBOL_ELEMENT
+  INTERNALIZED_STRING_LIST(CONSTANT_STRING_ELEMENT)
+#undef CONSTANT_STRING_ELEMENT
 };
 
 
@@ -2378,6 +2380,11 @@
   }
   set_heap_number_map(Map::cast(obj));
 
+  { MaybeObject* maybe_obj = AllocateMap(SYMBOL_TYPE, Symbol::kSize);
+    if (!maybe_obj->ToObject(&obj)) return false;
+  }
+  set_symbol_map(Map::cast(obj));
+
   { MaybeObject* maybe_obj = AllocateMap(FOREIGN_TYPE, Foreign::kSize);
     if (!maybe_obj->ToObject(&obj)) return false;
   }
@@ -2738,17 +2745,17 @@
   set_infinity_value(HeapNumber::cast(obj));
 
   // The hole has not been created yet, but we want to put something
-  // predictable in the gaps in the symbol table, so lets make that Smi zero.
+  // predictable in the gaps in the string table, so lets make that Smi zero.
   set_the_hole_value(reinterpret_cast<Oddball*>(Smi::FromInt(0)));
 
-  // Allocate initial symbol table.
-  { MaybeObject* maybe_obj = SymbolTable::Allocate(kInitialSymbolTableSize);
+  // Allocate initial string table.
+  { MaybeObject* maybe_obj = StringTable::Allocate(kInitialStringTableSize);
     if (!maybe_obj->ToObject(&obj)) return false;
   }
-  // Don't use set_symbol_table() due to asserts.
-  roots_[kSymbolTableRootIndex] = obj;
+  // Don't use set_string_table() due to asserts.
+  roots_[kStringTableRootIndex] = obj;
 
-  // Finish initializing oddballs after creating symboltable.
+  // Finish initializing oddballs after creating the string table.
   { MaybeObject* maybe_obj =
         undefined_value()->Initialize("undefined",
                                       nan_value(),
@@ -2804,31 +2811,25 @@
   }
   set_termination_exception(obj);
 
-  // Allocate the empty string.
-  { MaybeObject* maybe_obj = AllocateRawOneByteString(0, TENURED);
-    if (!maybe_obj->ToObject(&obj)) return false;
-  }
-  set_empty_string(String::cast(obj));
-
-  for (unsigned i = 0; i < ARRAY_SIZE(constant_symbol_table); i++) {
+  for (unsigned i = 0; i < ARRAY_SIZE(constant_string_table); i++) {
     { MaybeObject* maybe_obj =
-          LookupUtf8Symbol(constant_symbol_table[i].contents);
+          InternalizeUtf8String(constant_string_table[i].contents);
       if (!maybe_obj->ToObject(&obj)) return false;
     }
-    roots_[constant_symbol_table[i].index] = String::cast(obj);
+    roots_[constant_string_table[i].index] = String::cast(obj);
   }
 
-  // Allocate the hidden symbol which is used to identify the hidden properties
+  // Allocate the hidden string which is used to identify the hidden properties
   // in JSObjects. The hash code has a special value so that it will not match
   // the empty string when searching for the property. It cannot be part of the
   // loop above because it needs to be allocated manually with the special
-  // hash code in place. The hash code for the hidden_symbol is zero to ensure
+  // hash code in place. The hash code for the hidden_string is zero to ensure
   // that it will always be at the first entry in property descriptors.
-  { MaybeObject* maybe_obj =
-        AllocateOneByteSymbol(OneByteVector("", 0), String::kEmptyStringHash);
+  { MaybeObject* maybe_obj = AllocateOneByteInternalizedString(
+      OneByteVector("", 0), String::kEmptyStringHash);
     if (!maybe_obj->ToObject(&obj)) return false;
   }
-  hidden_symbol_ = String::cast(obj);
+  hidden_string_ = String::cast(obj);
 
   // Allocate the foreign for __proto__.
   { MaybeObject* maybe_obj =
@@ -2950,7 +2951,7 @@
     kConstructStubDeoptPCOffsetRootIndex,
     kGetterStubDeoptPCOffsetRootIndex,
     kSetterStubDeoptPCOffsetRootIndex,
-    kSymbolTableRootIndex,
+    kStringTableRootIndex,
   };
 
   for (unsigned int i = 0; i < ARRAY_SIZE(writable_roots); i++) {
@@ -2966,10 +2967,10 @@
                                    Object* key_pattern,
                                    ResultsCacheType type) {
   FixedArray* cache;
-  if (!key_string->IsSymbol()) return Smi::FromInt(0);
+  if (!key_string->IsInternalizedString()) return Smi::FromInt(0);
   if (type == STRING_SPLIT_SUBSTRINGS) {
     ASSERT(key_pattern->IsString());
-    if (!key_pattern->IsSymbol()) return Smi::FromInt(0);
+    if (!key_pattern->IsInternalizedString()) return Smi::FromInt(0);
     cache = heap->string_split_cache();
   } else {
     ASSERT(type == REGEXP_MULTIPLE_INDICES);
@@ -3000,10 +3001,10 @@
                                FixedArray* value_array,
                                ResultsCacheType type) {
   FixedArray* cache;
-  if (!key_string->IsSymbol()) return;
+  if (!key_string->IsInternalizedString()) return;
   if (type == STRING_SPLIT_SUBSTRINGS) {
     ASSERT(key_pattern->IsString());
-    if (!key_pattern->IsSymbol()) return;
+    if (!key_pattern->IsInternalizedString()) return;
     cache = heap->string_split_cache();
   } else {
     ASSERT(type == REGEXP_MULTIPLE_INDICES);
@@ -3035,14 +3036,14 @@
     }
   }
   // If the array is a reasonably short list of substrings, convert it into a
-  // list of symbols.
+  // list of internalized strings.
   if (type == STRING_SPLIT_SUBSTRINGS && value_array->length() < 100) {
     for (int i = 0; i < value_array->length(); i++) {
       String* str = String::cast(value_array->get(i));
-      Object* symbol;
-      MaybeObject* maybe_symbol = heap->LookupSymbol(str);
-      if (maybe_symbol->ToObject(&symbol)) {
-        value_array->set(i, symbol);
+      Object* internalized_str;
+      MaybeObject* maybe_string = heap->InternalizeString(str);
+      if (maybe_string->ToObject(&internalized_str)) {
+        value_array->set(i, internalized_str);
       }
     }
   }
@@ -3275,7 +3276,7 @@
   Code* construct_stub =
       isolate_->builtins()->builtin(Builtins::kJSConstructStubGeneric);
   share->set_construct_stub(construct_stub);
-  share->set_instance_class_name(Object_symbol());
+  share->set_instance_class_name(Object_string());
   share->set_function_data(undefined_value(), SKIP_WRITE_BARRIER);
   share->set_script(undefined_value(), SKIP_WRITE_BARRIER);
   share->set_debug_info(undefined_value(), SKIP_WRITE_BARRIER);
@@ -3341,12 +3342,12 @@
     Heap* heap,
     uint16_t c1,
     uint16_t c2) {
-  String* symbol;
+  String* result;
   // Numeric strings have a different hash algorithm not known by
-  // LookupTwoCharsSymbolIfExists, so we skip this step for such strings.
+  // LookupTwoCharsStringIfExists, so we skip this step for such strings.
   if ((!Between(c1, '0', '9') || !Between(c2, '0', '9')) &&
-      heap->symbol_table()->LookupTwoCharsSymbolIfExists(c1, c2, &symbol)) {
-    return symbol;
+      heap->string_table()->LookupTwoCharsStringIfExists(c1, c2, &result)) {
+    return result;
   // Now we know the length is 2, we might as well make use of that fact
   // when building the new string.
   } else if (static_cast<unsigned>(c1 | c2) <= String::kMaxOneByteCharCodeU) {
@@ -3387,7 +3388,7 @@
   int length = first_length + second_length;
 
   // Optimization for 2-byte strings often used as keys in a decompression
-  // dictionary.  Check whether we already have the string in the symbol
+  // dictionary.  Check whether we already have the string in the string
   // table to prevent creation of many unneccesary strings.
   if (length == 2) {
     uint16_t c1 = first->Get(0);
@@ -3502,8 +3503,8 @@
     return LookupSingleCharacterStringFromCode(buffer->Get(start));
   } else if (length == 2) {
     // Optimization for 2-byte strings often used as keys in a decompression
-    // dictionary.  Check whether we already have the string in the symbol
-    // table to prevent creation of many unneccesary strings.
+    // dictionary.  Check whether we already have the string in the string
+    // table to prevent creation of many unnecessary strings.
     uint16_t c1 = buffer->Get(start);
     uint16_t c2 = buffer->Get(start + 1);
     return MakeOrFindTwoCharacterString(this, c1, c2);
@@ -3650,7 +3651,7 @@
     buffer[0] = static_cast<uint8_t>(code);
     Object* result;
     MaybeObject* maybe_result =
-        LookupOneByteSymbol(Vector<const uint8_t>(buffer, 1));
+        InternalizeOneByteString(Vector<const uint8_t>(buffer, 1));
 
     if (!maybe_result->ToObject(&result)) return maybe_result;
     single_character_string_cache()->set(code, result);
@@ -3903,6 +3904,28 @@
 }
 
 
+MaybeObject* Heap::AllocateWithAllocationSite(Map* map, AllocationSpace space,
+    Handle<Object> allocation_site_info_payload) {
+  ASSERT(gc_state_ == NOT_IN_GC);
+  ASSERT(map->instance_type() != MAP_TYPE);
+  // If allocation failures are disallowed, we may allocate in a different
+  // space when new space is full and the object is not a large object.
+  AllocationSpace retry_space =
+      (space != NEW_SPACE) ? space : TargetSpaceId(map->instance_type());
+  int size = map->instance_size() + AllocationSiteInfo::kSize;
+  Object* result;
+  MaybeObject* maybe_result = AllocateRaw(size, space, retry_space);
+  if (!maybe_result->ToObject(&result)) return maybe_result;
+  // No need for write barrier since object is white and map is in old space.
+  HeapObject::cast(result)->set_map_no_write_barrier(map);
+  AllocationSiteInfo* alloc_info = reinterpret_cast<AllocationSiteInfo*>(
+      reinterpret_cast<Address>(result) + map->instance_size());
+  alloc_info->set_map_no_write_barrier(allocation_site_info_map());
+  alloc_info->set_payload(*allocation_site_info_payload, SKIP_WRITE_BARRIER);
+  return result;
+}
+
+
 MaybeObject* Heap::Allocate(Map* map, AllocationSpace space) {
   ASSERT(gc_state_ == NOT_IN_GC);
   ASSERT(map->instance_type() != MAP_TYPE);
@@ -3910,11 +3933,10 @@
   // space when new space is full and the object is not a large object.
   AllocationSpace retry_space =
       (space != NEW_SPACE) ? space : TargetSpaceId(map->instance_type());
+  int size = map->instance_size();
   Object* result;
-  { MaybeObject* maybe_result =
-        AllocateRaw(map->instance_size(), space, retry_space);
-    if (!maybe_result->ToObject(&result)) return maybe_result;
-  }
+  MaybeObject* maybe_result = AllocateRaw(size, space, retry_space);
+  if (!maybe_result->ToObject(&result)) return maybe_result;
   // No need for write barrier since object is white and map is in old space.
   HeapObject::cast(result)->set_map_no_write_barrier(map);
   return result;
@@ -3959,7 +3981,7 @@
   // constructor to the function.
   MaybeObject* maybe_failure =
       JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
-          constructor_symbol(), function, DONT_ENUM);
+          constructor_string(), function, DONT_ENUM);
   if (maybe_failure->IsFailure()) return maybe_failure;
 
   return prototype;
@@ -4098,7 +4120,7 @@
       DescriptorArray::WhitenessWitness witness(descriptors);
       for (int i = 0; i < count; i++) {
         String* name = fun->shared()->GetThisPropertyAssignmentName(i);
-        ASSERT(name->IsSymbol());
+        ASSERT(name->IsInternalizedString());
         FieldDescriptor field(name, i, NONE, i + 1);
         descriptors->Set(i, &field, witness);
       }
@@ -4182,10 +4204,48 @@
       (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
   if (map->instance_size() > Page::kMaxNonCodeHeapObjectSize) space = LO_SPACE;
   Object* obj;
-  { MaybeObject* maybe_obj = Allocate(map, space);
-    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+  MaybeObject* maybe_obj = Allocate(map, space);
+  if (!maybe_obj->To(&obj)) return maybe_obj;
+
+  // Initialize the JSObject.
+  InitializeJSObjectFromMap(JSObject::cast(obj),
+                            FixedArray::cast(properties),
+                            map);
+  ASSERT(JSObject::cast(obj)->HasFastElements());
+  return obj;
+}
+
+
+MaybeObject* Heap::AllocateJSObjectFromMapWithAllocationSite(Map* map,
+    Handle<Object> allocation_site_info_payload) {
+  // JSFunctions should be allocated using AllocateFunction to be
+  // properly initialized.
+  ASSERT(map->instance_type() != JS_FUNCTION_TYPE);
+
+  // Both types of global objects should be allocated using
+  // AllocateGlobalObject to be properly initialized.
+  ASSERT(map->instance_type() != JS_GLOBAL_OBJECT_TYPE);
+  ASSERT(map->instance_type() != JS_BUILTINS_OBJECT_TYPE);
+
+  // Allocate the backing storage for the properties.
+  int prop_size =
+      map->pre_allocated_property_fields() +
+      map->unused_property_fields() -
+      map->inobject_properties();
+  ASSERT(prop_size >= 0);
+  Object* properties;
+  { MaybeObject* maybe_properties = AllocateFixedArray(prop_size);
+    if (!maybe_properties->ToObject(&properties)) return maybe_properties;
   }
 
+  // Allocate the JSObject.
+  AllocationSpace space = NEW_SPACE;
+  if (map->instance_size() > Page::kMaxNonCodeHeapObjectSize) space = LO_SPACE;
+  Object* obj;
+  MaybeObject* maybe_obj = AllocateWithAllocationSite(map, space,
+      allocation_site_info_payload);
+  if (!maybe_obj->To(&obj)) return maybe_obj;
+
   // Initialize the JSObject.
   InitializeJSObjectFromMap(JSObject::cast(obj),
                             FixedArray::cast(properties),
@@ -4218,6 +4278,51 @@
 }
 
 
+MaybeObject* Heap::AllocateJSObjectWithAllocationSite(JSFunction* constructor,
+    Handle<Object> allocation_site_info_payload) {
+  // Allocate the initial map if absent.
+  if (!constructor->has_initial_map()) {
+    Object* initial_map;
+    { MaybeObject* maybe_initial_map = AllocateInitialMap(constructor);
+      if (!maybe_initial_map->ToObject(&initial_map)) return maybe_initial_map;
+    }
+    constructor->set_initial_map(Map::cast(initial_map));
+    Map::cast(initial_map)->set_constructor(constructor);
+  }
+  // Allocate the object based on the constructors initial map, or the payload
+  // advice
+  Map* initial_map = constructor->initial_map();
+
+  JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(
+      *allocation_site_info_payload);
+  Smi* smi = Smi::cast(cell->value());
+  ElementsKind to_kind = static_cast<ElementsKind>(smi->value());
+  AllocationSiteMode mode = TRACK_ALLOCATION_SITE;
+  if (to_kind != initial_map->elements_kind()) {
+    MaybeObject* maybe_new_map = constructor->GetElementsTransitionMap(
+        isolate(), to_kind);
+    if (!maybe_new_map->To(&initial_map)) return maybe_new_map;
+    // Possibly alter the mode, since we found an updated elements kind
+    // in the type info cell.
+    mode = AllocationSiteInfo::GetMode(to_kind);
+  }
+
+  MaybeObject* result;
+  if (mode == TRACK_ALLOCATION_SITE) {
+    result = AllocateJSObjectFromMapWithAllocationSite(initial_map,
+        allocation_site_info_payload);
+  } else {
+    result = AllocateJSObjectFromMap(initial_map, NOT_TENURED);
+  }
+#ifdef DEBUG
+  // Make sure result is NOT a global object if valid.
+  Object* non_failure;
+  ASSERT(!result->ToObject(&non_failure) || !non_failure->IsGlobalObject());
+#endif
+  return result;
+}
+
+
 MaybeObject* Heap::AllocateJSModule(Context* context, ScopeInfo* scope_info) {
   // Allocate a fresh map. Modules do not have a prototype.
   Map* map;
@@ -4239,11 +4344,14 @@
     int capacity,
     ArrayStorageAllocationMode mode,
     PretenureFlag pretenure) {
-  ASSERT(capacity >= length);
   MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure);
   JSArray* array;
   if (!maybe_array->To(&array)) return maybe_array;
 
+  // TODO(mvstanton): this body of code is duplicate with AllocateJSArrayStorage
+  // for performance reasons.
+  ASSERT(capacity >= length);
+
   if (capacity == 0) {
     array->set_length(Smi::FromInt(0));
     array->set_elements(empty_fixed_array());
@@ -4276,6 +4384,60 @@
 }
 
 
+MaybeObject* Heap::AllocateJSArrayAndStorageWithAllocationSite(
+    ElementsKind elements_kind,
+    int length,
+    int capacity,
+    Handle<Object> allocation_site_payload,
+    ArrayStorageAllocationMode mode) {
+  MaybeObject* maybe_array = AllocateJSArrayWithAllocationSite(elements_kind,
+      allocation_site_payload);
+  JSArray* array;
+  if (!maybe_array->To(&array)) return maybe_array;
+  return AllocateJSArrayStorage(array, length, capacity, mode);
+}
+
+
+MaybeObject* Heap::AllocateJSArrayStorage(
+    JSArray* array,
+    int length,
+    int capacity,
+    ArrayStorageAllocationMode mode) {
+  ASSERT(capacity >= length);
+
+  if (capacity == 0) {
+    array->set_length(Smi::FromInt(0));
+    array->set_elements(empty_fixed_array());
+    return array;
+  }
+
+  FixedArrayBase* elms;
+  MaybeObject* maybe_elms = NULL;
+  ElementsKind elements_kind = array->GetElementsKind();
+  if (IsFastDoubleElementsKind(elements_kind)) {
+    if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
+      maybe_elms = AllocateUninitializedFixedDoubleArray(capacity);
+    } else {
+      ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
+      maybe_elms = AllocateFixedDoubleArrayWithHoles(capacity);
+    }
+  } else {
+    ASSERT(IsFastSmiOrObjectElementsKind(elements_kind));
+    if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
+      maybe_elms = AllocateUninitializedFixedArray(capacity);
+    } else {
+      ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
+      maybe_elms = AllocateFixedArrayWithHoles(capacity);
+    }
+  }
+  if (!maybe_elms->To(&elms)) return maybe_elms;
+
+  array->set_elements(elms);
+  array->set_length(Smi::FromInt(length));
+  return array;
+}
+
+
 MaybeObject* Heap::AllocateJSArrayWithElements(
     FixedArrayBase* elements,
     ElementsKind elements_kind,
@@ -4406,8 +4568,7 @@
 }
 
 
-MaybeObject* Heap::CopyJSObject(JSObject* source,
-                                AllocationSiteMode mode) {
+MaybeObject* Heap::CopyJSObject(JSObject* source) {
   // Never used to copy functions.  If functions need to be copied we
   // have to be careful to clear the literals array.
   SLOW_ASSERT(!source->IsJSFunction());
@@ -4417,25 +4578,13 @@
   int object_size = map->instance_size();
   Object* clone;
 
-  bool track_origin = mode == TRACK_ALLOCATION_SITE &&
-      map->CanTrackAllocationSite();
-
   WriteBarrierMode wb_mode = UPDATE_WRITE_BARRIER;
 
   // If we're forced to always allocate, we use the general allocation
   // functions which may leave us with an object in old space.
-  int adjusted_object_size = object_size;
   if (always_allocate()) {
-    // We'll only track origin if we are certain to allocate in new space
-    if (track_origin) {
-      const int kMinFreeNewSpaceAfterGC = InitialSemiSpaceSize() * 3/4;
-      if ((object_size + AllocationSiteInfo::kSize) < kMinFreeNewSpaceAfterGC) {
-        adjusted_object_size += AllocationSiteInfo::kSize;
-      }
-    }
-
     { MaybeObject* maybe_clone =
-          AllocateRaw(adjusted_object_size, NEW_SPACE, OLD_POINTER_SPACE);
+          AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE);
       if (!maybe_clone->ToObject(&clone)) return maybe_clone;
     }
     Address clone_address = HeapObject::cast(clone)->address();
@@ -4448,10 +4597,107 @@
                  (object_size - JSObject::kHeaderSize) / kPointerSize);
   } else {
     wb_mode = SKIP_WRITE_BARRIER;
-    if (track_origin) {
+
+    { MaybeObject* maybe_clone = new_space_.AllocateRaw(object_size);
+      if (!maybe_clone->ToObject(&clone)) return maybe_clone;
+    }
+    SLOW_ASSERT(InNewSpace(clone));
+    // Since we know the clone is allocated in new space, we can copy
+    // the contents without worrying about updating the write barrier.
+    CopyBlock(HeapObject::cast(clone)->address(),
+              source->address(),
+              object_size);
+  }
+
+  SLOW_ASSERT(
+      JSObject::cast(clone)->GetElementsKind() == source->GetElementsKind());
+  FixedArrayBase* elements = FixedArrayBase::cast(source->elements());
+  FixedArray* properties = FixedArray::cast(source->properties());
+  // Update elements if necessary.
+  if (elements->length() > 0) {
+    Object* elem;
+    { MaybeObject* maybe_elem;
+      if (elements->map() == fixed_cow_array_map()) {
+        maybe_elem = FixedArray::cast(elements);
+      } else if (source->HasFastDoubleElements()) {
+        maybe_elem = CopyFixedDoubleArray(FixedDoubleArray::cast(elements));
+      } else {
+        maybe_elem = CopyFixedArray(FixedArray::cast(elements));
+      }
+      if (!maybe_elem->ToObject(&elem)) return maybe_elem;
+    }
+    JSObject::cast(clone)->set_elements(FixedArrayBase::cast(elem), wb_mode);
+  }
+  // Update properties if necessary.
+  if (properties->length() > 0) {
+    Object* prop;
+    { MaybeObject* maybe_prop = CopyFixedArray(properties);
+      if (!maybe_prop->ToObject(&prop)) return maybe_prop;
+    }
+    JSObject::cast(clone)->set_properties(FixedArray::cast(prop), wb_mode);
+  }
+  // Return the new clone.
+  return clone;
+}
+
+
+MaybeObject* Heap::CopyJSObjectWithAllocationSite(JSObject* source) {
+  // Never used to copy functions.  If functions need to be copied we
+  // have to be careful to clear the literals array.
+  SLOW_ASSERT(!source->IsJSFunction());
+
+  // Make the clone.
+  Map* map = source->map();
+  int object_size = map->instance_size();
+  Object* clone;
+
+  ASSERT(map->CanTrackAllocationSite());
+  ASSERT(map->instance_type() == JS_ARRAY_TYPE);
+  WriteBarrierMode wb_mode = UPDATE_WRITE_BARRIER;
+
+  // If we're forced to always allocate, we use the general allocation
+  // functions which may leave us with an object in old space.
+  int adjusted_object_size = object_size;
+  if (always_allocate()) {
+    // We'll only track origin if we are certain to allocate in new space
+    const int kMinFreeNewSpaceAfterGC = InitialSemiSpaceSize() * 3/4;
+    if ((object_size + AllocationSiteInfo::kSize) < kMinFreeNewSpaceAfterGC) {
       adjusted_object_size += AllocationSiteInfo::kSize;
     }
 
+    { MaybeObject* maybe_clone =
+          AllocateRaw(adjusted_object_size, NEW_SPACE, OLD_POINTER_SPACE);
+      if (!maybe_clone->ToObject(&clone)) return maybe_clone;
+    }
+    Address clone_address = HeapObject::cast(clone)->address();
+    CopyBlock(clone_address,
+              source->address(),
+              object_size);
+    // Update write barrier for all fields that lie beyond the header.
+    int write_barrier_offset = adjusted_object_size > object_size
+        ? JSArray::kSize + AllocationSiteInfo::kSize
+        : JSObject::kHeaderSize;
+    if (((object_size - write_barrier_offset) / kPointerSize) > 0) {
+      RecordWrites(clone_address,
+                   write_barrier_offset,
+                   (object_size - write_barrier_offset) / kPointerSize);
+    }
+
+    // Track allocation site information, if we failed to allocate it inline.
+    if (InNewSpace(clone) &&
+        adjusted_object_size == object_size) {
+      MaybeObject* maybe_alloc_info =
+          AllocateStruct(ALLOCATION_SITE_INFO_TYPE);
+      AllocationSiteInfo* alloc_info;
+      if (maybe_alloc_info->To(&alloc_info)) {
+        alloc_info->set_map_no_write_barrier(allocation_site_info_map());
+        alloc_info->set_payload(source, SKIP_WRITE_BARRIER);
+      }
+    }
+  } else {
+    wb_mode = SKIP_WRITE_BARRIER;
+    adjusted_object_size += AllocationSiteInfo::kSize;
+
     { MaybeObject* maybe_clone = new_space_.AllocateRaw(adjusted_object_size);
       if (!maybe_clone->ToObject(&clone)) return maybe_clone;
     }
@@ -4466,8 +4712,8 @@
   if (adjusted_object_size > object_size) {
     AllocationSiteInfo* alloc_info = reinterpret_cast<AllocationSiteInfo*>(
         reinterpret_cast<Address>(clone) + object_size);
-    alloc_info->set_map(allocation_site_info_map());
-    alloc_info->set_payload(source);
+    alloc_info->set_map_no_write_barrier(allocation_site_info_map());
+    alloc_info->set_payload(source, SKIP_WRITE_BARRIER);
   }
 
   SLOW_ASSERT(
@@ -4528,7 +4774,8 @@
   SharedFunctionInfo* shared = NULL;
   if (type == JS_FUNCTION_TYPE) {
     String* name;
-    maybe = LookupOneByteSymbol(STATIC_ASCII_VECTOR("<freezing call trap>"));
+    maybe =
+        InternalizeOneByteString(STATIC_ASCII_VECTOR("<freezing call trap>"));
     if (!maybe->To<String>(&name)) return maybe;
     maybe = AllocateSharedFunctionInfo(name);
     if (!maybe->To<SharedFunctionInfo>(&shared)) return maybe;
@@ -4662,25 +4909,27 @@
 }
 
 
-Map* Heap::SymbolMapForString(String* string) {
-  // If the string is in new space it cannot be used as a symbol.
+Map* Heap::InternalizedStringMapForString(String* string) {
+  // If the string is in new space it cannot be used as internalized.
   if (InNewSpace(string)) return NULL;
 
-  // Find the corresponding symbol map for strings.
+  // Find the corresponding internalized string map for strings.
   switch (string->map()->instance_type()) {
-    case STRING_TYPE: return symbol_map();
-    case ASCII_STRING_TYPE: return ascii_symbol_map();
-    case CONS_STRING_TYPE: return cons_symbol_map();
-    case CONS_ASCII_STRING_TYPE: return cons_ascii_symbol_map();
-    case EXTERNAL_STRING_TYPE: return external_symbol_map();
-    case EXTERNAL_ASCII_STRING_TYPE: return external_ascii_symbol_map();
+    case STRING_TYPE: return internalized_string_map();
+    case ASCII_STRING_TYPE: return ascii_internalized_string_map();
+    case CONS_STRING_TYPE: return cons_internalized_string_map();
+    case CONS_ASCII_STRING_TYPE: return cons_ascii_internalized_string_map();
+    case EXTERNAL_STRING_TYPE: return external_internalized_string_map();
+    case EXTERNAL_ASCII_STRING_TYPE:
+      return external_ascii_internalized_string_map();
     case EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
-      return external_symbol_with_ascii_data_map();
-    case SHORT_EXTERNAL_STRING_TYPE: return short_external_symbol_map();
+      return external_internalized_string_with_ascii_data_map();
+    case SHORT_EXTERNAL_STRING_TYPE:
+      return short_external_internalized_string_map();
     case SHORT_EXTERNAL_ASCII_STRING_TYPE:
-      return short_external_ascii_symbol_map();
+      return short_external_ascii_internalized_string_map();
     case SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
-      return short_external_symbol_with_ascii_data_map();
+      return short_external_internalized_string_with_ascii_data_map();
     default: return NULL;  // No match found.
   }
 }
@@ -4734,9 +4983,8 @@
 
 
 template<bool is_one_byte, typename T>
-MaybeObject* Heap::AllocateInternalSymbol(T t,
-                                          int chars,
-                                          uint32_t hash_field) {
+MaybeObject* Heap::AllocateInternalizedStringImpl(
+    T t, int chars, uint32_t hash_field) {
   ASSERT(chars >= 0);
   // Compute map and object size.
   int size;
@@ -4746,13 +4994,13 @@
     if (chars > SeqOneByteString::kMaxLength) {
       return Failure::OutOfMemoryException(0x9);
     }
-    map = ascii_symbol_map();
+    map = ascii_internalized_string_map();
     size = SeqOneByteString::SizeFor(chars);
   } else {
     if (chars > SeqTwoByteString::kMaxLength) {
       return Failure::OutOfMemoryException(0xa);
     }
-    map = symbol_map();
+    map = internalized_string_map();
     size = SeqTwoByteString::SizeFor(chars);
   }
 
@@ -4783,13 +5031,13 @@
 
 // Need explicit instantiations.
 template
-MaybeObject* Heap::AllocateInternalSymbol<true>(String*, int, uint32_t);
+MaybeObject* Heap::AllocateInternalizedStringImpl<true>(String*, int, uint32_t);
 template
-MaybeObject* Heap::AllocateInternalSymbol<false>(String*, int, uint32_t);
+MaybeObject* Heap::AllocateInternalizedStringImpl<false>(
+    String*, int, uint32_t);
 template
-MaybeObject* Heap::AllocateInternalSymbol<false>(Vector<const char>,
-                                                 int,
-                                                 uint32_t);
+MaybeObject* Heap::AllocateInternalizedStringImpl<false>(
+    Vector<const char>, int, uint32_t);
 
 
 MaybeObject* Heap::AllocateRawOneByteString(int length,
@@ -4897,6 +5145,25 @@
 }
 
 
+MaybeObject* Heap::AllocateJSArrayWithAllocationSite(
+    ElementsKind elements_kind,
+    Handle<Object> allocation_site_info_payload) {
+  Context* native_context = isolate()->context()->native_context();
+  JSFunction* array_function = native_context->array_function();
+  Map* map = array_function->initial_map();
+  Object* maybe_map_array = native_context->js_array_maps();
+  if (!maybe_map_array->IsUndefined()) {
+    Object* maybe_transitioned_map =
+        FixedArray::cast(maybe_map_array)->get(elements_kind);
+    if (!maybe_transitioned_map->IsUndefined()) {
+      map = Map::cast(maybe_transitioned_map);
+    }
+  }
+  return AllocateJSObjectFromMapWithAllocationSite(map,
+      allocation_site_info_payload);
+}
+
+
 MaybeObject* Heap::AllocateEmptyFixedArray() {
   int size = FixedArray::SizeFor(0);
   Object* result;
@@ -5167,6 +5434,34 @@
 }
 
 
+MaybeObject* Heap::AllocateSymbol(PretenureFlag pretenure) {
+  // Statically ensure that it is safe to allocate symbols in paged spaces.
+  STATIC_ASSERT(Symbol::kSize <= Page::kNonCodeObjectAreaSize);
+  AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
+
+  Object* result;
+  MaybeObject* maybe = AllocateRaw(Symbol::kSize, space, OLD_DATA_SPACE);
+  if (!maybe->ToObject(&result)) return maybe;
+
+  HeapObject::cast(result)->set_map_no_write_barrier(symbol_map());
+
+  // Generate a random hash value.
+  int hash;
+  int attempts = 0;
+  do {
+    hash = V8::RandomPrivate(isolate()) & Name::kHashBitMask;
+    attempts++;
+  } while (hash == 0 && attempts < 30);
+  if (hash == 0) hash = 1;  // never return 0
+
+  Symbol::cast(result)->set_hash_field(
+      Name::kIsNotArrayIndexMask | (hash << Name::kHashShift));
+
+  ASSERT(result->IsSymbol());
+  return result;
+}
+
+
 MaybeObject* Heap::AllocateNativeContext() {
   Object* result;
   { MaybeObject* maybe_result =
@@ -5661,93 +5956,93 @@
 #endif
 
 
-MaybeObject* Heap::LookupUtf8Symbol(Vector<const char> string) {
-  Object* symbol = NULL;
+MaybeObject* Heap::InternalizeUtf8String(Vector<const char> string) {
+  Object* result = NULL;
   Object* new_table;
   { MaybeObject* maybe_new_table =
-        symbol_table()->LookupUtf8Symbol(string, &symbol);
+        string_table()->LookupUtf8String(string, &result);
     if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
   }
-  // Can't use set_symbol_table because SymbolTable::cast knows that
-  // SymbolTable is a singleton and checks for identity.
-  roots_[kSymbolTableRootIndex] = new_table;
-  ASSERT(symbol != NULL);
-  return symbol;
+  // Can't use set_string_table because StringTable::cast knows that
+  // StringTable is a singleton and checks for identity.
+  roots_[kStringTableRootIndex] = new_table;
+  ASSERT(result != NULL);
+  return result;
 }
 
 
-MaybeObject* Heap::LookupOneByteSymbol(Vector<const uint8_t> string) {
-  Object* symbol = NULL;
+MaybeObject* Heap::InternalizeOneByteString(Vector<const uint8_t> string) {
+  Object* result = NULL;
   Object* new_table;
   { MaybeObject* maybe_new_table =
-        symbol_table()->LookupOneByteSymbol(string, &symbol);
+        string_table()->LookupOneByteString(string, &result);
     if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
   }
-  // Can't use set_symbol_table because SymbolTable::cast knows that
-  // SymbolTable is a singleton and checks for identity.
-  roots_[kSymbolTableRootIndex] = new_table;
-  ASSERT(symbol != NULL);
-  return symbol;
+  // Can't use set_string_table because StringTable::cast knows that
+  // StringTable is a singleton and checks for identity.
+  roots_[kStringTableRootIndex] = new_table;
+  ASSERT(result != NULL);
+  return result;
 }
 
 
-MaybeObject* Heap::LookupOneByteSymbol(Handle<SeqOneByteString> string,
+MaybeObject* Heap::InternalizeOneByteString(Handle<SeqOneByteString> string,
                                      int from,
                                      int length) {
-  Object* symbol = NULL;
+  Object* result = NULL;
   Object* new_table;
   { MaybeObject* maybe_new_table =
-        symbol_table()->LookupSubStringOneByteSymbol(string,
+        string_table()->LookupSubStringOneByteString(string,
                                                    from,
                                                    length,
-                                                   &symbol);
+                                                   &result);
     if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
   }
-  // Can't use set_symbol_table because SymbolTable::cast knows that
-  // SymbolTable is a singleton and checks for identity.
-  roots_[kSymbolTableRootIndex] = new_table;
-  ASSERT(symbol != NULL);
-  return symbol;
+  // Can't use set_string_table because StringTable::cast knows that
+  // StringTable is a singleton and checks for identity.
+  roots_[kStringTableRootIndex] = new_table;
+  ASSERT(result != NULL);
+  return result;
 }
 
 
-MaybeObject* Heap::LookupTwoByteSymbol(Vector<const uc16> string) {
-  Object* symbol = NULL;
+MaybeObject* Heap::InternalizeTwoByteString(Vector<const uc16> string) {
+  Object* result = NULL;
   Object* new_table;
   { MaybeObject* maybe_new_table =
-        symbol_table()->LookupTwoByteSymbol(string, &symbol);
+        string_table()->LookupTwoByteString(string, &result);
     if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
   }
-  // Can't use set_symbol_table because SymbolTable::cast knows that
-  // SymbolTable is a singleton and checks for identity.
-  roots_[kSymbolTableRootIndex] = new_table;
-  ASSERT(symbol != NULL);
-  return symbol;
+  // Can't use set_string_table because StringTable::cast knows that
+  // StringTable is a singleton and checks for identity.
+  roots_[kStringTableRootIndex] = new_table;
+  ASSERT(result != NULL);
+  return result;
 }
 
 
-MaybeObject* Heap::LookupSymbol(String* string) {
-  if (string->IsSymbol()) return string;
-  Object* symbol = NULL;
+MaybeObject* Heap::InternalizeString(String* string) {
+  if (string->IsInternalizedString()) return string;
+  Object* result = NULL;
   Object* new_table;
   { MaybeObject* maybe_new_table =
-        symbol_table()->LookupString(string, &symbol);
+        string_table()->LookupString(string, &result);
     if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
   }
-  // Can't use set_symbol_table because SymbolTable::cast knows that
-  // SymbolTable is a singleton and checks for identity.
-  roots_[kSymbolTableRootIndex] = new_table;
-  ASSERT(symbol != NULL);
-  return symbol;
+  // Can't use set_string_table because StringTable::cast knows that
+  // StringTable is a singleton and checks for identity.
+  roots_[kStringTableRootIndex] = new_table;
+  ASSERT(result != NULL);
+  return result;
 }
 
 
-bool Heap::LookupSymbolIfExists(String* string, String** symbol) {
-  if (string->IsSymbol()) {
-    *symbol = string;
+bool Heap::InternalizeStringIfExists(String* string, String** result) {
+  if (string->IsInternalizedString()) {
+    *result = string;
     return true;
   }
-  return symbol_table()->LookupSymbolIfExists(string, symbol);
+  return string_table()->LookupStringIfExists(string, result);
 }
 
 
@@ -5975,8 +6270,8 @@
 
 
 void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) {
-  v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex]));
-  v->Synchronize(VisitorSynchronization::kSymbolTable);
+  v->VisitPointer(reinterpret_cast<Object**>(&roots_[kStringTableRootIndex]));
+  v->Synchronize(VisitorSynchronization::kStringTable);
   if (mode != VISIT_ALL_IN_SCAVENGE &&
       mode != VISIT_ALL_IN_SWEEP_NEWSPACE) {
     // Scavenge collections have special processing for this.
@@ -5991,8 +6286,8 @@
   v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]);
   v->Synchronize(VisitorSynchronization::kStrongRootList);
 
-  v->VisitPointer(BitCast<Object**>(&hidden_symbol_));
-  v->Synchronize(VisitorSynchronization::kSymbol);
+  v->VisitPointer(BitCast<Object**>(&hidden_string_));
+  v->Synchronize(VisitorSynchronization::kInternalizedString);
 
   isolate_->bootstrapper()->Iterate(v);
   v->Synchronize(VisitorSynchronization::kBootstrapper);
@@ -7169,9 +7464,9 @@
 
 
 void KeyedLookupCache::Update(Map* map, String* name, int field_offset) {
-  String* symbol;
-  if (HEAP->LookupSymbolIfExists(name, &symbol)) {
-    int index = (Hash(map, symbol) & kHashMask);
+  String* internalized_name;
+  if (HEAP->InternalizeStringIfExists(name, &internalized_name)) {
+    int index = (Hash(map, internalized_name) & kHashMask);
     // After a GC there will be free slots, so we use them in order (this may
     // help to get the most frequently used one in position 0).
     for (int i = 0; i< kEntriesPerBucket; i++) {
@@ -7179,7 +7474,7 @@
       Object* free_entry_indicator = NULL;
       if (key.map == free_entry_indicator) {
         key.map = map;
-        key.name = symbol;
+        key.name = internalized_name;
         field_offsets_[index + i] = field_offset;
         return;
       }
@@ -7196,7 +7491,7 @@
     // Write the new first entry.
     Key& key = keys_[index];
     key.map = map;
-    key.name = symbol;
+    key.name = internalized_name;
     field_offsets_[index] = field_offset;
   }
 }
@@ -7329,7 +7624,7 @@
   if (nested_ || list_.is_empty() || isolate->has_pending_exception()) return;
   nested_ = true;
   HandleScope scope(isolate);
-  Handle<String> stack_key = isolate->factory()->stack_symbol();
+  Handle<String> stack_key = isolate->factory()->stack_string();
   int write_index = 0;
   int budget = kBudgetPerGC;
   for (int i = 0; i < list_.length(); i++) {
@@ -7353,7 +7648,7 @@
       Object* getter_obj = AccessorPair::cast(callback)->getter();
       if (!getter_obj->IsJSFunction()) continue;
       getter_fun = JSFunction::cast(getter_obj);
-      String* key = isolate->heap()->hidden_stack_trace_symbol();
+      String* key = isolate->heap()->hidden_stack_trace_string();
       if (key != getter_fun->GetHiddenProperty(key)) continue;
     }