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

Side by Side Diff: src/runtime.cc

Issue 6240012: Optimize calls to object literal properties that are initialized with a funct... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 9 years, 10 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
« src/ia32/lithium-codegen-ia32.cc ('K') | « src/parser.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 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 274 matching lines...) Expand 10 before | Expand all | Expand 10 after
285 285
286 286
287 static Handle<Object> CreateLiteralBoilerplate( 287 static Handle<Object> CreateLiteralBoilerplate(
288 Handle<FixedArray> literals, 288 Handle<FixedArray> literals,
289 Handle<FixedArray> constant_properties); 289 Handle<FixedArray> constant_properties);
290 290
291 291
292 static Handle<Object> CreateObjectLiteralBoilerplate( 292 static Handle<Object> CreateObjectLiteralBoilerplate(
293 Handle<FixedArray> literals, 293 Handle<FixedArray> literals,
294 Handle<FixedArray> constant_properties, 294 Handle<FixedArray> constant_properties,
295 bool should_have_fast_elements) { 295 bool should_have_fast_elements,
296 bool has_function_literal) {
296 // Get the global context from the literals array. This is the 297 // Get the global context from the literals array. This is the
297 // context in which the function was created and we use the object 298 // context in which the function was created and we use the object
298 // function from this context to create the object literal. We do 299 // function from this context to create the object literal. We do
299 // not use the object function from the current global context 300 // not use the object function from the current global context
300 // because this might be the object function from another context 301 // because this might be the object function from another context
301 // which we should not have access to. 302 // which we should not have access to.
302 Handle<Context> context = 303 Handle<Context> context =
303 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals)); 304 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
304 305
305 bool is_result_from_cache; 306 // In case we have function literals, we want the object to be in
306 Handle<Map> map = ComputeObjectLiteralMap(context, 307 // slow properties mode for now and we don't go in the map cache.
Mads Ager (chromium) 2011/02/01 13:51:00 Please expand the comment to say that we cannot sh
fschneider 2011/02/02 10:18:38 Done.
307 constant_properties, 308 bool is_result_from_cache = false;
308 &is_result_from_cache); 309 Handle<Map> map = has_function_literal
310 ? Handle<Map>(context->object_function()->initial_map())
311 : ComputeObjectLiteralMap(context,
312 constant_properties,
313 &is_result_from_cache);
309 314
310 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map); 315 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
311 316
312 // Normalize the elements of the boilerplate to save space if needed. 317 // Normalize the elements of the boilerplate to save space if needed.
313 if (!should_have_fast_elements) NormalizeElements(boilerplate); 318 if (!should_have_fast_elements) NormalizeElements(boilerplate);
314 319
315 { // Add the constant properties to the boilerplate. 320 // Add the constant properties to the boilerplate.
316 int length = constant_properties->length(); 321 int length = constant_properties->length();
317 OptimizedObjectForAddingMultipleProperties opt(boilerplate, 322 bool should_transform =
318 length / 2, 323 !is_result_from_cache && boilerplate->HasFastProperties();
319 !is_result_from_cache); 324 if (should_transform || has_function_literal) {
320 for (int index = 0; index < length; index +=2) { 325 // Normalize the properties of object to avoid n^2 behavior
321 Handle<Object> key(constant_properties->get(index+0)); 326 // when extending the object multiple properties. Indicate the number of
322 Handle<Object> value(constant_properties->get(index+1)); 327 // properties to be added.
323 if (value->IsFixedArray()) { 328 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
324 // The value contains the constant_properties of a 329 }
325 // simple object literal. 330
326 Handle<FixedArray> array = Handle<FixedArray>::cast(value); 331 for (int index = 0; index < length; index +=2) {
327 value = CreateLiteralBoilerplate(literals, array); 332 Handle<Object> key(constant_properties->get(index+0));
328 if (value.is_null()) return value; 333 Handle<Object> value(constant_properties->get(index+1));
329 } 334 if (value->IsFixedArray()) {
330 Handle<Object> result; 335 // The value contains the constant_properties of a
331 uint32_t element_index = 0; 336 // simple object or array literal.
332 if (key->IsSymbol()) { 337 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
333 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) { 338 value = CreateLiteralBoilerplate(literals, array);
334 // Array index as string (uint32). 339 if (value.is_null()) return value;
335 result = SetOwnElement(boilerplate, element_index, value); 340 }
336 } else { 341 Handle<Object> result;
337 Handle<String> name(String::cast(*key)); 342 uint32_t element_index = 0;
338 ASSERT(!name->AsArrayIndex(&element_index)); 343 if (key->IsSymbol()) {
339 result = SetLocalPropertyIgnoreAttributes(boilerplate, name, 344 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
340 value, NONE); 345 // Array index as string (uint32).
341 }
342 } else if (key->ToArrayIndex(&element_index)) {
343 // Array index (uint32).
344 result = SetOwnElement(boilerplate, element_index, value); 346 result = SetOwnElement(boilerplate, element_index, value);
345 } else { 347 } else {
346 // Non-uint32 number. 348 Handle<String> name(String::cast(*key));
347 ASSERT(key->IsNumber()); 349 ASSERT(!name->AsArrayIndex(&element_index));
348 double num = key->Number();
349 char arr[100];
350 Vector<char> buffer(arr, ARRAY_SIZE(arr));
351 const char* str = DoubleToCString(num, buffer);
352 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
353 result = SetLocalPropertyIgnoreAttributes(boilerplate, name, 350 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
354 value, NONE); 351 value, NONE);
355 } 352 }
356 // If setting the property on the boilerplate throws an 353 } else if (key->ToArrayIndex(&element_index)) {
357 // exception, the exception is converted to an empty handle in 354 // Array index (uint32).
358 // the handle based operations. In that case, we need to 355 result = SetOwnElement(boilerplate, element_index, value);
359 // convert back to an exception. 356 } else {
360 if (result.is_null()) return result; 357 // Non-uint32 number.
358 ASSERT(key->IsNumber());
359 double num = key->Number();
360 char arr[100];
361 Vector<char> buffer(arr, ARRAY_SIZE(arr));
362 const char* str = DoubleToCString(num, buffer);
363 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
364 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
365 value, NONE);
361 } 366 }
367 // If setting the property on the boilerplate throws an
368 // exception, the exception is converted to an empty handle in
369 // the handle based operations. In that case, we need to
370 // convert back to an exception.
371 if (result.is_null()) return result;
372 }
373
374 // Transform to fast properties if necessary. For object literals with
375 // containing function literals we defer this operation until after all
376 // computed properties have been assigned so that we can generate
377 // constant function properties.
378 if (should_transform && !has_function_literal) {
379 TransformToFastProperties(boilerplate,
380 boilerplate->map()->unused_property_fields());
362 } 381 }
363 382
364 return boilerplate; 383 return boilerplate;
365 } 384 }
366 385
367 386
368 static Handle<Object> CreateArrayLiteralBoilerplate( 387 static Handle<Object> CreateArrayLiteralBoilerplate(
369 Handle<FixedArray> literals, 388 Handle<FixedArray> literals,
370 Handle<FixedArray> elements) { 389 Handle<FixedArray> elements) {
371 // Create the JSArray. 390 // Create the JSArray.
(...skipping 10 matching lines...) Expand all
382 #ifdef DEBUG 401 #ifdef DEBUG
383 // Copy-on-write arrays must be shallow (and simple). 402 // Copy-on-write arrays must be shallow (and simple).
384 for (int i = 0; i < content->length(); i++) { 403 for (int i = 0; i < content->length(); i++) {
385 ASSERT(!content->get(i)->IsFixedArray()); 404 ASSERT(!content->get(i)->IsFixedArray());
386 } 405 }
387 #endif 406 #endif
388 } else { 407 } else {
389 for (int i = 0; i < content->length(); i++) { 408 for (int i = 0; i < content->length(); i++) {
390 if (content->get(i)->IsFixedArray()) { 409 if (content->get(i)->IsFixedArray()) {
391 // The value contains the constant_properties of a 410 // The value contains the constant_properties of a
392 // simple object literal. 411 // simple object or array literal.
393 Handle<FixedArray> fa(FixedArray::cast(content->get(i))); 412 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
394 Handle<Object> result = 413 Handle<Object> result =
395 CreateLiteralBoilerplate(literals, fa); 414 CreateLiteralBoilerplate(literals, fa);
396 if (result.is_null()) return result; 415 if (result.is_null()) return result;
397 content->set(i, *result); 416 content->set(i, *result);
398 } 417 }
399 } 418 }
400 } 419 }
401 420
402 // Set the elements. 421 // Set the elements.
403 Handle<JSArray>::cast(object)->SetContent(*content); 422 Handle<JSArray>::cast(object)->SetContent(*content);
404 return object; 423 return object;
405 } 424 }
406 425
407 426
408 static Handle<Object> CreateLiteralBoilerplate( 427 static Handle<Object> CreateLiteralBoilerplate(
409 Handle<FixedArray> literals, 428 Handle<FixedArray> literals,
410 Handle<FixedArray> array) { 429 Handle<FixedArray> array) {
411 Handle<FixedArray> elements = CompileTimeValue::GetElements(array); 430 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
412 switch (CompileTimeValue::GetType(array)) { 431 switch (CompileTimeValue::GetType(array)) {
413 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS: 432 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
414 return CreateObjectLiteralBoilerplate(literals, elements, true); 433 return CreateObjectLiteralBoilerplate(literals, elements, true, false);
415 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS: 434 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
416 return CreateObjectLiteralBoilerplate(literals, elements, false); 435 return CreateObjectLiteralBoilerplate(literals, elements, false, false);
417 case CompileTimeValue::ARRAY_LITERAL: 436 case CompileTimeValue::ARRAY_LITERAL:
418 return CreateArrayLiteralBoilerplate(literals, elements); 437 return CreateArrayLiteralBoilerplate(literals, elements);
419 default: 438 default:
420 UNREACHABLE(); 439 UNREACHABLE();
421 return Handle<Object>::null(); 440 return Handle<Object>::null();
422 } 441 }
423 } 442 }
424 443
425 444
426 static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) { 445 static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
(...skipping 16 matching lines...) Expand all
443 return *object; 462 return *object;
444 } 463 }
445 464
446 465
447 static MaybeObject* Runtime_CreateObjectLiteral(Arguments args) { 466 static MaybeObject* Runtime_CreateObjectLiteral(Arguments args) {
448 HandleScope scope; 467 HandleScope scope;
449 ASSERT(args.length() == 4); 468 ASSERT(args.length() == 4);
450 CONVERT_ARG_CHECKED(FixedArray, literals, 0); 469 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
451 CONVERT_SMI_CHECKED(literals_index, args[1]); 470 CONVERT_SMI_CHECKED(literals_index, args[1]);
452 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); 471 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
453 CONVERT_SMI_CHECKED(fast_elements, args[3]); 472 CONVERT_SMI_CHECKED(flags, args[3]);
454 bool should_have_fast_elements = fast_elements == 1; 473 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
474 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
455 475
456 // Check if boilerplate exists. If not, create it first. 476 // Check if boilerplate exists. If not, create it first.
457 Handle<Object> boilerplate(literals->get(literals_index)); 477 Handle<Object> boilerplate(literals->get(literals_index));
458 if (*boilerplate == Heap::undefined_value()) { 478 if (*boilerplate == Heap::undefined_value()) {
459 boilerplate = CreateObjectLiteralBoilerplate(literals, 479 boilerplate = CreateObjectLiteralBoilerplate(literals,
460 constant_properties, 480 constant_properties,
461 should_have_fast_elements); 481 should_have_fast_elements,
482 has_function_literal);
462 if (boilerplate.is_null()) return Failure::Exception(); 483 if (boilerplate.is_null()) return Failure::Exception();
463 // Update the functions literal and return the boilerplate. 484 // Update the functions literal and return the boilerplate.
464 literals->set(literals_index, *boilerplate); 485 literals->set(literals_index, *boilerplate);
465 } 486 }
466 return DeepCopyBoilerplate(JSObject::cast(*boilerplate)); 487 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
467 } 488 }
468 489
469 490
470 static MaybeObject* Runtime_CreateObjectLiteralShallow(Arguments args) { 491 static MaybeObject* Runtime_CreateObjectLiteralShallow(Arguments args) {
471 HandleScope scope; 492 HandleScope scope;
472 ASSERT(args.length() == 4); 493 ASSERT(args.length() == 4);
473 CONVERT_ARG_CHECKED(FixedArray, literals, 0); 494 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
474 CONVERT_SMI_CHECKED(literals_index, args[1]); 495 CONVERT_SMI_CHECKED(literals_index, args[1]);
475 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); 496 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
476 CONVERT_SMI_CHECKED(fast_elements, args[3]); 497 CONVERT_SMI_CHECKED(flags, args[3]);
477 bool should_have_fast_elements = fast_elements == 1; 498 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
499 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
478 500
479 // Check if boilerplate exists. If not, create it first. 501 // Check if boilerplate exists. If not, create it first.
480 Handle<Object> boilerplate(literals->get(literals_index)); 502 Handle<Object> boilerplate(literals->get(literals_index));
481 if (*boilerplate == Heap::undefined_value()) { 503 if (*boilerplate == Heap::undefined_value()) {
482 boilerplate = CreateObjectLiteralBoilerplate(literals, 504 boilerplate = CreateObjectLiteralBoilerplate(literals,
483 constant_properties, 505 constant_properties,
484 should_have_fast_elements); 506 should_have_fast_elements,
507 has_function_literal);
485 if (boilerplate.is_null()) return Failure::Exception(); 508 if (boilerplate.is_null()) return Failure::Exception();
486 // Update the functions literal and return the boilerplate. 509 // Update the functions literal and return the boilerplate.
487 literals->set(literals_index, *boilerplate); 510 literals->set(literals_index, *boilerplate);
488 } 511 }
489 return Heap::CopyJSObject(JSObject::cast(*boilerplate)); 512 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
490 } 513 }
491 514
492 515
493 static MaybeObject* Runtime_CreateArrayLiteral(Arguments args) { 516 static MaybeObject* Runtime_CreateArrayLiteral(Arguments args) {
494 HandleScope scope; 517 HandleScope scope;
(...skipping 10375 matching lines...) Expand 10 before | Expand all | Expand 10 after
10870 } else { 10893 } else {
10871 // Handle last resort GC and make sure to allow future allocations 10894 // Handle last resort GC and make sure to allow future allocations
10872 // to grow the heap without causing GCs (if possible). 10895 // to grow the heap without causing GCs (if possible).
10873 Counters::gc_last_resort_from_js.Increment(); 10896 Counters::gc_last_resort_from_js.Increment();
10874 Heap::CollectAllGarbage(false); 10897 Heap::CollectAllGarbage(false);
10875 } 10898 }
10876 } 10899 }
10877 10900
10878 10901
10879 } } // namespace v8::internal 10902 } } // namespace v8::internal
OLDNEW
« src/ia32/lithium-codegen-ia32.cc ('K') | « src/parser.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698