| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 323 | 323 |
| 324 former_start[to_trim] = Heap::fixed_array_map(); | 324 former_start[to_trim] = Heap::fixed_array_map(); |
| 325 former_start[to_trim + 1] = reinterpret_cast<Object*>(len - to_trim); | 325 former_start[to_trim + 1] = reinterpret_cast<Object*>(len - to_trim); |
| 326 | 326 |
| 327 ASSERT_EQ(elms->address() + to_trim * kPointerSize, | 327 ASSERT_EQ(elms->address() + to_trim * kPointerSize, |
| 328 (elms + to_trim * kPointerSize)->address()); | 328 (elms + to_trim * kPointerSize)->address()); |
| 329 return elms + to_trim * kPointerSize; | 329 return elms + to_trim * kPointerSize; |
| 330 } | 330 } |
| 331 | 331 |
| 332 | 332 |
| 333 static bool ArrayPrototypeHasNoElements() { | 333 static bool ArrayPrototypeHasNoElements(Context* global_context, |
| 334 JSObject* array_proto) { |
| 334 // This method depends on non writability of Object and Array prototype | 335 // This method depends on non writability of Object and Array prototype |
| 335 // fields. | 336 // fields. |
| 336 Context* global_context = Top::context()->global_context(); | 337 if (array_proto->elements() != Heap::empty_fixed_array()) return false; |
| 337 // Array.prototype | |
| 338 JSObject* proto = | |
| 339 JSObject::cast(global_context->array_function()->prototype()); | |
| 340 if (proto->elements() != Heap::empty_fixed_array()) return false; | |
| 341 // Hidden prototype | 338 // Hidden prototype |
| 342 proto = JSObject::cast(proto->GetPrototype()); | 339 array_proto = JSObject::cast(array_proto->GetPrototype()); |
| 343 ASSERT(proto->elements() == Heap::empty_fixed_array()); | 340 ASSERT(array_proto->elements() == Heap::empty_fixed_array()); |
| 344 // Object.prototype | 341 // Object.prototype |
| 345 proto = JSObject::cast(proto->GetPrototype()); | 342 array_proto = JSObject::cast(array_proto->GetPrototype()); |
| 346 if (proto != global_context->initial_object_prototype()) return false; | 343 if (array_proto != global_context->initial_object_prototype()) return false; |
| 347 if (proto->elements() != Heap::empty_fixed_array()) return false; | 344 if (array_proto->elements() != Heap::empty_fixed_array()) return false; |
| 348 ASSERT(proto->GetPrototype()->IsNull()); | 345 ASSERT(array_proto->GetPrototype()->IsNull()); |
| 349 return true; | 346 return true; |
| 350 } | 347 } |
| 351 | 348 |
| 352 | 349 |
| 353 static bool IsJSArrayWithFastElements(Object* receiver, | 350 static bool IsJSArrayWithFastElements(Object* receiver, |
| 354 FixedArray** elements) { | 351 FixedArray** elements) { |
| 355 if (!receiver->IsJSArray()) { | 352 if (!receiver->IsJSArray()) { |
| 356 return false; | 353 return false; |
| 357 } | 354 } |
| 358 | 355 |
| 359 JSArray* array = JSArray::cast(receiver); | 356 JSArray* array = JSArray::cast(receiver); |
| 360 | 357 |
| 361 HeapObject* elms = HeapObject::cast(array->elements()); | 358 HeapObject* elms = HeapObject::cast(array->elements()); |
| 362 if (elms->map() != Heap::fixed_array_map()) { | 359 if (elms->map() != Heap::fixed_array_map()) { |
| 363 return false; | 360 return false; |
| 364 } | 361 } |
| 365 | 362 |
| 366 *elements = FixedArray::cast(elms); | 363 *elements = FixedArray::cast(elms); |
| 367 return true; | 364 return true; |
| 368 } | 365 } |
| 369 | 366 |
| 370 | 367 |
| 368 static bool IsFastElementMovingAllowed(Object* receiver, |
| 369 FixedArray** elements) { |
| 370 if (!IsJSArrayWithFastElements(receiver, elements)) return false; |
| 371 |
| 372 Context* global_context = Top::context()->global_context(); |
| 373 JSObject* array_proto = |
| 374 JSObject::cast(global_context->array_function()->prototype()); |
| 375 if (JSArray::cast(receiver)->GetPrototype() != array_proto) return false; |
| 376 return ArrayPrototypeHasNoElements(global_context, array_proto); |
| 377 } |
| 378 |
| 379 |
| 371 static Object* CallJsBuiltin(const char* name, | 380 static Object* CallJsBuiltin(const char* name, |
| 372 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) { | 381 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) { |
| 373 HandleScope handleScope; | 382 HandleScope handleScope; |
| 374 | 383 |
| 375 Handle<Object> js_builtin = | 384 Handle<Object> js_builtin = |
| 376 GetProperty(Handle<JSObject>(Top::global_context()->builtins()), | 385 GetProperty(Handle<JSObject>(Top::global_context()->builtins()), |
| 377 name); | 386 name); |
| 378 ASSERT(js_builtin->IsJSFunction()); | 387 ASSERT(js_builtin->IsJSFunction()); |
| 379 Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin)); | 388 Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin)); |
| 380 ScopedVector<Object**> argv(args.length() - 1); | 389 ScopedVector<Object**> argv(args.length() - 1); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 458 | 467 |
| 459 // Set the length. | 468 // Set the length. |
| 460 array->set_length(Smi::FromInt(len - 1)); | 469 array->set_length(Smi::FromInt(len - 1)); |
| 461 | 470 |
| 462 if (!top->IsTheHole()) { | 471 if (!top->IsTheHole()) { |
| 463 // Delete the top element. | 472 // Delete the top element. |
| 464 elms->set_the_hole(len - 1); | 473 elms->set_the_hole(len - 1); |
| 465 return top; | 474 return top; |
| 466 } | 475 } |
| 467 | 476 |
| 468 // Remember to check the prototype chain. | 477 top = array->GetPrototype()->GetElement(len - 1); |
| 469 JSFunction* array_function = | |
| 470 Top::context()->global_context()->array_function(); | |
| 471 JSObject* prototype = JSObject::cast(array_function->prototype()); | |
| 472 top = prototype->GetElement(len - 1); | |
| 473 | 478 |
| 474 return top; | 479 return top; |
| 475 } | 480 } |
| 476 | 481 |
| 477 | 482 |
| 478 BUILTIN(ArrayShift) { | 483 BUILTIN(ArrayShift) { |
| 479 Object* receiver = *args.receiver(); | 484 Object* receiver = *args.receiver(); |
| 480 FixedArray* elms = NULL; | 485 FixedArray* elms = NULL; |
| 481 if (!IsJSArrayWithFastElements(receiver, &elms) | 486 if (!IsFastElementMovingAllowed(receiver, &elms)) { |
| 482 || !ArrayPrototypeHasNoElements()) { | |
| 483 return CallJsBuiltin("ArrayShift", args); | 487 return CallJsBuiltin("ArrayShift", args); |
| 484 } | 488 } |
| 485 JSArray* array = JSArray::cast(receiver); | 489 JSArray* array = JSArray::cast(receiver); |
| 486 ASSERT(array->HasFastElements()); | 490 ASSERT(array->HasFastElements()); |
| 487 | 491 |
| 488 int len = Smi::cast(array->length())->value(); | 492 int len = Smi::cast(array->length())->value(); |
| 489 if (len == 0) return Heap::undefined_value(); | 493 if (len == 0) return Heap::undefined_value(); |
| 490 | 494 |
| 491 // Get first element | 495 // Get first element |
| 492 Object* first = elms->get(0); | 496 Object* first = elms->get(0); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 508 // Set the length. | 512 // Set the length. |
| 509 array->set_length(Smi::FromInt(len - 1)); | 513 array->set_length(Smi::FromInt(len - 1)); |
| 510 | 514 |
| 511 return first; | 515 return first; |
| 512 } | 516 } |
| 513 | 517 |
| 514 | 518 |
| 515 BUILTIN(ArrayUnshift) { | 519 BUILTIN(ArrayUnshift) { |
| 516 Object* receiver = *args.receiver(); | 520 Object* receiver = *args.receiver(); |
| 517 FixedArray* elms = NULL; | 521 FixedArray* elms = NULL; |
| 518 if (!IsJSArrayWithFastElements(receiver, &elms) | 522 if (!IsFastElementMovingAllowed(receiver, &elms)) { |
| 519 || !ArrayPrototypeHasNoElements()) { | |
| 520 return CallJsBuiltin("ArrayUnshift", args); | 523 return CallJsBuiltin("ArrayUnshift", args); |
| 521 } | 524 } |
| 522 JSArray* array = JSArray::cast(receiver); | 525 JSArray* array = JSArray::cast(receiver); |
| 523 ASSERT(array->HasFastElements()); | 526 ASSERT(array->HasFastElements()); |
| 524 | 527 |
| 525 int len = Smi::cast(array->length())->value(); | 528 int len = Smi::cast(array->length())->value(); |
| 526 int to_add = args.length() - 1; | 529 int to_add = args.length() - 1; |
| 527 int new_length = len + to_add; | 530 int new_length = len + to_add; |
| 528 // Currently fixed arrays cannot grow too big, so | 531 // Currently fixed arrays cannot grow too big, so |
| 529 // we should never hit this case. | 532 // we should never hit this case. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 558 | 561 |
| 559 // Set the length. | 562 // Set the length. |
| 560 array->set_length(Smi::FromInt(new_length)); | 563 array->set_length(Smi::FromInt(new_length)); |
| 561 return Smi::FromInt(new_length); | 564 return Smi::FromInt(new_length); |
| 562 } | 565 } |
| 563 | 566 |
| 564 | 567 |
| 565 BUILTIN(ArraySlice) { | 568 BUILTIN(ArraySlice) { |
| 566 Object* receiver = *args.receiver(); | 569 Object* receiver = *args.receiver(); |
| 567 FixedArray* elms = NULL; | 570 FixedArray* elms = NULL; |
| 568 if (!IsJSArrayWithFastElements(receiver, &elms) | 571 if (!IsFastElementMovingAllowed(receiver, &elms)) { |
| 569 || !ArrayPrototypeHasNoElements()) { | |
| 570 return CallJsBuiltin("ArraySlice", args); | 572 return CallJsBuiltin("ArraySlice", args); |
| 571 } | 573 } |
| 572 JSArray* array = JSArray::cast(receiver); | 574 JSArray* array = JSArray::cast(receiver); |
| 573 ASSERT(array->HasFastElements()); | 575 ASSERT(array->HasFastElements()); |
| 574 | 576 |
| 575 int len = Smi::cast(array->length())->value(); | 577 int len = Smi::cast(array->length())->value(); |
| 576 | 578 |
| 577 int n_arguments = args.length() - 1; | 579 int n_arguments = args.length() - 1; |
| 578 | 580 |
| 579 // Note carefully choosen defaults---if argument is missing, | 581 // Note carefully choosen defaults---if argument is missing, |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 628 | 630 |
| 629 // Set the length. | 631 // Set the length. |
| 630 result_array->set_length(Smi::FromInt(result_len)); | 632 result_array->set_length(Smi::FromInt(result_len)); |
| 631 return result_array; | 633 return result_array; |
| 632 } | 634 } |
| 633 | 635 |
| 634 | 636 |
| 635 BUILTIN(ArraySplice) { | 637 BUILTIN(ArraySplice) { |
| 636 Object* receiver = *args.receiver(); | 638 Object* receiver = *args.receiver(); |
| 637 FixedArray* elms = NULL; | 639 FixedArray* elms = NULL; |
| 638 if (!IsJSArrayWithFastElements(receiver, &elms) | 640 if (!IsFastElementMovingAllowed(receiver, &elms)) { |
| 639 || !ArrayPrototypeHasNoElements()) { | |
| 640 return CallJsBuiltin("ArraySplice", args); | 641 return CallJsBuiltin("ArraySplice", args); |
| 641 } | 642 } |
| 642 JSArray* array = JSArray::cast(receiver); | 643 JSArray* array = JSArray::cast(receiver); |
| 643 ASSERT(array->HasFastElements()); | 644 ASSERT(array->HasFastElements()); |
| 644 | 645 |
| 645 int len = Smi::cast(array->length())->value(); | 646 int len = Smi::cast(array->length())->value(); |
| 646 | 647 |
| 647 int n_arguments = args.length() - 1; | 648 int n_arguments = args.length() - 1; |
| 648 | 649 |
| 649 // SpiderMonkey and JSC return undefined in the case where no | 650 // SpiderMonkey and JSC return undefined in the case where no |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 781 } | 782 } |
| 782 | 783 |
| 783 // Set the length. | 784 // Set the length. |
| 784 array->set_length(Smi::FromInt(new_length)); | 785 array->set_length(Smi::FromInt(new_length)); |
| 785 | 786 |
| 786 return result_array; | 787 return result_array; |
| 787 } | 788 } |
| 788 | 789 |
| 789 | 790 |
| 790 BUILTIN(ArrayConcat) { | 791 BUILTIN(ArrayConcat) { |
| 791 if (!ArrayPrototypeHasNoElements()) { | 792 Context* global_context = Top::context()->global_context(); |
| 793 JSObject* array_proto = |
| 794 JSObject::cast(global_context->array_function()->prototype()); |
| 795 if (!ArrayPrototypeHasNoElements(global_context, array_proto)) { |
| 792 return CallJsBuiltin("ArrayConcat", args); | 796 return CallJsBuiltin("ArrayConcat", args); |
| 793 } | 797 } |
| 794 | 798 |
| 795 // Iterate through all the arguments performing checks | 799 // Iterate through all the arguments performing checks |
| 796 // and calculating total length. | 800 // and calculating total length. |
| 797 int n_arguments = args.length(); | 801 int n_arguments = args.length(); |
| 798 int result_len = 0; | 802 int result_len = 0; |
| 799 for (int i = 0; i < n_arguments; i++) { | 803 for (int i = 0; i < n_arguments; i++) { |
| 800 Object* arg = args[i]; | 804 Object* arg = args[i]; |
| 801 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements()) { | 805 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements() |
| 806 || JSArray::cast(arg)->GetPrototype() != array_proto) { |
| 802 return CallJsBuiltin("ArrayConcat", args); | 807 return CallJsBuiltin("ArrayConcat", args); |
| 803 } | 808 } |
| 804 | 809 |
| 805 int len = Smi::cast(JSArray::cast(arg)->length())->value(); | 810 int len = Smi::cast(JSArray::cast(arg)->length())->value(); |
| 806 | 811 |
| 807 // We shouldn't overflow when adding another len. | 812 // We shouldn't overflow when adding another len. |
| 808 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); | 813 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); |
| 809 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); | 814 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); |
| 810 USE(kHalfOfMaxInt); | 815 USE(kHalfOfMaxInt); |
| 811 result_len += len; | 816 result_len += len; |
| (...skipping 690 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1502 if (entry->contains(pc)) { | 1507 if (entry->contains(pc)) { |
| 1503 return names_[i]; | 1508 return names_[i]; |
| 1504 } | 1509 } |
| 1505 } | 1510 } |
| 1506 } | 1511 } |
| 1507 return NULL; | 1512 return NULL; |
| 1508 } | 1513 } |
| 1509 | 1514 |
| 1510 | 1515 |
| 1511 } } // namespace v8::internal | 1516 } } // namespace v8::internal |
| OLD | NEW |