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 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 static Handle<Object> CreateLiteralBoilerplate( | 297 static Handle<Object> CreateLiteralBoilerplate( |
298 Isolate* isolate, | 298 Isolate* isolate, |
299 Handle<FixedArray> literals, | 299 Handle<FixedArray> literals, |
300 Handle<FixedArray> constant_properties); | 300 Handle<FixedArray> constant_properties); |
301 | 301 |
302 | 302 |
303 static Handle<Object> CreateObjectLiteralBoilerplate( | 303 static Handle<Object> CreateObjectLiteralBoilerplate( |
304 Isolate* isolate, | 304 Isolate* isolate, |
305 Handle<FixedArray> literals, | 305 Handle<FixedArray> literals, |
306 Handle<FixedArray> constant_properties, | 306 Handle<FixedArray> constant_properties, |
307 bool should_have_fast_elements) { | 307 bool should_have_fast_elements, |
| 308 bool has_function_literal) { |
308 // Get the global context from the literals array. This is the | 309 // Get the global context from the literals array. This is the |
309 // context in which the function was created and we use the object | 310 // context in which the function was created and we use the object |
310 // function from this context to create the object literal. We do | 311 // function from this context to create the object literal. We do |
311 // not use the object function from the current global context | 312 // not use the object function from the current global context |
312 // because this might be the object function from another context | 313 // because this might be the object function from another context |
313 // which we should not have access to. | 314 // which we should not have access to. |
314 Handle<Context> context = | 315 Handle<Context> context = |
315 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals)); | 316 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals)); |
316 | 317 |
317 bool is_result_from_cache; | 318 // In case we have function literals, we want the object to be in |
318 Handle<Map> map = ComputeObjectLiteralMap(context, | 319 // slow properties mode for now. We don't go in the map cache because |
319 constant_properties, | 320 // maps with constant functions can't be shared if the functions are |
320 &is_result_from_cache); | 321 // not the same (which is the common case). |
| 322 bool is_result_from_cache = false; |
| 323 Handle<Map> map = has_function_literal |
| 324 ? Handle<Map>(context->object_function()->initial_map()) |
| 325 : ComputeObjectLiteralMap(context, |
| 326 constant_properties, |
| 327 &is_result_from_cache); |
321 | 328 |
322 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map); | 329 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map); |
323 | 330 |
324 // Normalize the elements of the boilerplate to save space if needed. | 331 // Normalize the elements of the boilerplate to save space if needed. |
325 if (!should_have_fast_elements) NormalizeElements(boilerplate); | 332 if (!should_have_fast_elements) NormalizeElements(boilerplate); |
326 | 333 |
327 { // Add the constant properties to the boilerplate. | 334 // Add the constant properties to the boilerplate. |
328 int length = constant_properties->length(); | 335 int length = constant_properties->length(); |
329 OptimizedObjectForAddingMultipleProperties opt(boilerplate, | 336 bool should_transform = |
330 length / 2, | 337 !is_result_from_cache && boilerplate->HasFastProperties(); |
331 !is_result_from_cache); | 338 if (should_transform || has_function_literal) { |
332 for (int index = 0; index < length; index +=2) { | 339 // Normalize the properties of object to avoid n^2 behavior |
333 Handle<Object> key(constant_properties->get(index+0), isolate); | 340 // when extending the object multiple properties. Indicate the number of |
334 Handle<Object> value(constant_properties->get(index+1), isolate); | 341 // properties to be added. |
335 if (value->IsFixedArray()) { | 342 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2); |
336 // The value contains the constant_properties of a | 343 } |
337 // simple object literal. | 344 |
338 Handle<FixedArray> array = Handle<FixedArray>::cast(value); | 345 for (int index = 0; index < length; index +=2) { |
339 value = CreateLiteralBoilerplate(isolate, literals, array); | 346 Handle<Object> key(constant_properties->get(index+0), isolate); |
340 if (value.is_null()) return value; | 347 Handle<Object> value(constant_properties->get(index+1), isolate); |
341 } | 348 if (value->IsFixedArray()) { |
342 Handle<Object> result; | 349 // The value contains the constant_properties of a |
343 uint32_t element_index = 0; | 350 // simple object or array literal. |
344 if (key->IsSymbol()) { | 351 Handle<FixedArray> array = Handle<FixedArray>::cast(value); |
345 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) { | 352 value = CreateLiteralBoilerplate(isolate, literals, array); |
346 // Array index as string (uint32). | 353 if (value.is_null()) return value; |
347 result = SetOwnElement(boilerplate, | 354 } |
348 element_index, | 355 Handle<Object> result; |
349 value, | 356 uint32_t element_index = 0; |
350 kNonStrictMode); | 357 if (key->IsSymbol()) { |
351 } else { | 358 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) { |
352 Handle<String> name(String::cast(*key)); | 359 // Array index as string (uint32). |
353 ASSERT(!name->AsArrayIndex(&element_index)); | |
354 result = SetLocalPropertyIgnoreAttributes(boilerplate, name, | |
355 value, NONE); | |
356 } | |
357 } else if (key->ToArrayIndex(&element_index)) { | |
358 // Array index (uint32). | |
359 result = SetOwnElement(boilerplate, | 360 result = SetOwnElement(boilerplate, |
360 element_index, | 361 element_index, |
361 value, | 362 value, |
362 kNonStrictMode); | 363 kNonStrictMode); |
363 } else { | 364 } else { |
364 // Non-uint32 number. | 365 Handle<String> name(String::cast(*key)); |
365 ASSERT(key->IsNumber()); | 366 ASSERT(!name->AsArrayIndex(&element_index)); |
366 double num = key->Number(); | |
367 char arr[100]; | |
368 Vector<char> buffer(arr, ARRAY_SIZE(arr)); | |
369 const char* str = DoubleToCString(num, buffer); | |
370 Handle<String> name = | |
371 isolate->factory()->NewStringFromAscii(CStrVector(str)); | |
372 result = SetLocalPropertyIgnoreAttributes(boilerplate, name, | 367 result = SetLocalPropertyIgnoreAttributes(boilerplate, name, |
373 value, NONE); | 368 value, NONE); |
374 } | 369 } |
375 // If setting the property on the boilerplate throws an | 370 } else if (key->ToArrayIndex(&element_index)) { |
376 // exception, the exception is converted to an empty handle in | 371 // Array index (uint32). |
377 // the handle based operations. In that case, we need to | 372 result = SetOwnElement(boilerplate, |
378 // convert back to an exception. | 373 element_index, |
379 if (result.is_null()) return result; | 374 value, |
| 375 kNonStrictMode); |
| 376 } else { |
| 377 // Non-uint32 number. |
| 378 ASSERT(key->IsNumber()); |
| 379 double num = key->Number(); |
| 380 char arr[100]; |
| 381 Vector<char> buffer(arr, ARRAY_SIZE(arr)); |
| 382 const char* str = DoubleToCString(num, buffer); |
| 383 Handle<String> name = |
| 384 isolate->factory()->NewStringFromAscii(CStrVector(str)); |
| 385 result = SetLocalPropertyIgnoreAttributes(boilerplate, name, |
| 386 value, NONE); |
380 } | 387 } |
| 388 // If setting the property on the boilerplate throws an |
| 389 // exception, the exception is converted to an empty handle in |
| 390 // the handle based operations. In that case, we need to |
| 391 // convert back to an exception. |
| 392 if (result.is_null()) return result; |
| 393 } |
| 394 |
| 395 // Transform to fast properties if necessary. For object literals with |
| 396 // containing function literals we defer this operation until after all |
| 397 // computed properties have been assigned so that we can generate |
| 398 // constant function properties. |
| 399 if (should_transform && !has_function_literal) { |
| 400 TransformToFastProperties(boilerplate, |
| 401 boilerplate->map()->unused_property_fields()); |
381 } | 402 } |
382 | 403 |
383 return boilerplate; | 404 return boilerplate; |
384 } | 405 } |
385 | 406 |
386 | 407 |
387 static Handle<Object> CreateArrayLiteralBoilerplate( | 408 static Handle<Object> CreateArrayLiteralBoilerplate( |
388 Isolate* isolate, | 409 Isolate* isolate, |
389 Handle<FixedArray> literals, | 410 Handle<FixedArray> literals, |
390 Handle<FixedArray> elements) { | 411 Handle<FixedArray> elements) { |
(...skipping 12 matching lines...) Expand all Loading... |
403 #ifdef DEBUG | 424 #ifdef DEBUG |
404 // Copy-on-write arrays must be shallow (and simple). | 425 // Copy-on-write arrays must be shallow (and simple). |
405 for (int i = 0; i < content->length(); i++) { | 426 for (int i = 0; i < content->length(); i++) { |
406 ASSERT(!content->get(i)->IsFixedArray()); | 427 ASSERT(!content->get(i)->IsFixedArray()); |
407 } | 428 } |
408 #endif | 429 #endif |
409 } else { | 430 } else { |
410 for (int i = 0; i < content->length(); i++) { | 431 for (int i = 0; i < content->length(); i++) { |
411 if (content->get(i)->IsFixedArray()) { | 432 if (content->get(i)->IsFixedArray()) { |
412 // The value contains the constant_properties of a | 433 // The value contains the constant_properties of a |
413 // simple object literal. | 434 // simple object or array literal. |
414 Handle<FixedArray> fa(FixedArray::cast(content->get(i))); | 435 Handle<FixedArray> fa(FixedArray::cast(content->get(i))); |
415 Handle<Object> result = | 436 Handle<Object> result = |
416 CreateLiteralBoilerplate(isolate, literals, fa); | 437 CreateLiteralBoilerplate(isolate, literals, fa); |
417 if (result.is_null()) return result; | 438 if (result.is_null()) return result; |
418 content->set(i, *result); | 439 content->set(i, *result); |
419 } | 440 } |
420 } | 441 } |
421 } | 442 } |
422 | 443 |
423 // Set the elements. | 444 // Set the elements. |
424 Handle<JSArray>::cast(object)->SetContent(*content); | 445 Handle<JSArray>::cast(object)->SetContent(*content); |
425 return object; | 446 return object; |
426 } | 447 } |
427 | 448 |
428 | 449 |
429 static Handle<Object> CreateLiteralBoilerplate( | 450 static Handle<Object> CreateLiteralBoilerplate( |
430 Isolate* isolate, | 451 Isolate* isolate, |
431 Handle<FixedArray> literals, | 452 Handle<FixedArray> literals, |
432 Handle<FixedArray> array) { | 453 Handle<FixedArray> array) { |
433 Handle<FixedArray> elements = CompileTimeValue::GetElements(array); | 454 Handle<FixedArray> elements = CompileTimeValue::GetElements(array); |
| 455 const bool kHasNoFunctionLiteral = false; |
434 switch (CompileTimeValue::GetType(array)) { | 456 switch (CompileTimeValue::GetType(array)) { |
435 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS: | 457 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS: |
436 return CreateObjectLiteralBoilerplate(isolate, literals, elements, true); | 458 return CreateObjectLiteralBoilerplate(isolate, |
| 459 literals, |
| 460 elements, |
| 461 true, |
| 462 kHasNoFunctionLiteral); |
437 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS: | 463 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS: |
438 return CreateObjectLiteralBoilerplate(isolate, literals, elements, false); | 464 return CreateObjectLiteralBoilerplate(isolate, |
| 465 literals, |
| 466 elements, |
| 467 false, |
| 468 kHasNoFunctionLiteral); |
439 case CompileTimeValue::ARRAY_LITERAL: | 469 case CompileTimeValue::ARRAY_LITERAL: |
440 return CreateArrayLiteralBoilerplate(isolate, literals, elements); | 470 return CreateArrayLiteralBoilerplate(isolate, literals, elements); |
441 default: | 471 default: |
442 UNREACHABLE(); | 472 UNREACHABLE(); |
443 return Handle<Object>::null(); | 473 return Handle<Object>::null(); |
444 } | 474 } |
445 } | 475 } |
446 | 476 |
447 | 477 |
448 static MaybeObject* Runtime_CreateArrayLiteralBoilerplate( | 478 static MaybeObject* Runtime_CreateArrayLiteralBoilerplate( |
(...skipping 20 matching lines...) Expand all Loading... |
469 } | 499 } |
470 | 500 |
471 | 501 |
472 static MaybeObject* Runtime_CreateObjectLiteral(RUNTIME_CALLING_CONVENTION) { | 502 static MaybeObject* Runtime_CreateObjectLiteral(RUNTIME_CALLING_CONVENTION) { |
473 RUNTIME_GET_ISOLATE; | 503 RUNTIME_GET_ISOLATE; |
474 HandleScope scope(isolate); | 504 HandleScope scope(isolate); |
475 ASSERT(args.length() == 4); | 505 ASSERT(args.length() == 4); |
476 CONVERT_ARG_CHECKED(FixedArray, literals, 0); | 506 CONVERT_ARG_CHECKED(FixedArray, literals, 0); |
477 CONVERT_SMI_CHECKED(literals_index, args[1]); | 507 CONVERT_SMI_CHECKED(literals_index, args[1]); |
478 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); | 508 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); |
479 CONVERT_SMI_CHECKED(fast_elements, args[3]); | 509 CONVERT_SMI_CHECKED(flags, args[3]); |
480 bool should_have_fast_elements = fast_elements == 1; | 510 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0; |
| 511 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0; |
481 | 512 |
482 // Check if boilerplate exists. If not, create it first. | 513 // Check if boilerplate exists. If not, create it first. |
483 Handle<Object> boilerplate(literals->get(literals_index), isolate); | 514 Handle<Object> boilerplate(literals->get(literals_index), isolate); |
484 if (*boilerplate == isolate->heap()->undefined_value()) { | 515 if (*boilerplate == isolate->heap()->undefined_value()) { |
485 boilerplate = CreateObjectLiteralBoilerplate(isolate, | 516 boilerplate = CreateObjectLiteralBoilerplate(isolate, |
486 literals, | 517 literals, |
487 constant_properties, | 518 constant_properties, |
488 should_have_fast_elements); | 519 should_have_fast_elements, |
| 520 has_function_literal); |
489 if (boilerplate.is_null()) return Failure::Exception(); | 521 if (boilerplate.is_null()) return Failure::Exception(); |
490 // Update the functions literal and return the boilerplate. | 522 // Update the functions literal and return the boilerplate. |
491 literals->set(literals_index, *boilerplate); | 523 literals->set(literals_index, *boilerplate); |
492 } | 524 } |
493 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate)); | 525 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate)); |
494 } | 526 } |
495 | 527 |
496 | 528 |
497 static MaybeObject* Runtime_CreateObjectLiteralShallow( | 529 static MaybeObject* Runtime_CreateObjectLiteralShallow( |
498 RUNTIME_CALLING_CONVENTION) { | 530 RUNTIME_CALLING_CONVENTION) { |
499 RUNTIME_GET_ISOLATE; | 531 RUNTIME_GET_ISOLATE; |
500 HandleScope scope(isolate); | 532 HandleScope scope(isolate); |
501 ASSERT(args.length() == 4); | 533 ASSERT(args.length() == 4); |
502 CONVERT_ARG_CHECKED(FixedArray, literals, 0); | 534 CONVERT_ARG_CHECKED(FixedArray, literals, 0); |
503 CONVERT_SMI_CHECKED(literals_index, args[1]); | 535 CONVERT_SMI_CHECKED(literals_index, args[1]); |
504 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); | 536 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2); |
505 CONVERT_SMI_CHECKED(fast_elements, args[3]); | 537 CONVERT_SMI_CHECKED(flags, args[3]); |
506 bool should_have_fast_elements = fast_elements == 1; | 538 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0; |
| 539 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0; |
507 | 540 |
508 // Check if boilerplate exists. If not, create it first. | 541 // Check if boilerplate exists. If not, create it first. |
509 Handle<Object> boilerplate(literals->get(literals_index), isolate); | 542 Handle<Object> boilerplate(literals->get(literals_index), isolate); |
510 if (*boilerplate == isolate->heap()->undefined_value()) { | 543 if (*boilerplate == isolate->heap()->undefined_value()) { |
511 boilerplate = CreateObjectLiteralBoilerplate(isolate, | 544 boilerplate = CreateObjectLiteralBoilerplate(isolate, |
512 literals, | 545 literals, |
513 constant_properties, | 546 constant_properties, |
514 should_have_fast_elements); | 547 should_have_fast_elements, |
| 548 has_function_literal); |
515 if (boilerplate.is_null()) return Failure::Exception(); | 549 if (boilerplate.is_null()) return Failure::Exception(); |
516 // Update the functions literal and return the boilerplate. | 550 // Update the functions literal and return the boilerplate. |
517 literals->set(literals_index, *boilerplate); | 551 literals->set(literals_index, *boilerplate); |
518 } | 552 } |
519 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate)); | 553 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate)); |
520 } | 554 } |
521 | 555 |
522 | 556 |
523 static MaybeObject* Runtime_CreateArrayLiteral(RUNTIME_CALLING_CONVENTION) { | 557 static MaybeObject* Runtime_CreateArrayLiteral(RUNTIME_CALLING_CONVENTION) { |
524 RUNTIME_GET_ISOLATE; | 558 RUNTIME_GET_ISOLATE; |
(...skipping 11666 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12191 } else { | 12225 } else { |
12192 // Handle last resort GC and make sure to allow future allocations | 12226 // Handle last resort GC and make sure to allow future allocations |
12193 // to grow the heap without causing GCs (if possible). | 12227 // to grow the heap without causing GCs (if possible). |
12194 COUNTERS->gc_last_resort_from_js()->Increment(); | 12228 COUNTERS->gc_last_resort_from_js()->Increment(); |
12195 HEAP->CollectAllGarbage(false); | 12229 HEAP->CollectAllGarbage(false); |
12196 } | 12230 } |
12197 } | 12231 } |
12198 | 12232 |
12199 | 12233 |
12200 } } // namespace v8::internal | 12234 } } // namespace v8::internal |
OLD | NEW |