Improved string hash-code distribution by excluding bit-field bits from the hash-code.
Changed string search algorithm used in indexOf from KMP to Boyer-Moore.
Improved the generated code for the instanceof operator.
Improved performance of slow-case string equality checks by specializing the code based on the string representation.
Improve the handling of out-of-memory situations (issue 70).
Improved performance of strict equality checks.
Improved profiler output to make it easier to see anonymous functions.
Improved performance of slow-case keyed loads.
Improved property access performance by allocating a number of properties in the front object.
Changed the toString behavior on the built-in object constructors to print [native code] instead of the actual source. Some web applications do not like constructors with complex toString results.
git-svn-id: http://v8.googlecode.com/svn/trunk@511 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/heap.cc b/src/heap.cc
index 526f0fe..7ebc96c 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -733,10 +733,20 @@
int size) {
void** src = reinterpret_cast<void**>((*source_p)->address());
void** dst = reinterpret_cast<void**>(target->address());
- int counter = size/kPointerSize - 1;
- do {
- *dst++ = *src++;
- } while (counter-- > 0);
+
+ // Use block copying memcpy if the object we're migrating is big
+ // enough to justify the extra call/setup overhead.
+ static const int kBlockCopyLimit = 16 * kPointerSize;
+
+ if (size >= kBlockCopyLimit) {
+ memcpy(dst, src, size);
+ } else {
+ int remaining = size / kPointerSize;
+ do {
+ remaining--;
+ *dst++ = *src++;
+ } while (remaining > 0);
+ }
// Set the forwarding address.
(*source_p)->set_map_word(MapWord::FromForwardingAddress(target));
@@ -833,6 +843,7 @@
reinterpret_cast<Map*>(result)->set_map(meta_map());
reinterpret_cast<Map*>(result)->set_instance_type(instance_type);
reinterpret_cast<Map*>(result)->set_instance_size(instance_size);
+ reinterpret_cast<Map*>(result)->set_inobject_properties(0);
reinterpret_cast<Map*>(result)->set_unused_property_fields(0);
return result;
}
@@ -848,6 +859,7 @@
map->set_prototype(null_value());
map->set_constructor(null_value());
map->set_instance_size(instance_size);
+ map->set_inobject_properties(0);
map->set_instance_descriptors(empty_descriptor_array());
map->set_code_cache(empty_fixed_array());
map->set_unused_property_fields(0);
@@ -921,32 +933,32 @@
STRING_TYPE_LIST(ALLOCATE_STRING_MAP);
#undef ALLOCATE_STRING_MAP
- obj = AllocateMap(SHORT_STRING_TYPE, TwoByteString::kHeaderSize);
+ obj = AllocateMap(SHORT_STRING_TYPE, SeqTwoByteString::kHeaderSize);
if (obj->IsFailure()) return false;
undetectable_short_string_map_ = Map::cast(obj);
undetectable_short_string_map_->set_is_undetectable();
- obj = AllocateMap(MEDIUM_STRING_TYPE, TwoByteString::kHeaderSize);
+ obj = AllocateMap(MEDIUM_STRING_TYPE, SeqTwoByteString::kHeaderSize);
if (obj->IsFailure()) return false;
undetectable_medium_string_map_ = Map::cast(obj);
undetectable_medium_string_map_->set_is_undetectable();
- obj = AllocateMap(LONG_STRING_TYPE, TwoByteString::kHeaderSize);
+ obj = AllocateMap(LONG_STRING_TYPE, SeqTwoByteString::kHeaderSize);
if (obj->IsFailure()) return false;
undetectable_long_string_map_ = Map::cast(obj);
undetectable_long_string_map_->set_is_undetectable();
- obj = AllocateMap(SHORT_ASCII_STRING_TYPE, AsciiString::kHeaderSize);
+ obj = AllocateMap(SHORT_ASCII_STRING_TYPE, SeqAsciiString::kHeaderSize);
if (obj->IsFailure()) return false;
undetectable_short_ascii_string_map_ = Map::cast(obj);
undetectable_short_ascii_string_map_->set_is_undetectable();
- obj = AllocateMap(MEDIUM_ASCII_STRING_TYPE, AsciiString::kHeaderSize);
+ obj = AllocateMap(MEDIUM_ASCII_STRING_TYPE, SeqAsciiString::kHeaderSize);
if (obj->IsFailure()) return false;
undetectable_medium_ascii_string_map_ = Map::cast(obj);
undetectable_medium_ascii_string_map_->set_is_undetectable();
- obj = AllocateMap(LONG_ASCII_STRING_TYPE, AsciiString::kHeaderSize);
+ obj = AllocateMap(LONG_ASCII_STRING_TYPE, SeqAsciiString::kHeaderSize);
if (obj->IsFailure()) return false;
undetectable_long_ascii_string_map_ = Map::cast(obj);
undetectable_long_ascii_string_map_->set_is_undetectable();
@@ -1318,7 +1330,8 @@
Object* Heap::AllocateConsString(String* first, String* second) {
int length = first->length() + second->length();
- bool is_ascii = first->is_ascii() && second->is_ascii();
+ bool is_ascii = first->is_ascii_representation()
+ && second->is_ascii_representation();
// If the resulting string is small make a flat string.
if (length < ConsString::kMinLength) {
@@ -1375,13 +1388,13 @@
Map* map;
if (length <= String::kMaxShortStringSize) {
- map = buffer->is_ascii() ? short_sliced_ascii_string_map()
+ map = buffer->is_ascii_representation() ? short_sliced_ascii_string_map()
: short_sliced_string_map();
} else if (length <= String::kMaxMediumStringSize) {
- map = buffer->is_ascii() ? medium_sliced_ascii_string_map()
+ map = buffer->is_ascii_representation() ? medium_sliced_ascii_string_map()
: medium_sliced_string_map();
} else {
- map = buffer->is_ascii() ? long_sliced_ascii_string_map()
+ map = buffer->is_ascii_representation() ? long_sliced_ascii_string_map()
: long_sliced_string_map();
}
@@ -1400,19 +1413,33 @@
Object* Heap::AllocateSubString(String* buffer, int start, int end) {
int length = end - start;
+ if (length == 1) {
+ return Heap::LookupSingleCharacterStringFromCode(buffer->Get(start));
+ }
+
// Make an attempt to flatten the buffer to reduce access time.
buffer->TryFlatten();
- Object* result = buffer->is_ascii()
+ Object* result = buffer->is_ascii_representation()
? AllocateRawAsciiString(length)
: AllocateRawTwoByteString(length);
if (result->IsFailure()) return result;
// Copy the characters into the new object.
String* string_result = String::cast(result);
- for (int i = 0; i < length; i++) {
- string_result->Set(i, buffer->Get(start + i));
+ StringHasher hasher(length);
+ int i = 0;
+ for (; i < length && hasher.is_array_index(); i++) {
+ uc32 c = buffer->Get(start + i);
+ hasher.AddCharacter(c);
+ string_result->Set(i, c);
}
+ for (; i < length; i++) {
+ uc32 c = buffer->Get(start + i);
+ hasher.AddCharacterNoIndex(c);
+ string_result->Set(i, c);
+ }
+ string_result->set_length_field(hasher.GetHashField());
return result;
}
@@ -1636,8 +1663,17 @@
Object* Heap::AllocateInitialMap(JSFunction* fun) {
ASSERT(!fun->has_initial_map());
- // First create a new map.
- Object* map_obj = Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+ // First create a new map with the expected number of properties being
+ // allocated in-object.
+ int expected_nof_properties = fun->shared()->expected_nof_properties();
+ int instance_size = JSObject::kHeaderSize +
+ expected_nof_properties * kPointerSize;
+ if (instance_size > JSObject::kMaxInstanceSize) {
+ instance_size = JSObject::kMaxInstanceSize;
+ expected_nof_properties = (instance_size - JSObject::kHeaderSize) /
+ kPointerSize;
+ }
+ Object* map_obj = Heap::AllocateMap(JS_OBJECT_TYPE, instance_size);
if (map_obj->IsFailure()) return map_obj;
// Fetch or allocate prototype.
@@ -1649,7 +1685,8 @@
if (prototype->IsFailure()) return prototype;
}
Map* map = Map::cast(map_obj);
- map->set_unused_property_fields(fun->shared()->expected_nof_properties());
+ map->set_inobject_properties(expected_nof_properties);
+ map->set_unused_property_fields(expected_nof_properties);
map->set_prototype(prototype);
return map;
}
@@ -1677,7 +1714,8 @@
ASSERT(map->instance_type() != JS_FUNCTION_TYPE);
// Allocate the backing storage for the properties.
- Object* properties = AllocateFixedArray(map->unused_property_fields());
+ int prop_size = map->unused_property_fields() - map->inobject_properties();
+ Object* properties = AllocateFixedArray(prop_size);
if (properties->IsFailure()) return properties;
// Allocate the JSObject.
@@ -1726,7 +1764,8 @@
ASSERT(map->instance_size() == object->map()->instance_size());
// Allocate the backing storage for the properties.
- Object* properties = AllocateFixedArray(map->unused_property_fields());
+ int prop_size = map->unused_property_fields() - map->inobject_properties();
+ Object* properties = AllocateFixedArray(prop_size);
if (properties->IsFailure()) return properties;
// Reset the map for the object.
@@ -1744,9 +1783,9 @@
if (result->IsFailure()) return result;
// Copy the characters into the new object.
- AsciiString* string_result = AsciiString::cast(result);
+ SeqAsciiString* string_result = SeqAsciiString::cast(result);
for (int i = 0; i < string.length(); i++) {
- string_result->AsciiStringSet(i, string[i]);
+ string_result->SeqAsciiStringSet(i, string[i]);
}
return result;
}
@@ -1872,7 +1911,7 @@
Object* Heap::AllocateSymbol(unibrow::CharacterStream* buffer,
int chars,
- int hash) {
+ uint32_t length_field) {
// Ensure the chars matches the number of characters in the buffer.
ASSERT(static_cast<unsigned>(chars) == buffer->Length());
// Determine whether the string is ascii.
@@ -1894,7 +1933,7 @@
} else {
map = long_ascii_symbol_map();
}
- size = AsciiString::SizeFor(chars);
+ size = SeqAsciiString::SizeFor(chars);
} else {
if (chars <= String::kMaxShortStringSize) {
map = short_symbol_map();
@@ -1903,7 +1942,7 @@
} else {
map = long_symbol_map();
}
- size = TwoByteString::SizeFor(chars);
+ size = SeqTwoByteString::SizeFor(chars);
}
// Allocate string.
@@ -1914,7 +1953,7 @@
reinterpret_cast<HeapObject*>(result)->set_map(map);
// The hash value contains the length of the string.
- String::cast(result)->set_length_field(hash);
+ String::cast(result)->set_length_field(length_field);
ASSERT_EQ(size, String::cast(result)->Size());
@@ -1928,7 +1967,7 @@
Object* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) {
AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
- int size = AsciiString::SizeFor(length);
+ int size = SeqAsciiString::SizeFor(length);
if (size > MaxHeapObjectSize()) {
space = LO_SPACE;
}
@@ -1958,7 +1997,7 @@
Object* Heap::AllocateRawTwoByteString(int length, PretenureFlag pretenure) {
AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
- int size = TwoByteString::SizeFor(length);
+ int size = SeqTwoByteString::SizeFor(length);
if (size > MaxHeapObjectSize()) {
space = LO_SPACE;
}
@@ -2251,6 +2290,16 @@
}
+bool Heap::LookupSymbolIfExists(String* string, String** symbol) {
+ if (string->IsSymbol()) {
+ *symbol = string;
+ return true;
+ }
+ SymbolTable* table = SymbolTable::cast(symbol_table_);
+ return table->LookupSymbolIfExists(string, symbol);
+}
+
+
#ifdef DEBUG
void Heap::ZapFromSpace() {
ASSERT(HAS_HEAP_OBJECT_TAG(kFromSpaceZapValue));