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. We don't go in the map cache because |
307 constant_properties, | 308 // maps with constant functions can't be shared if the functions are |
308 &is_result_from_cache); | 309 // not the same (which is the common case). |
| 310 bool is_result_from_cache = false; |
| 311 Handle<Map> map = has_function_literal |
| 312 ? Handle<Map>(context->object_function()->initial_map()) |
| 313 : ComputeObjectLiteralMap(context, |
| 314 constant_properties, |
| 315 &is_result_from_cache); |
309 | 316 |
310 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map); | 317 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map); |
311 | 318 |
312 // Normalize the elements of the boilerplate to save space if needed. | 319 // Normalize the elements of the boilerplate to save space if needed. |
313 if (!should_have_fast_elements) NormalizeElements(boilerplate); | 320 if (!should_have_fast_elements) NormalizeElements(boilerplate); |
314 | 321 |
315 { // Add the constant properties to the boilerplate. | 322 // Add the constant properties to the boilerplate. |
316 int length = constant_properties->length(); | 323 int length = constant_properties->length(); |
317 OptimizedObjectForAddingMultipleProperties opt(boilerplate, | 324 bool should_transform = |
318 length / 2, | 325 !is_result_from_cache && boilerplate->HasFastProperties(); |
319 !is_result_from_cache); | 326 if (should_transform || has_function_literal) { |
320 for (int index = 0; index < length; index +=2) { | 327 // Normalize the properties of object to avoid n^2 behavior |
321 Handle<Object> key(constant_properties->get(index+0)); | 328 // when extending the object multiple properties. Indicate the number of |
322 Handle<Object> value(constant_properties->get(index+1)); | 329 // properties to be added. |
323 if (value->IsFixedArray()) { | 330 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2); |
324 // The value contains the constant_properties of a | 331 } |
325 // simple object literal. | 332 |
326 Handle<FixedArray> array = Handle<FixedArray>::cast(value); | 333 for (int index = 0; index < length; index +=2) { |
327 value = CreateLiteralBoilerplate(literals, array); | 334 Handle<Object> key(constant_properties->get(index+0)); |
328 if (value.is_null()) return value; | 335 Handle<Object> value(constant_properties->get(index+1)); |
329 } | 336 if (value->IsFixedArray()) { |
330 Handle<Object> result; | 337 // The value contains the constant_properties of a |
331 uint32_t element_index = 0; | 338 // simple object or array literal. |
332 if (key->IsSymbol()) { | 339 Handle<FixedArray> array = Handle<FixedArray>::cast(value); |
333 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) { | 340 value = CreateLiteralBoilerplate(literals, array); |
334 // Array index as string (uint32). | 341 if (value.is_null()) return value; |
335 result = SetOwnElement(boilerplate, element_index, value); | 342 } |
336 } else { | 343 Handle<Object> result; |
337 Handle<String> name(String::cast(*key)); | 344 uint32_t element_index = 0; |
338 ASSERT(!name->AsArrayIndex(&element_index)); | 345 if (key->IsSymbol()) { |
339 result = SetLocalPropertyIgnoreAttributes(boilerplate, name, | 346 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) { |
340 value, NONE); | 347 // Array index as string (uint32). |
341 } | |
342 } else if (key->ToArrayIndex(&element_index)) { | |
343 // Array index (uint32). | |
344 result = SetOwnElement(boilerplate, element_index, value); | 348 result = SetOwnElement(boilerplate, element_index, value); |
345 } else { | 349 } else { |
346 // Non-uint32 number. | 350 Handle<String> name(String::cast(*key)); |
347 ASSERT(key->IsNumber()); | 351 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, | 352 result = SetLocalPropertyIgnoreAttributes(boilerplate, name, |
354 value, NONE); | 353 value, NONE); |
355 } | 354 } |
356 // If setting the property on the boilerplate throws an | 355 } else if (key->ToArrayIndex(&element_index)) { |
357 // exception, the exception is converted to an empty handle in | 356 // Array index (uint32). |
358 // the handle based operations. In that case, we need to | 357 result = SetOwnElement(boilerplate, element_index, value); |
359 // convert back to an exception. | 358 } else { |
360 if (result.is_null()) return result; | 359 // Non-uint32 number. |
| 360 ASSERT(key->IsNumber()); |
| 361 double num = key->Number(); |
| 362 char arr[100]; |
| 363 Vector<char> buffer(arr, ARRAY_SIZE(arr)); |
| 364 const char* str = DoubleToCString(num, buffer); |
| 365 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str)); |
| 366 result = SetLocalPropertyIgnoreAttributes(boilerplate, name, |
| 367 value, NONE); |
361 } | 368 } |
| 369 // If setting the property on the boilerplate throws an |
| 370 // exception, the exception is converted to an empty handle in |
| 371 // the handle based operations. In that case, we need to |
| 372 // convert back to an exception. |
| 373 if (result.is_null()) return result; |
| 374 } |
| 375 |
| 376 // Transform to fast properties if necessary. For object literals with |
| 377 // containing function literals we defer this operation until after all |
| 378 // computed properties have been assigned so that we can generate |
| 379 // constant function properties. |
| 380 if (should_transform && !has_function_literal) { |
| 381 TransformToFastProperties(boilerplate, |
| 382 boilerplate->map()->unused_property_fields()); |
362 } | 383 } |
363 | 384 |
364 return boilerplate; | 385 return boilerplate; |
365 } | 386 } |
366 | 387 |
367 | 388 |
368 static Handle<Object> CreateArrayLiteralBoilerplate( | 389 static Handle<Object> CreateArrayLiteralBoilerplate( |
369 Handle<FixedArray> literals, | 390 Handle<FixedArray> literals, |
370 Handle<FixedArray> elements) { | 391 Handle<FixedArray> elements) { |
371 // Create the JSArray. | 392 // Create the JSArray. |
(...skipping 10 matching lines...) Expand all Loading... |
382 #ifdef DEBUG | 403 #ifdef DEBUG |
383 // Copy-on-write arrays must be shallow (and simple). | 404 // Copy-on-write arrays must be shallow (and simple). |
384 for (int i = 0; i < content->length(); i++) { | 405 for (int i = 0; i < content->length(); i++) { |
385 ASSERT(!content->get(i)->IsFixedArray()); | 406 ASSERT(!content->get(i)->IsFixedArray()); |
386 } | 407 } |
387 #endif | 408 #endif |
388 } else { | 409 } else { |
389 for (int i = 0; i < content->length(); i++) { | 410 for (int i = 0; i < content->length(); i++) { |
390 if (content->get(i)->IsFixedArray()) { | 411 if (content->get(i)->IsFixedArray()) { |
391 // The value contains the constant_properties of a | 412 // The value contains the constant_properties of a |
392 // simple object literal. | 413 // simple object or array literal. |
393 Handle<FixedArray> fa(FixedArray::cast(content->get(i))); | 414 Handle<FixedArray> fa(FixedArray::cast(content->get(i))); |
394 Handle<Object> result = | 415 Handle<Object> result = |
395 CreateLiteralBoilerplate(literals, fa); | 416 CreateLiteralBoilerplate(literals, fa); |
396 if (result.is_null()) return result; | 417 if (result.is_null()) return result; |
397 content->set(i, *result); | 418 content->set(i, *result); |
398 } | 419 } |
399 } | 420 } |
400 } | 421 } |
401 | 422 |
402 // Set the elements. | 423 // Set the elements. |
403 Handle<JSArray>::cast(object)->SetContent(*content); | 424 Handle<JSArray>::cast(object)->SetContent(*content); |
404 return object; | 425 return object; |
405 } | 426 } |
406 | 427 |
407 | 428 |
408 static Handle<Object> CreateLiteralBoilerplate( | 429 static Handle<Object> CreateLiteralBoilerplate( |
409 Handle<FixedArray> literals, | 430 Handle<FixedArray> literals, |
410 Handle<FixedArray> array) { | 431 Handle<FixedArray> array) { |
411 Handle<FixedArray> elements = CompileTimeValue::GetElements(array); | 432 Handle<FixedArray> elements = CompileTimeValue::GetElements(array); |
412 switch (CompileTimeValue::GetType(array)) { | 433 switch (CompileTimeValue::GetType(array)) { |
413 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS: | 434 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS: |
414 return CreateObjectLiteralBoilerplate(literals, elements, true); | 435 return CreateObjectLiteralBoilerplate(literals, elements, true, false); |
415 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS: | 436 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS: |
416 return CreateObjectLiteralBoilerplate(literals, elements, false); | 437 return CreateObjectLiteralBoilerplate(literals, elements, false, false); |
417 case CompileTimeValue::ARRAY_LITERAL: | 438 case CompileTimeValue::ARRAY_LITERAL: |
418 return CreateArrayLiteralBoilerplate(literals, elements); | 439 return CreateArrayLiteralBoilerplate(literals, elements); |
419 default: | 440 default: |
420 UNREACHABLE(); | 441 UNREACHABLE(); |
421 return Handle<Object>::null(); | 442 return Handle<Object>::null(); |
422 } | 443 } |
423 } | 444 } |
424 | 445 |
425 | 446 |
426 static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) { | 447 static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) { |
(...skipping 16 matching lines...) Expand all Loading... |
443 return *object; | 464 return *object; |
444 } | 465 } |
445 | 466 |
446 | 467 |
447 static MaybeObject* Runtime_CreateObjectLiteral(Arguments args) { | 468 static MaybeObject* Runtime_CreateObjectLiteral(Arguments args) { |
448 HandleScope scope; | 469 HandleScope scope; |
449 ASSERT(args.length() == 4); | 470 ASSERT(args.length() == 4); |
450 CONVERT_ARG_CHECKED(FixedArray, literals, 0); | 471 CONVERT_ARG_CHECKED(FixedArray, literals, 0); |
451 CONVERT_SMI_CHECKED(literals_index, args[1]); | 472 CONVERT_SMI_CHECKED(literals_index, args[1]); |
452 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); | 473 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); |
453 CONVERT_SMI_CHECKED(fast_elements, args[3]); | 474 CONVERT_SMI_CHECKED(flags, args[3]); |
454 bool should_have_fast_elements = fast_elements == 1; | 475 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0; |
| 476 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0; |
455 | 477 |
456 // Check if boilerplate exists. If not, create it first. | 478 // Check if boilerplate exists. If not, create it first. |
457 Handle<Object> boilerplate(literals->get(literals_index)); | 479 Handle<Object> boilerplate(literals->get(literals_index)); |
458 if (*boilerplate == Heap::undefined_value()) { | 480 if (*boilerplate == Heap::undefined_value()) { |
459 boilerplate = CreateObjectLiteralBoilerplate(literals, | 481 boilerplate = CreateObjectLiteralBoilerplate(literals, |
460 constant_properties, | 482 constant_properties, |
461 should_have_fast_elements); | 483 should_have_fast_elements, |
| 484 has_function_literal); |
462 if (boilerplate.is_null()) return Failure::Exception(); | 485 if (boilerplate.is_null()) return Failure::Exception(); |
463 // Update the functions literal and return the boilerplate. | 486 // Update the functions literal and return the boilerplate. |
464 literals->set(literals_index, *boilerplate); | 487 literals->set(literals_index, *boilerplate); |
465 } | 488 } |
466 return DeepCopyBoilerplate(JSObject::cast(*boilerplate)); | 489 return DeepCopyBoilerplate(JSObject::cast(*boilerplate)); |
467 } | 490 } |
468 | 491 |
469 | 492 |
470 static MaybeObject* Runtime_CreateObjectLiteralShallow(Arguments args) { | 493 static MaybeObject* Runtime_CreateObjectLiteralShallow(Arguments args) { |
471 HandleScope scope; | 494 HandleScope scope; |
472 ASSERT(args.length() == 4); | 495 ASSERT(args.length() == 4); |
473 CONVERT_ARG_CHECKED(FixedArray, literals, 0); | 496 CONVERT_ARG_CHECKED(FixedArray, literals, 0); |
474 CONVERT_SMI_CHECKED(literals_index, args[1]); | 497 CONVERT_SMI_CHECKED(literals_index, args[1]); |
475 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); | 498 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); |
476 CONVERT_SMI_CHECKED(fast_elements, args[3]); | 499 CONVERT_SMI_CHECKED(flags, args[3]); |
477 bool should_have_fast_elements = fast_elements == 1; | 500 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0; |
| 501 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0; |
478 | 502 |
479 // Check if boilerplate exists. If not, create it first. | 503 // Check if boilerplate exists. If not, create it first. |
480 Handle<Object> boilerplate(literals->get(literals_index)); | 504 Handle<Object> boilerplate(literals->get(literals_index)); |
481 if (*boilerplate == Heap::undefined_value()) { | 505 if (*boilerplate == Heap::undefined_value()) { |
482 boilerplate = CreateObjectLiteralBoilerplate(literals, | 506 boilerplate = CreateObjectLiteralBoilerplate(literals, |
483 constant_properties, | 507 constant_properties, |
484 should_have_fast_elements); | 508 should_have_fast_elements, |
| 509 has_function_literal); |
485 if (boilerplate.is_null()) return Failure::Exception(); | 510 if (boilerplate.is_null()) return Failure::Exception(); |
486 // Update the functions literal and return the boilerplate. | 511 // Update the functions literal and return the boilerplate. |
487 literals->set(literals_index, *boilerplate); | 512 literals->set(literals_index, *boilerplate); |
488 } | 513 } |
489 return Heap::CopyJSObject(JSObject::cast(*boilerplate)); | 514 return Heap::CopyJSObject(JSObject::cast(*boilerplate)); |
490 } | 515 } |
491 | 516 |
492 | 517 |
493 static MaybeObject* Runtime_CreateArrayLiteral(Arguments args) { | 518 static MaybeObject* Runtime_CreateArrayLiteral(Arguments args) { |
494 HandleScope scope; | 519 HandleScope scope; |
(...skipping 10375 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10870 } else { | 10895 } else { |
10871 // Handle last resort GC and make sure to allow future allocations | 10896 // Handle last resort GC and make sure to allow future allocations |
10872 // to grow the heap without causing GCs (if possible). | 10897 // to grow the heap without causing GCs (if possible). |
10873 Counters::gc_last_resort_from_js.Increment(); | 10898 Counters::gc_last_resort_from_js.Increment(); |
10874 Heap::CollectAllGarbage(false); | 10899 Heap::CollectAllGarbage(false); |
10875 } | 10900 } |
10876 } | 10901 } |
10877 | 10902 |
10878 | 10903 |
10879 } } // namespace v8::internal | 10904 } } // namespace v8::internal |
OLD | NEW |