OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |