Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(55)

Side by Side Diff: src/objects.cc

Issue 9050001: Ensure newly allocated empty Arrays are transitioned to FAST_ELEMENT (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: fix existing and add new tests Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 1159 matching lines...) Expand 10 before | Expand all | Expand 10 after
1170 accumulator->Put('>'); 1170 accumulator->Put('>');
1171 break; 1171 break;
1172 } 1172 }
1173 } 1173 }
1174 } 1174 }
1175 1175
1176 1176
1177 void JSObject::PrintElementsTransition( 1177 void JSObject::PrintElementsTransition(
1178 FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements, 1178 FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements,
1179 ElementsKind to_kind, FixedArrayBase* to_elements) { 1179 ElementsKind to_kind, FixedArrayBase* to_elements) {
1180 PrintF(file, "elements transition [");
1181 PrintElementsKind(file, from_kind);
1182 PrintF(file, " -> ");
1183 PrintElementsKind(file, to_kind);
1184 PrintF(file, "] in ");
1185 JavaScriptFrame::PrintTop(file, false, true);
1186 PrintF(file, " for ");
1187 ShortPrint(file);
1188 PrintF(file, " from ");
1189 from_elements->ShortPrint(file);
1190 PrintF(file, " to ");
1191 to_elements->ShortPrint(file);
1192 PrintF(file, "\n");
1193 }
1194
1195 enum {
1196 kFastElementArrayBiasIncrement = 1,
1197 kFastElementArrayBiasThreshold = 3,
1198 kFastSmiOnlyElementArrayBiasIncrement = -10,
1199 kFastSmiOnlyElementArrayBiasThreshold = -30
1200 };
1201
1202
1203 void JSObject::RecordElementsTransition(
1204 ElementsKind from_kind, FixedArrayBase* from_elements,
1205 ElementsKind to_kind, FixedArrayBase* to_elements) {
1180 if (from_kind != to_kind) { 1206 if (from_kind != to_kind) {
1181 PrintF(file, "elements transition ["); 1207 if (FLAG_trace_elements_transitions) {
1182 PrintElementsKind(file, from_kind); 1208 PrintElementsTransition(stdout, from_kind, from_elements,
1183 PrintF(file, " -> "); 1209 to_kind, to_elements);
1184 PrintElementsKind(file, to_kind); 1210 }
1185 PrintF(file, "] in "); 1211 }
1186 JavaScriptFrame::PrintTop(file, false, true); 1212
1187 PrintF(file, " for "); 1213 // Use elements transitions to determine whether Array() should by default
1188 ShortPrint(file); 1214 // return an array of type FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS. Defaulting
1189 PrintF(file, " from "); 1215 // to FAST_ELEMENTS save the expense of element transition for code that
1190 from_elements->ShortPrint(file); 1216 // doesn't make use of double arrays. More FAST_ELEMENTS transitions than
1191 PrintF(file, " to "); 1217 // FAST_DOUBLE_ELEMENTS transitions suggest that Array() should always return
1192 to_elements->ShortPrint(file); 1218 // elements kinds of FAST_ELEMENTS. However, FAST_DOUBLE_ELEMENTS
1193 PrintF(file, "\n"); 1219 // transitions are weighted an order of magnitude heavier than FAST_ELEMENT
1220 // transitions, since the savings is in general much greater if the runtime
1221 // can recognize and exploit FAST_DOUBLE_ELEMENTS, even at the expense of
1222 // extra transitions.
1223 Context* global_context = GetIsolate()->context()->global_context();
1224 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()
1225 IsJSArray() && from_kind == FAST_SMI_ONLY_ELEMENTS) {
1226 Object* bias_object = global_context->fast_array_element_bias();
1227 if (!bias_object->IsUndefined()) {
1228 int bias = Smi::cast(bias_object)->value();
1229 if (to_kind == FAST_ELEMENTS) {
1230 bias += kFastElementArrayBiasIncrement;
1231 } else {
1232 ASSERT(to_kind == FAST_DOUBLE_ELEMENTS);
1233 bias += kFastSmiOnlyElementArrayBiasIncrement;
1234 }
1235 global_context->set_fast_array_element_bias(Smi::FromInt(bias));
1236 if (bias > kFastElementArrayBiasThreshold) {
1237 JSFunction* array_function = global_context->array_function();
1238 Map* untransitioned_map = Map::cast(
1239 global_context->untransitioned_js_array_map());
1240 if (untransitioned_map == array_function->initial_map()) {
1241 if (untransitioned_map->elements_kind() == FAST_SMI_ONLY_ELEMENTS) {
1242 bool dummy;
1243 Map* transitioned_map =
1244 untransitioned_map->LookupElementsTransitionMap(FAST_ELEMENTS,
1245 &dummy);
Jakob Kummerow 2012/01/04 20:55:17 nit: indentation
1246 if (transitioned_map != NULL) {
1247 array_function->set_initial_map(transitioned_map);
1248 }
1249 }
1250 }
1251 } else if (bias < kFastSmiOnlyElementArrayBiasThreshold) {
1252 JSFunction* array_function = global_context->array_function();
1253 Map* untransitioned_map = Map::cast(
1254 global_context->untransitioned_js_array_map());
1255 if (!untransitioned_map->IsUndefined() &&
1256 untransitioned_map != array_function->initial_map()) {
1257 bool dummy;
1258 Map* transitioned_map =
1259 untransitioned_map->LookupElementsTransitionMap(FAST_ELEMENTS,
1260 &dummy);
1261 if (transitioned_map == array_function->initial_map()) {
1262 array_function->set_initial_map(untransitioned_map);
1263 }
1264 }
1265 }
1266 }
1194 } 1267 }
1195 } 1268 }
1196 1269
1197 1270
1198 void HeapObject::HeapObjectShortPrint(StringStream* accumulator) { 1271 void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
1199 Heap* heap = GetHeap(); 1272 Heap* heap = GetHeap();
1200 if (!heap->Contains(this)) { 1273 if (!heap->Contains(this)) {
1201 accumulator->Add("!!!INVALID POINTER!!!"); 1274 accumulator->Add("!!!INVALID POINTER!!!");
1202 return; 1275 return;
1203 } 1276 }
(...skipping 972 matching lines...) Expand 10 before | Expand all | Expand 10 after
2176 } else { 2249 } else {
2177 result->NotFound(); 2250 result->NotFound();
2178 } 2251 }
2179 } 2252 }
2180 2253
2181 2254
2182 void Map::LookupInDescriptors(JSObject* holder, 2255 void Map::LookupInDescriptors(JSObject* holder,
2183 String* name, 2256 String* name,
2184 LookupResult* result) { 2257 LookupResult* result) {
2185 DescriptorArray* descriptors = instance_descriptors(); 2258 DescriptorArray* descriptors = instance_descriptors();
2186 DescriptorLookupCache* cache = 2259 int number = descriptors->SearchWithCache(name);
2187 GetHeap()->isolate()->descriptor_lookup_cache();
2188 int number = cache->Lookup(descriptors, name);
2189 if (number == DescriptorLookupCache::kAbsent) {
2190 number = descriptors->Search(name);
2191 cache->Update(descriptors, name, number);
2192 }
2193 if (number != DescriptorArray::kNotFound) { 2260 if (number != DescriptorArray::kNotFound) {
2194 result->DescriptorResult(holder, descriptors->GetDetails(number), number); 2261 result->DescriptorResult(holder, descriptors->GetDetails(number), number);
2195 } else { 2262 } else {
2196 result->NotFound(); 2263 result->NotFound();
2197 } 2264 }
2198 } 2265 }
2199 2266
2200 2267
2201 static bool ContainsMap(MapHandleList* maps, Handle<Map> map) { 2268 static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
2202 ASSERT(!map.is_null()); 2269 ASSERT(!map.is_null());
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
2323 2390
2324 String* Map::elements_transition_sentinel_name() { 2391 String* Map::elements_transition_sentinel_name() {
2325 return GetHeap()->empty_symbol(); 2392 return GetHeap()->empty_symbol();
2326 } 2393 }
2327 2394
2328 2395
2329 Object* Map::GetDescriptorContents(String* sentinel_name, 2396 Object* Map::GetDescriptorContents(String* sentinel_name,
2330 bool* safe_to_add_transition) { 2397 bool* safe_to_add_transition) {
2331 // Get the cached index for the descriptors lookup, or find and cache it. 2398 // Get the cached index for the descriptors lookup, or find and cache it.
2332 DescriptorArray* descriptors = instance_descriptors(); 2399 DescriptorArray* descriptors = instance_descriptors();
2333 DescriptorLookupCache* cache = GetIsolate()->descriptor_lookup_cache(); 2400 int index = descriptors->SearchWithCache(sentinel_name);
2334 int index = cache->Lookup(descriptors, sentinel_name);
2335 if (index == DescriptorLookupCache::kAbsent) {
2336 index = descriptors->Search(sentinel_name);
2337 cache->Update(descriptors, sentinel_name, index);
2338 }
2339 // If the transition already exists, return its descriptor. 2401 // If the transition already exists, return its descriptor.
2340 if (index != DescriptorArray::kNotFound) { 2402 if (index != DescriptorArray::kNotFound) {
2341 PropertyDetails details(descriptors->GetDetails(index)); 2403 PropertyDetails details(descriptors->GetDetails(index));
2342 if (details.type() == ELEMENTS_TRANSITION) { 2404 if (details.type() == ELEMENTS_TRANSITION) {
2343 return descriptors->GetValue(index); 2405 return descriptors->GetValue(index);
2344 } else { 2406 } else {
2345 *safe_to_add_transition = false; 2407 *safe_to_add_transition = false;
2346 } 2408 }
2347 } 2409 }
2348 return NULL; 2410 return NULL;
(...skipping 5924 matching lines...) Expand 10 before | Expand all | Expand 10 after
8273 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 8335 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8274 case EXTERNAL_INT_ELEMENTS: 8336 case EXTERNAL_INT_ELEMENTS:
8275 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 8337 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
8276 case EXTERNAL_FLOAT_ELEMENTS: 8338 case EXTERNAL_FLOAT_ELEMENTS:
8277 case EXTERNAL_DOUBLE_ELEMENTS: 8339 case EXTERNAL_DOUBLE_ELEMENTS:
8278 case EXTERNAL_PIXEL_ELEMENTS: 8340 case EXTERNAL_PIXEL_ELEMENTS:
8279 UNREACHABLE(); 8341 UNREACHABLE();
8280 break; 8342 break;
8281 } 8343 }
8282 8344
8283 if (FLAG_trace_elements_transitions) { 8345 RecordElementsTransition(elements_kind, old_elements_raw,
8284 PrintElementsTransition(stdout, elements_kind, old_elements_raw, 8346 FAST_ELEMENTS, new_elements);
8285 FAST_ELEMENTS, new_elements);
8286 }
8287 8347
8288 // Update the length if necessary. 8348 // Update the length if necessary.
8289 if (IsJSArray()) { 8349 if (IsJSArray()) {
8290 JSArray::cast(this)->set_length(Smi::FromInt(length)); 8350 JSArray::cast(this)->set_length(Smi::FromInt(length));
8291 } 8351 }
8292 8352
8293 return new_elements; 8353 return new_elements;
8294 } 8354 }
8295 8355
8296 8356
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
8329 } 8389 }
8330 case DICTIONARY_ELEMENTS: { 8390 case DICTIONARY_ELEMENTS: {
8331 elems->Initialize(NumberDictionary::cast(old_elements)); 8391 elems->Initialize(NumberDictionary::cast(old_elements));
8332 break; 8392 break;
8333 } 8393 }
8334 default: 8394 default:
8335 UNREACHABLE(); 8395 UNREACHABLE();
8336 break; 8396 break;
8337 } 8397 }
8338 8398
8339 if (FLAG_trace_elements_transitions) { 8399 RecordElementsTransition(elements_kind, old_elements,
8340 PrintElementsTransition(stdout, elements_kind, old_elements, 8400 FAST_DOUBLE_ELEMENTS, elems);
8341 FAST_DOUBLE_ELEMENTS, elems);
8342 }
8343 8401
8344 ASSERT(new_map->has_fast_double_elements()); 8402 ASSERT(new_map->has_fast_double_elements());
8345 set_map(new_map); 8403 set_map(new_map);
8346 ASSERT(elems->IsFixedDoubleArray()); 8404 ASSERT(elems->IsFixedDoubleArray());
8347 set_elements(elems); 8405 set_elements(elems);
8348 8406
8349 if (IsJSArray()) { 8407 if (IsJSArray()) {
8350 JSArray::cast(this)->set_length(Smi::FromInt(length)); 8408 JSArray::cast(this)->set_length(Smi::FromInt(length));
8351 } 8409 }
8352 8410
(...skipping 758 matching lines...) Expand 10 before | Expand all | Expand 10 after
9111 // Convert to fast double elements if appropriate. 9169 // Convert to fast double elements if appropriate.
9112 if (HasFastSmiOnlyElements() && !value->IsSmi() && value->IsNumber()) { 9170 if (HasFastSmiOnlyElements() && !value->IsSmi() && value->IsNumber()) {
9113 MaybeObject* maybe = 9171 MaybeObject* maybe =
9114 SetFastDoubleElementsCapacityAndLength(new_capacity, array_length); 9172 SetFastDoubleElementsCapacityAndLength(new_capacity, array_length);
9115 if (maybe->IsFailure()) return maybe; 9173 if (maybe->IsFailure()) return maybe;
9116 FixedDoubleArray::cast(elements())->set(index, value->Number()); 9174 FixedDoubleArray::cast(elements())->set(index, value->Number());
9117 return value; 9175 return value;
9118 } 9176 }
9119 // Change elements kind from SMI_ONLY to generic FAST if necessary. 9177 // Change elements kind from SMI_ONLY to generic FAST if necessary.
9120 if (HasFastSmiOnlyElements() && !value->IsSmi()) { 9178 if (HasFastSmiOnlyElements() && !value->IsSmi()) {
9121 MaybeObject* maybe_new_map = GetElementsTransitionMap(FAST_ELEMENTS); 9179 MaybeObject* maybe = TransitionElementsKind(FAST_ELEMENTS);
9122 Map* new_map; 9180 if (maybe->IsFailure()) return maybe;
9123 if (!maybe_new_map->To<Map>(&new_map)) return maybe_new_map;
9124 set_map(new_map);
9125 if (FLAG_trace_elements_transitions) {
9126 PrintElementsTransition(stdout, FAST_SMI_ONLY_ELEMENTS, elements(),
9127 FAST_ELEMENTS, elements());
9128 }
9129 } 9181 }
9130 // Increase backing store capacity if that's been decided previously. 9182 // Increase backing store capacity if that's been decided previously.
9131 if (new_capacity != capacity) { 9183 if (new_capacity != capacity) {
9132 Object* new_elements; 9184 Object* new_elements;
9133 SetFastElementsCapacityMode set_capacity_mode = 9185 SetFastElementsCapacityMode set_capacity_mode =
9134 value->IsSmi() && HasFastSmiOnlyElements() 9186 value->IsSmi() && HasFastSmiOnlyElements()
9135 ? kAllowSmiOnlyElements 9187 ? kAllowSmiOnlyElements
9136 : kDontAllowSmiOnlyElements; 9188 : kDontAllowSmiOnlyElements;
9137 MaybeObject* maybe = 9189 MaybeObject* maybe =
9138 SetFastElementsCapacityAndLength(new_capacity, 9190 SetFastElementsCapacityAndLength(new_capacity,
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after
9487 // All possible cases have been handled above. Add a return to avoid the 9539 // All possible cases have been handled above. Add a return to avoid the
9488 // complaints from the compiler. 9540 // complaints from the compiler.
9489 UNREACHABLE(); 9541 UNREACHABLE();
9490 return isolate->heap()->null_value(); 9542 return isolate->heap()->null_value();
9491 } 9543 }
9492 9544
9493 9545
9494 MUST_USE_RESULT MaybeObject* JSObject::TransitionElementsKind( 9546 MUST_USE_RESULT MaybeObject* JSObject::TransitionElementsKind(
9495 ElementsKind to_kind) { 9547 ElementsKind to_kind) {
9496 ElementsKind from_kind = map()->elements_kind(); 9548 ElementsKind from_kind = map()->elements_kind();
9549 if (from_kind == to_kind) return this;
9550
9497 FixedArrayBase* elms = FixedArrayBase::cast(elements()); 9551 FixedArrayBase* elms = FixedArrayBase::cast(elements());
9498 uint32_t capacity = static_cast<uint32_t>(elms->length()); 9552 uint32_t capacity = static_cast<uint32_t>(elms->length());
9499 uint32_t length = capacity; 9553 uint32_t length = capacity;
9500 9554
9501 if (IsJSArray()) { 9555 if (IsJSArray()) {
9502 Object* raw_length = JSArray::cast(this)->length(); 9556 Object* raw_length = JSArray::cast(this)->length();
9503 if (raw_length->IsUndefined()) { 9557 if (raw_length->IsUndefined()) {
9504 // If length is undefined, then JSArray is being initialized and has no 9558 // If length is undefined, then JSArray is being initialized and has no
9505 // elements, assume a length of zero. 9559 // elements, assume a length of zero.
9506 length = 0; 9560 length = 0;
9507 } else { 9561 } else {
9508 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length)); 9562 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
9509 } 9563 }
9510 } 9564 }
9511 9565
9512 if ((from_kind == FAST_SMI_ONLY_ELEMENTS && to_kind == FAST_ELEMENTS) || 9566 if ((from_kind == FAST_SMI_ONLY_ELEMENTS && to_kind == FAST_ELEMENTS) ||
9513 (length == 0)) { 9567 (length == 0)) {
9514 MaybeObject* maybe_new_map = GetElementsTransitionMap(to_kind); 9568 MaybeObject* maybe_new_map = GetElementsTransitionMap(to_kind);
9515 Map* new_map; 9569 Map* new_map;
9516 if (!maybe_new_map->To(&new_map)) return maybe_new_map; 9570 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9517 if (FLAG_trace_elements_transitions) { 9571 RecordElementsTransition(from_kind, elms, to_kind, elms);
9518 PrintElementsTransition(stdout, from_kind, elms, to_kind, elms);
9519 }
9520 set_map(new_map); 9572 set_map(new_map);
9521 return this; 9573 return this;
9522 } 9574 }
9523 9575
9524 if (from_kind == FAST_SMI_ONLY_ELEMENTS && 9576 if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9525 to_kind == FAST_DOUBLE_ELEMENTS) { 9577 to_kind == FAST_DOUBLE_ELEMENTS) {
9526 MaybeObject* maybe_result = 9578 MaybeObject* maybe_result =
9527 SetFastDoubleElementsCapacityAndLength(capacity, length); 9579 SetFastDoubleElementsCapacityAndLength(capacity, length);
9528 if (maybe_result->IsFailure()) return maybe_result; 9580 if (maybe_result->IsFailure()) return maybe_result;
9529 return this; 9581 return this;
(...skipping 3042 matching lines...) Expand 10 before | Expand all | Expand 10 after
12572 if (break_point_objects()->IsUndefined()) return 0; 12624 if (break_point_objects()->IsUndefined()) return 0;
12573 // Single break point. 12625 // Single break point.
12574 if (!break_point_objects()->IsFixedArray()) return 1; 12626 if (!break_point_objects()->IsFixedArray()) return 1;
12575 // Multiple break points. 12627 // Multiple break points.
12576 return FixedArray::cast(break_point_objects())->length(); 12628 return FixedArray::cast(break_point_objects())->length();
12577 } 12629 }
12578 #endif // ENABLE_DEBUGGER_SUPPORT 12630 #endif // ENABLE_DEBUGGER_SUPPORT
12579 12631
12580 12632
12581 } } // namespace v8::internal 12633 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698