| 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 |