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