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 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
312 ASSERT(proto->elements() == Heap::empty_fixed_array()); | 312 ASSERT(proto->elements() == Heap::empty_fixed_array()); |
313 // Object.prototype | 313 // Object.prototype |
314 proto = JSObject::cast(proto->GetPrototype()); | 314 proto = JSObject::cast(proto->GetPrototype()); |
315 if (proto != global_context->initial_object_prototype()) return false; | 315 if (proto != global_context->initial_object_prototype()) return false; |
316 if (proto->elements() != Heap::empty_fixed_array()) return false; | 316 if (proto->elements() != Heap::empty_fixed_array()) return false; |
317 ASSERT(proto->GetPrototype()->IsNull()); | 317 ASSERT(proto->GetPrototype()->IsNull()); |
318 return true; | 318 return true; |
319 } | 319 } |
320 | 320 |
321 | 321 |
| 322 static bool IsJSArrayWithFastElements(Object* receiver, |
| 323 FixedArray** elements) { |
| 324 if (!receiver->IsJSArray()) { |
| 325 return false; |
| 326 } |
| 327 |
| 328 JSArray* array = JSArray::cast(receiver); |
| 329 |
| 330 HeapObject* elms = HeapObject::cast(array->elements()); |
| 331 if (elms->map() != Heap::fixed_array_map()) { |
| 332 return false; |
| 333 } |
| 334 |
| 335 *elements = FixedArray::cast(elms); |
| 336 return true; |
| 337 } |
| 338 |
| 339 |
322 static Object* CallJsBuiltin(const char* name, | 340 static Object* CallJsBuiltin(const char* name, |
323 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) { | 341 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) { |
324 HandleScope handleScope; | 342 HandleScope handleScope; |
325 | 343 |
326 Handle<Object> js_builtin = | 344 Handle<Object> js_builtin = |
327 GetProperty(Handle<JSObject>(Top::global_context()->builtins()), | 345 GetProperty(Handle<JSObject>(Top::global_context()->builtins()), |
328 name); | 346 name); |
329 ASSERT(js_builtin->IsJSFunction()); | 347 ASSERT(js_builtin->IsJSFunction()); |
330 Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin)); | 348 Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin)); |
331 Vector<Object**> argv(Vector<Object**>::New(args.length() - 1)); | 349 Vector<Object**> argv(Vector<Object**>::New(args.length() - 1)); |
332 int n_args = args.length() - 1; | 350 int n_args = args.length() - 1; |
333 for (int i = 0; i < n_args; i++) { | 351 for (int i = 0; i < n_args; i++) { |
334 argv[i] = &args[i + 1]; | 352 argv[i] = args.at<Object>(i + 1).location(); |
335 } | 353 } |
336 bool pending_exception = false; | 354 bool pending_exception = false; |
337 Handle<Object> result = Execution::Call(function, | 355 Handle<Object> result = Execution::Call(function, |
338 args.receiver(), | 356 args.receiver(), |
339 n_args, | 357 n_args, |
340 argv.start(), | 358 argv.start(), |
341 &pending_exception); | 359 &pending_exception); |
342 argv.Dispose(); | 360 argv.Dispose(); |
343 if (pending_exception) return Failure::Exception(); | 361 if (pending_exception) return Failure::Exception(); |
344 return *result; | 362 return *result; |
345 } | 363 } |
346 | 364 |
347 | 365 |
348 BUILTIN(ArrayPush) { | 366 BUILTIN(ArrayPush) { |
349 JSArray* array = JSArray::cast(*args.receiver()); | 367 Object* receiver = *args.receiver(); |
350 ASSERT(array->HasFastElements()); | 368 FixedArray* elms = NULL; |
| 369 if (!IsJSArrayWithFastElements(receiver, &elms)) { |
| 370 return CallJsBuiltin("ArrayPush", args); |
| 371 } |
| 372 JSArray* array = JSArray::cast(receiver); |
351 | 373 |
352 int len = Smi::cast(array->length())->value(); | 374 int len = Smi::cast(array->length())->value(); |
353 int to_add = args.length() - 1; | 375 int to_add = args.length() - 1; |
354 if (to_add == 0) { | 376 if (to_add == 0) { |
355 return Smi::FromInt(len); | 377 return Smi::FromInt(len); |
356 } | 378 } |
357 // Currently fixed arrays cannot grow too big, so | 379 // Currently fixed arrays cannot grow too big, so |
358 // we should never hit this case. | 380 // we should never hit this case. |
359 ASSERT(to_add <= (Smi::kMaxValue - len)); | 381 ASSERT(to_add <= (Smi::kMaxValue - len)); |
360 | 382 |
361 int new_length = len + to_add; | 383 int new_length = len + to_add; |
362 FixedArray* elms = FixedArray::cast(array->elements()); | |
363 | 384 |
364 if (new_length > elms->length()) { | 385 if (new_length > elms->length()) { |
365 // New backing storage is needed. | 386 // New backing storage is needed. |
366 int capacity = new_length + (new_length >> 1) + 16; | 387 int capacity = new_length + (new_length >> 1) + 16; |
367 Object* obj = Heap::AllocateUninitializedFixedArray(capacity); | 388 Object* obj = Heap::AllocateUninitializedFixedArray(capacity); |
368 if (obj->IsFailure()) return obj; | 389 if (obj->IsFailure()) return obj; |
369 FixedArray* new_elms = FixedArray::cast(obj); | 390 FixedArray* new_elms = FixedArray::cast(obj); |
370 | 391 |
371 AssertNoAllocation no_gc; | 392 AssertNoAllocation no_gc; |
372 CopyElements(&no_gc, new_elms, 0, elms, 0, len); | 393 CopyElements(&no_gc, new_elms, 0, elms, 0, len); |
(...skipping 10 matching lines...) Expand all Loading... |
383 elms->set(index + len, args[index + 1], mode); | 404 elms->set(index + len, args[index + 1], mode); |
384 } | 405 } |
385 | 406 |
386 // Set the length. | 407 // Set the length. |
387 array->set_length(Smi::FromInt(new_length)); | 408 array->set_length(Smi::FromInt(new_length)); |
388 return Smi::FromInt(new_length); | 409 return Smi::FromInt(new_length); |
389 } | 410 } |
390 | 411 |
391 | 412 |
392 BUILTIN(ArrayPop) { | 413 BUILTIN(ArrayPop) { |
393 JSArray* array = JSArray::cast(*args.receiver()); | 414 Object* receiver = *args.receiver(); |
394 ASSERT(array->HasFastElements()); | 415 FixedArray* elms = NULL; |
| 416 if (!IsJSArrayWithFastElements(receiver, &elms)) { |
| 417 return CallJsBuiltin("ArrayPop", args); |
| 418 } |
| 419 JSArray* array = JSArray::cast(receiver); |
395 | 420 |
396 int len = Smi::cast(array->length())->value(); | 421 int len = Smi::cast(array->length())->value(); |
397 if (len == 0) return Heap::undefined_value(); | 422 if (len == 0) return Heap::undefined_value(); |
398 | 423 |
399 // Get top element | 424 // Get top element |
400 FixedArray* elms = FixedArray::cast(array->elements()); | |
401 Object* top = elms->get(len - 1); | 425 Object* top = elms->get(len - 1); |
402 | 426 |
403 // Set the length. | 427 // Set the length. |
404 array->set_length(Smi::FromInt(len - 1)); | 428 array->set_length(Smi::FromInt(len - 1)); |
405 | 429 |
406 if (!top->IsTheHole()) { | 430 if (!top->IsTheHole()) { |
407 // Delete the top element. | 431 // Delete the top element. |
408 elms->set_the_hole(len - 1); | 432 elms->set_the_hole(len - 1); |
409 return top; | 433 return top; |
410 } | 434 } |
411 | 435 |
412 // Remember to check the prototype chain. | 436 // Remember to check the prototype chain. |
413 JSFunction* array_function = | 437 JSFunction* array_function = |
414 Top::context()->global_context()->array_function(); | 438 Top::context()->global_context()->array_function(); |
415 JSObject* prototype = JSObject::cast(array_function->prototype()); | 439 JSObject* prototype = JSObject::cast(array_function->prototype()); |
416 top = prototype->GetElement(len - 1); | 440 top = prototype->GetElement(len - 1); |
417 | 441 |
418 return top; | 442 return top; |
419 } | 443 } |
420 | 444 |
421 | 445 |
422 BUILTIN(ArrayShift) { | 446 BUILTIN(ArrayShift) { |
423 if (!ArrayPrototypeHasNoElements()) { | 447 Object* receiver = *args.receiver(); |
| 448 FixedArray* elms = NULL; |
| 449 if (!IsJSArrayWithFastElements(receiver, &elms) |
| 450 || !ArrayPrototypeHasNoElements()) { |
424 return CallJsBuiltin("ArrayShift", args); | 451 return CallJsBuiltin("ArrayShift", args); |
425 } | 452 } |
426 | 453 JSArray* array = JSArray::cast(receiver); |
427 JSArray* array = JSArray::cast(*args.receiver()); | |
428 ASSERT(array->HasFastElements()); | 454 ASSERT(array->HasFastElements()); |
429 | 455 |
430 int len = Smi::cast(array->length())->value(); | 456 int len = Smi::cast(array->length())->value(); |
431 if (len == 0) return Heap::undefined_value(); | 457 if (len == 0) return Heap::undefined_value(); |
432 | 458 |
433 FixedArray* elms = FixedArray::cast(array->elements()); | |
434 | |
435 // Get first element | 459 // Get first element |
436 Object* first = elms->get(0); | 460 Object* first = elms->get(0); |
437 if (first->IsTheHole()) { | 461 if (first->IsTheHole()) { |
438 first = Heap::undefined_value(); | 462 first = Heap::undefined_value(); |
439 } | 463 } |
440 | 464 |
441 // Shift the elements. | 465 // Shift the elements. |
442 AssertNoAllocation no_gc; | 466 AssertNoAllocation no_gc; |
443 MoveElements(&no_gc, elms, 0, elms, 1, len - 1); | 467 MoveElements(&no_gc, elms, 0, elms, 1, len - 1); |
444 elms->set(len - 1, Heap::the_hole_value()); | 468 elms->set(len - 1, Heap::the_hole_value()); |
445 | 469 |
446 // Set the length. | 470 // Set the length. |
447 array->set_length(Smi::FromInt(len - 1)); | 471 array->set_length(Smi::FromInt(len - 1)); |
448 | 472 |
449 return first; | 473 return first; |
450 } | 474 } |
451 | 475 |
452 | 476 |
453 BUILTIN(ArrayUnshift) { | 477 BUILTIN(ArrayUnshift) { |
454 if (!ArrayPrototypeHasNoElements()) { | 478 Object* receiver = *args.receiver(); |
| 479 FixedArray* elms = NULL; |
| 480 if (!IsJSArrayWithFastElements(receiver, &elms) |
| 481 || !ArrayPrototypeHasNoElements()) { |
455 return CallJsBuiltin("ArrayUnshift", args); | 482 return CallJsBuiltin("ArrayUnshift", args); |
456 } | 483 } |
457 | 484 JSArray* array = JSArray::cast(receiver); |
458 JSArray* array = JSArray::cast(*args.receiver()); | |
459 ASSERT(array->HasFastElements()); | 485 ASSERT(array->HasFastElements()); |
460 | 486 |
461 int len = Smi::cast(array->length())->value(); | 487 int len = Smi::cast(array->length())->value(); |
462 int to_add = args.length() - 1; | 488 int to_add = args.length() - 1; |
463 // Note that we cannot quit early if to_add == 0 as | 489 // Note that we cannot quit early if to_add == 0 as |
464 // values should be lifted from prototype into | 490 // values should be lifted from prototype into |
465 // the array. | 491 // the array. |
466 | 492 |
467 int new_length = len + to_add; | 493 int new_length = len + to_add; |
468 // Currently fixed arrays cannot grow too big, so | 494 // Currently fixed arrays cannot grow too big, so |
469 // we should never hit this case. | 495 // we should never hit this case. |
470 ASSERT(to_add <= (Smi::kMaxValue - len)); | 496 ASSERT(to_add <= (Smi::kMaxValue - len)); |
471 | 497 |
472 FixedArray* elms = FixedArray::cast(array->elements()); | |
473 | |
474 if (new_length > elms->length()) { | 498 if (new_length > elms->length()) { |
475 // New backing storage is needed. | 499 // New backing storage is needed. |
476 int capacity = new_length + (new_length >> 1) + 16; | 500 int capacity = new_length + (new_length >> 1) + 16; |
477 Object* obj = Heap::AllocateUninitializedFixedArray(capacity); | 501 Object* obj = Heap::AllocateUninitializedFixedArray(capacity); |
478 if (obj->IsFailure()) return obj; | 502 if (obj->IsFailure()) return obj; |
479 FixedArray* new_elms = FixedArray::cast(obj); | 503 FixedArray* new_elms = FixedArray::cast(obj); |
480 | 504 |
481 AssertNoAllocation no_gc; | 505 AssertNoAllocation no_gc; |
482 CopyElements(&no_gc, new_elms, to_add, elms, 0, len); | 506 CopyElements(&no_gc, new_elms, to_add, elms, 0, len); |
483 FillWithHoles(new_elms, new_length, capacity); | 507 FillWithHoles(new_elms, new_length, capacity); |
(...skipping 12 matching lines...) Expand all Loading... |
496 elms->set(i, args[i + 1], mode); | 520 elms->set(i, args[i + 1], mode); |
497 } | 521 } |
498 | 522 |
499 // Set the length. | 523 // Set the length. |
500 array->set_length(Smi::FromInt(new_length)); | 524 array->set_length(Smi::FromInt(new_length)); |
501 return Smi::FromInt(new_length); | 525 return Smi::FromInt(new_length); |
502 } | 526 } |
503 | 527 |
504 | 528 |
505 BUILTIN(ArraySlice) { | 529 BUILTIN(ArraySlice) { |
506 if (!ArrayPrototypeHasNoElements()) { | 530 Object* receiver = *args.receiver(); |
| 531 FixedArray* elms = NULL; |
| 532 if (!IsJSArrayWithFastElements(receiver, &elms) |
| 533 || !ArrayPrototypeHasNoElements()) { |
507 return CallJsBuiltin("ArraySlice", args); | 534 return CallJsBuiltin("ArraySlice", args); |
508 } | 535 } |
509 | 536 JSArray* array = JSArray::cast(receiver); |
510 JSArray* array = JSArray::cast(*args.receiver()); | |
511 ASSERT(array->HasFastElements()); | 537 ASSERT(array->HasFastElements()); |
512 | 538 |
513 int len = Smi::cast(array->length())->value(); | 539 int len = Smi::cast(array->length())->value(); |
514 | 540 |
515 int n_arguments = args.length() - 1; | 541 int n_arguments = args.length() - 1; |
516 | 542 |
517 // Note carefully choosen defaults---if argument is missing, | 543 // Note carefully choosen defaults---if argument is missing, |
518 // it's undefined which gets converted to 0 for relative_start | 544 // it's undefined which gets converted to 0 for relative_start |
519 // and to len for relative_end. | 545 // and to len for relative_end. |
520 int relative_start = 0; | 546 int relative_start = 0; |
(...skipping 30 matching lines...) Expand all Loading... |
551 } | 577 } |
552 | 578 |
553 Object* result = AllocateJSArray(); | 579 Object* result = AllocateJSArray(); |
554 if (result->IsFailure()) return result; | 580 if (result->IsFailure()) return result; |
555 JSArray* result_array = JSArray::cast(result); | 581 JSArray* result_array = JSArray::cast(result); |
556 | 582 |
557 result = Heap::AllocateUninitializedFixedArray(result_len); | 583 result = Heap::AllocateUninitializedFixedArray(result_len); |
558 if (result->IsFailure()) return result; | 584 if (result->IsFailure()) return result; |
559 FixedArray* result_elms = FixedArray::cast(result); | 585 FixedArray* result_elms = FixedArray::cast(result); |
560 | 586 |
561 FixedArray* elms = FixedArray::cast(array->elements()); | |
562 | |
563 AssertNoAllocation no_gc; | 587 AssertNoAllocation no_gc; |
564 CopyElements(&no_gc, result_elms, 0, elms, k, result_len); | 588 CopyElements(&no_gc, result_elms, 0, elms, k, result_len); |
565 | 589 |
566 // Set elements. | 590 // Set elements. |
567 result_array->set_elements(result_elms); | 591 result_array->set_elements(result_elms); |
568 | 592 |
569 // Set the length. | 593 // Set the length. |
570 result_array->set_length(Smi::FromInt(result_len)); | 594 result_array->set_length(Smi::FromInt(result_len)); |
571 return result_array; | 595 return result_array; |
572 } | 596 } |
573 | 597 |
574 | 598 |
575 BUILTIN(ArraySplice) { | 599 BUILTIN(ArraySplice) { |
576 if (!ArrayPrototypeHasNoElements()) { | 600 Object* receiver = *args.receiver(); |
| 601 FixedArray* elms = NULL; |
| 602 if (!IsJSArrayWithFastElements(receiver, &elms) |
| 603 || !ArrayPrototypeHasNoElements()) { |
577 return CallJsBuiltin("ArraySplice", args); | 604 return CallJsBuiltin("ArraySplice", args); |
578 } | 605 } |
579 | 606 JSArray* array = JSArray::cast(receiver); |
580 JSArray* array = JSArray::cast(*args.receiver()); | |
581 ASSERT(array->HasFastElements()); | 607 ASSERT(array->HasFastElements()); |
582 | 608 |
583 int len = Smi::cast(array->length())->value(); | 609 int len = Smi::cast(array->length())->value(); |
584 | 610 |
585 int n_arguments = args.length() - 1; | 611 int n_arguments = args.length() - 1; |
586 | 612 |
587 // SpiderMonkey and JSC return undefined in the case where no | 613 // SpiderMonkey and JSC return undefined in the case where no |
588 // arguments are given instead of using the implicit undefined | 614 // arguments are given instead of using the implicit undefined |
589 // arguments. This does not follow ECMA-262, but we do the same for | 615 // arguments. This does not follow ECMA-262, but we do the same for |
590 // compatibility. | 616 // compatibility. |
(...skipping 20 matching lines...) Expand all Loading... |
611 if (n_arguments > 1) { | 637 if (n_arguments > 1) { |
612 Object* arg2 = args[2]; | 638 Object* arg2 = args[2]; |
613 if (arg2->IsSmi()) { | 639 if (arg2->IsSmi()) { |
614 delete_count = Smi::cast(arg2)->value(); | 640 delete_count = Smi::cast(arg2)->value(); |
615 } else { | 641 } else { |
616 return CallJsBuiltin("ArraySplice", args); | 642 return CallJsBuiltin("ArraySplice", args); |
617 } | 643 } |
618 } | 644 } |
619 int actual_delete_count = Min(Max(delete_count, 0), len - actual_start); | 645 int actual_delete_count = Min(Max(delete_count, 0), len - actual_start); |
620 | 646 |
621 FixedArray* elms = FixedArray::cast(array->elements()); | |
622 | |
623 JSArray* result_array = NULL; | 647 JSArray* result_array = NULL; |
624 if (actual_delete_count == 0) { | 648 if (actual_delete_count == 0) { |
625 Object* result = AllocateEmptyJSArray(); | 649 Object* result = AllocateEmptyJSArray(); |
626 if (result->IsFailure()) return result; | 650 if (result->IsFailure()) return result; |
627 result_array = JSArray::cast(result); | 651 result_array = JSArray::cast(result); |
628 } else { | 652 } else { |
629 // Allocate result array. | 653 // Allocate result array. |
630 Object* result = AllocateJSArray(); | 654 Object* result = AllocateJSArray(); |
631 if (result->IsFailure()) return result; | 655 if (result->IsFailure()) return result; |
632 result_array = JSArray::cast(result); | 656 result_array = JSArray::cast(result); |
(...skipping 718 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1351 if (entry->contains(pc)) { | 1375 if (entry->contains(pc)) { |
1352 return names_[i]; | 1376 return names_[i]; |
1353 } | 1377 } |
1354 } | 1378 } |
1355 } | 1379 } |
1356 return NULL; | 1380 return NULL; |
1357 } | 1381 } |
1358 | 1382 |
1359 | 1383 |
1360 } } // namespace v8::internal | 1384 } } // namespace v8::internal |
OLD | NEW |