Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index f3a543f0774788c6176b743e0f23d32c1f5e034f..8c379157c933b36d2bd2ed9fbdbff3e5e4af4836 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -1177,20 +1177,93 @@ void JSObject::JSObjectShortPrint(StringStream* accumulator) { |
void JSObject::PrintElementsTransition( |
FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements, |
ElementsKind to_kind, FixedArrayBase* to_elements) { |
+ PrintF(file, "elements transition ["); |
+ PrintElementsKind(file, from_kind); |
+ PrintF(file, " -> "); |
+ PrintElementsKind(file, to_kind); |
+ PrintF(file, "] in "); |
+ JavaScriptFrame::PrintTop(file, false, true); |
+ PrintF(file, " for "); |
+ ShortPrint(file); |
+ PrintF(file, " from "); |
+ from_elements->ShortPrint(file); |
+ PrintF(file, " to "); |
+ to_elements->ShortPrint(file); |
+ PrintF(file, "\n"); |
+} |
+ |
+enum { |
+ kFastElementArrayBiasIncrement = 1, |
+ kFastElementArrayBiasThreshold = 3, |
+ kFastSmiOnlyElementArrayBiasIncrement = -10, |
+ kFastSmiOnlyElementArrayBiasThreshold = -30 |
+}; |
+ |
+ |
+void JSObject::RecordElementsTransition( |
+ ElementsKind from_kind, FixedArrayBase* from_elements, |
+ ElementsKind to_kind, FixedArrayBase* to_elements) { |
if (from_kind != to_kind) { |
- PrintF(file, "elements transition ["); |
- PrintElementsKind(file, from_kind); |
- PrintF(file, " -> "); |
- PrintElementsKind(file, to_kind); |
- PrintF(file, "] in "); |
- JavaScriptFrame::PrintTop(file, false, true); |
- PrintF(file, " for "); |
- ShortPrint(file); |
- PrintF(file, " from "); |
- from_elements->ShortPrint(file); |
- PrintF(file, " to "); |
- to_elements->ShortPrint(file); |
- PrintF(file, "\n"); |
+ if (FLAG_trace_elements_transitions) { |
+ PrintElementsTransition(stdout, from_kind, from_elements, |
+ to_kind, to_elements); |
+ } |
+ } |
+ |
+ // Use elements transitions to determine whether Array() should by default |
+ // return an array of type FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS. Defaulting |
+ // to FAST_ELEMENTS save the expense of element transition for code that |
+ // doesn't make use of double arrays. More FAST_ELEMENTS transitions than |
+ // FAST_DOUBLE_ELEMENTS transitions suggest that Array() should always return |
+ // elements kinds of FAST_ELEMENTS. However, FAST_DOUBLE_ELEMENTS |
+ // transitions are weighted an order of magnitude heavier than FAST_ELEMENT |
+ // transitions, since the savings is in general much greater if the runtime |
+ // can recognize and exploit FAST_DOUBLE_ELEMENTS, even at the expense of |
+ // extra transitions. |
+ Context* global_context = GetIsolate()->context()->global_context(); |
+ if (global_context->untransitioned_js_array_map() != NULL && |
Jakob Kummerow
2012/01/04 20:55:17
Don't you mean s/NULL/GetHeap()->undefined_value()
|
+ IsJSArray() && from_kind == FAST_SMI_ONLY_ELEMENTS) { |
+ Object* bias_object = global_context->fast_array_element_bias(); |
+ if (!bias_object->IsUndefined()) { |
+ int bias = Smi::cast(bias_object)->value(); |
+ if (to_kind == FAST_ELEMENTS) { |
+ bias += kFastElementArrayBiasIncrement; |
+ } else { |
+ ASSERT(to_kind == FAST_DOUBLE_ELEMENTS); |
+ bias += kFastSmiOnlyElementArrayBiasIncrement; |
+ } |
+ global_context->set_fast_array_element_bias(Smi::FromInt(bias)); |
+ if (bias > kFastElementArrayBiasThreshold) { |
+ JSFunction* array_function = global_context->array_function(); |
+ Map* untransitioned_map = Map::cast( |
+ global_context->untransitioned_js_array_map()); |
+ if (untransitioned_map == array_function->initial_map()) { |
+ if (untransitioned_map->elements_kind() == FAST_SMI_ONLY_ELEMENTS) { |
+ bool dummy; |
+ Map* transitioned_map = |
+ untransitioned_map->LookupElementsTransitionMap(FAST_ELEMENTS, |
+ &dummy); |
Jakob Kummerow
2012/01/04 20:55:17
nit: indentation
|
+ if (transitioned_map != NULL) { |
+ array_function->set_initial_map(transitioned_map); |
+ } |
+ } |
+ } |
+ } else if (bias < kFastSmiOnlyElementArrayBiasThreshold) { |
+ JSFunction* array_function = global_context->array_function(); |
+ Map* untransitioned_map = Map::cast( |
+ global_context->untransitioned_js_array_map()); |
+ if (!untransitioned_map->IsUndefined() && |
+ untransitioned_map != array_function->initial_map()) { |
+ bool dummy; |
+ Map* transitioned_map = |
+ untransitioned_map->LookupElementsTransitionMap(FAST_ELEMENTS, |
+ &dummy); |
+ if (transitioned_map == array_function->initial_map()) { |
+ array_function->set_initial_map(untransitioned_map); |
+ } |
+ } |
+ } |
+ } |
} |
} |
@@ -2183,13 +2256,7 @@ void Map::LookupInDescriptors(JSObject* holder, |
String* name, |
LookupResult* result) { |
DescriptorArray* descriptors = instance_descriptors(); |
- DescriptorLookupCache* cache = |
- GetHeap()->isolate()->descriptor_lookup_cache(); |
- int number = cache->Lookup(descriptors, name); |
- if (number == DescriptorLookupCache::kAbsent) { |
- number = descriptors->Search(name); |
- cache->Update(descriptors, name, number); |
- } |
+ int number = descriptors->SearchWithCache(name); |
if (number != DescriptorArray::kNotFound) { |
result->DescriptorResult(holder, descriptors->GetDetails(number), number); |
} else { |
@@ -2330,12 +2397,7 @@ Object* Map::GetDescriptorContents(String* sentinel_name, |
bool* safe_to_add_transition) { |
// Get the cached index for the descriptors lookup, or find and cache it. |
DescriptorArray* descriptors = instance_descriptors(); |
- DescriptorLookupCache* cache = GetIsolate()->descriptor_lookup_cache(); |
- int index = cache->Lookup(descriptors, sentinel_name); |
- if (index == DescriptorLookupCache::kAbsent) { |
- index = descriptors->Search(sentinel_name); |
- cache->Update(descriptors, sentinel_name, index); |
- } |
+ int index = descriptors->SearchWithCache(sentinel_name); |
// If the transition already exists, return its descriptor. |
if (index != DescriptorArray::kNotFound) { |
PropertyDetails details(descriptors->GetDetails(index)); |
@@ -8280,10 +8342,8 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength( |
break; |
} |
- if (FLAG_trace_elements_transitions) { |
- PrintElementsTransition(stdout, elements_kind, old_elements_raw, |
- FAST_ELEMENTS, new_elements); |
- } |
+ RecordElementsTransition(elements_kind, old_elements_raw, |
+ FAST_ELEMENTS, new_elements); |
// Update the length if necessary. |
if (IsJSArray()) { |
@@ -8336,10 +8396,8 @@ MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength( |
break; |
} |
- if (FLAG_trace_elements_transitions) { |
- PrintElementsTransition(stdout, elements_kind, old_elements, |
- FAST_DOUBLE_ELEMENTS, elems); |
- } |
+ RecordElementsTransition(elements_kind, old_elements, |
+ FAST_DOUBLE_ELEMENTS, elems); |
ASSERT(new_map->has_fast_double_elements()); |
set_map(new_map); |
@@ -9118,14 +9176,8 @@ MaybeObject* JSObject::SetFastElement(uint32_t index, |
} |
// Change elements kind from SMI_ONLY to generic FAST if necessary. |
if (HasFastSmiOnlyElements() && !value->IsSmi()) { |
- MaybeObject* maybe_new_map = GetElementsTransitionMap(FAST_ELEMENTS); |
- Map* new_map; |
- if (!maybe_new_map->To<Map>(&new_map)) return maybe_new_map; |
- set_map(new_map); |
- if (FLAG_trace_elements_transitions) { |
- PrintElementsTransition(stdout, FAST_SMI_ONLY_ELEMENTS, elements(), |
- FAST_ELEMENTS, elements()); |
- } |
+ MaybeObject* maybe = TransitionElementsKind(FAST_ELEMENTS); |
+ if (maybe->IsFailure()) return maybe; |
} |
// Increase backing store capacity if that's been decided previously. |
if (new_capacity != capacity) { |
@@ -9494,6 +9546,8 @@ MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, |
MUST_USE_RESULT MaybeObject* JSObject::TransitionElementsKind( |
ElementsKind to_kind) { |
ElementsKind from_kind = map()->elements_kind(); |
+ if (from_kind == to_kind) return this; |
+ |
FixedArrayBase* elms = FixedArrayBase::cast(elements()); |
uint32_t capacity = static_cast<uint32_t>(elms->length()); |
uint32_t length = capacity; |
@@ -9514,9 +9568,7 @@ MUST_USE_RESULT MaybeObject* JSObject::TransitionElementsKind( |
MaybeObject* maybe_new_map = GetElementsTransitionMap(to_kind); |
Map* new_map; |
if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
- if (FLAG_trace_elements_transitions) { |
- PrintElementsTransition(stdout, from_kind, elms, to_kind, elms); |
- } |
+ RecordElementsTransition(from_kind, elms, to_kind, elms); |
set_map(new_map); |
return this; |
} |