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 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
372 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { | 372 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { |
373 Generate_JSEntryTrampolineHelper(masm, false); | 373 Generate_JSEntryTrampolineHelper(masm, false); |
374 } | 374 } |
375 | 375 |
376 | 376 |
377 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { | 377 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { |
378 Generate_JSEntryTrampolineHelper(masm, true); | 378 Generate_JSEntryTrampolineHelper(masm, true); |
379 } | 379 } |
380 | 380 |
381 | 381 |
| 382 void Builtins::Generate_FunctionCall(MacroAssembler* masm) { |
| 383 // 1. Make sure we have at least one argument. |
| 384 { Label done; |
| 385 __ test(eax, Operand(eax)); |
| 386 __ j(not_zero, &done, taken); |
| 387 __ pop(ebx); |
| 388 __ push(Immediate(Factory::undefined_value())); |
| 389 __ push(ebx); |
| 390 __ inc(eax); |
| 391 __ bind(&done); |
| 392 } |
| 393 |
| 394 // 2. Get the function to call from the stack. |
| 395 { Label done, non_function, function; |
| 396 // +1 ~ return address. |
| 397 __ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize)); |
| 398 __ test(edi, Immediate(kSmiTagMask)); |
| 399 __ j(zero, &non_function, not_taken); |
| 400 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); // get the map |
| 401 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
| 402 __ cmp(ecx, JS_FUNCTION_TYPE); |
| 403 __ j(equal, &function, taken); |
| 404 |
| 405 // Non-function called: Clear the function to force exception. |
| 406 __ bind(&non_function); |
| 407 __ xor_(edi, Operand(edi)); |
| 408 __ jmp(&done); |
| 409 |
| 410 // Function called: Change context eagerly to get the right global object. |
| 411 __ bind(&function); |
| 412 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
| 413 |
| 414 __ bind(&done); |
| 415 } |
| 416 |
| 417 // 3. Make sure first argument is an object; convert if necessary. |
| 418 { Label call_to_object, use_global_receiver, patch_receiver, done; |
| 419 __ mov(ebx, Operand(esp, eax, times_4, 0)); |
| 420 |
| 421 __ test(ebx, Immediate(kSmiTagMask)); |
| 422 __ j(zero, &call_to_object); |
| 423 |
| 424 __ cmp(ebx, Factory::null_value()); |
| 425 __ j(equal, &use_global_receiver); |
| 426 __ cmp(ebx, Factory::undefined_value()); |
| 427 __ j(equal, &use_global_receiver); |
| 428 |
| 429 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset)); |
| 430 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
| 431 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); |
| 432 __ j(less, &call_to_object); |
| 433 __ cmp(ecx, LAST_JS_OBJECT_TYPE); |
| 434 __ j(less_equal, &done); |
| 435 |
| 436 __ bind(&call_to_object); |
| 437 __ EnterInternalFrame(); // preserves eax, ebx, edi |
| 438 |
| 439 // Store the arguments count on the stack (smi tagged). |
| 440 ASSERT(kSmiTag == 0); |
| 441 __ shl(eax, kSmiTagSize); |
| 442 __ push(eax); |
| 443 |
| 444 __ push(edi); // save edi across the call |
| 445 __ push(ebx); |
| 446 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
| 447 __ mov(Operand(ebx), eax); |
| 448 __ pop(edi); // restore edi after the call |
| 449 |
| 450 // Get the arguments count and untag it. |
| 451 __ pop(eax); |
| 452 __ shr(eax, kSmiTagSize); |
| 453 |
| 454 __ ExitInternalFrame(); |
| 455 __ jmp(&patch_receiver); |
| 456 |
| 457 // Use the global object from the called function as the receiver. |
| 458 __ bind(&use_global_receiver); |
| 459 const int kGlobalIndex = |
| 460 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; |
| 461 __ mov(ebx, FieldOperand(esi, kGlobalIndex)); |
| 462 |
| 463 __ bind(&patch_receiver); |
| 464 __ mov(Operand(esp, eax, times_4, 0), ebx); |
| 465 |
| 466 __ bind(&done); |
| 467 } |
| 468 |
| 469 // 4. Shift stuff one slot down the stack. |
| 470 { Label loop; |
| 471 __ lea(ecx, Operand(eax, +1)); // +1 ~ copy receiver too |
| 472 __ bind(&loop); |
| 473 __ mov(ebx, Operand(esp, ecx, times_4, 0)); |
| 474 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx); |
| 475 __ dec(ecx); |
| 476 __ j(not_zero, &loop); |
| 477 } |
| 478 |
| 479 // 5. Remove TOS (copy of last arguments), but keep return address. |
| 480 __ pop(ebx); |
| 481 __ pop(ecx); |
| 482 __ push(ebx); |
| 483 __ dec(eax); |
| 484 |
| 485 // 6. Check that function really was a function and get the code to |
| 486 // call from the function and check that the number of expected |
| 487 // arguments matches what we're providing. |
| 488 { Label invoke; |
| 489 __ test(edi, Operand(edi)); |
| 490 __ j(not_zero, &invoke, taken); |
| 491 __ xor_(ebx, Operand(ebx)); |
| 492 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); |
| 493 __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), code_target); |
| 494 |
| 495 __ bind(&invoke); |
| 496 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
| 497 __ mov(ebx, |
| 498 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); |
| 499 __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); |
| 500 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); |
| 501 __ cmp(eax, Operand(ebx)); |
| 502 __ j(not_equal, Handle<Code>(builtin(ArgumentsAdaptorTrampoline))); |
| 503 } |
| 504 |
| 505 // 7. Jump (tail-call) to the code in register edx without checking arguments. |
| 506 ParameterCount expected(0); |
| 507 __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION); |
| 508 } |
| 509 |
| 510 |
382 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { | 511 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { |
383 __ EnterInternalFrame(); | 512 __ EnterInternalFrame(); |
384 | 513 |
385 __ push(Operand(ebp, 4 * kPointerSize)); // push this | 514 __ push(Operand(ebp, 4 * kPointerSize)); // push this |
386 __ push(Operand(ebp, 2 * kPointerSize)); // push arguments | 515 __ push(Operand(ebp, 2 * kPointerSize)); // push arguments |
387 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); | 516 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); |
388 | 517 |
389 // Eagerly check for stack-overflow before pushing all the arguments | 518 // Eagerly check for stack-overflow before pushing all the arguments |
390 // to the stack. | 519 // to the stack. |
391 Label okay; | 520 Label okay; |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
523 } | 652 } |
524 | 653 |
525 | 654 |
526 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { | 655 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { |
527 // ----------- S t a t e ------------- | 656 // ----------- S t a t e ------------- |
528 // -- eax : actual number of arguments | 657 // -- eax : actual number of arguments |
529 // -- ebx : expected number of arguments | 658 // -- ebx : expected number of arguments |
530 // -- edx : code entry to call | 659 // -- edx : code entry to call |
531 // ----------------------------------- | 660 // ----------------------------------- |
532 | 661 |
533 Label entry, invoke, function_prototype_call; | 662 Label invoke, dont_adapt_arguments; |
534 __ bind(&entry); | |
535 __ IncrementCounter(&Counters::arguments_adaptors, 1); | 663 __ IncrementCounter(&Counters::arguments_adaptors, 1); |
536 | 664 |
537 Label enough, too_few; | 665 Label enough, too_few; |
538 __ cmp(eax, Operand(ebx)); | 666 __ cmp(eax, Operand(ebx)); |
539 __ j(less, &too_few); | 667 __ j(less, &too_few); |
540 __ cmp(ebx, -1); | 668 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel); |
541 __ j(equal, &function_prototype_call); | 669 __ j(equal, &dont_adapt_arguments); |
542 | 670 |
543 { // Enough parameters: Actual >= expected. | 671 { // Enough parameters: Actual >= expected. |
544 __ bind(&enough); | 672 __ bind(&enough); |
545 EnterArgumentsAdaptorFrame(masm); | 673 EnterArgumentsAdaptorFrame(masm); |
546 | 674 |
547 // Copy receiver and all expected arguments. | 675 // Copy receiver and all expected arguments. |
548 const int offset = StandardFrameConstants::kCallerSPOffset; | 676 const int offset = StandardFrameConstants::kCallerSPOffset; |
549 __ lea(eax, Operand(ebp, eax, times_4, offset)); | 677 __ lea(eax, Operand(ebp, eax, times_4, offset)); |
550 __ mov(ecx, -1); // account for receiver | 678 __ mov(ecx, -1); // account for receiver |
551 | 679 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
597 ExitArgumentsAdaptorFrame(masm); | 725 ExitArgumentsAdaptorFrame(masm); |
598 __ ret(0); | 726 __ ret(0); |
599 | 727 |
600 // Compute the offset from the beginning of the ArgumentsAdaptorTrampoline | 728 // Compute the offset from the beginning of the ArgumentsAdaptorTrampoline |
601 // builtin code object to the return address after the call. | 729 // builtin code object to the return address after the call. |
602 ASSERT(return_site.is_bound()); | 730 ASSERT(return_site.is_bound()); |
603 arguments_adaptor_call_pc_offset_ = return_site.pos() + Code::kHeaderSize; | 731 arguments_adaptor_call_pc_offset_ = return_site.pos() + Code::kHeaderSize; |
604 | 732 |
605 | 733 |
606 // ------------------------------------------- | 734 // ------------------------------------------- |
607 // Function.prototype.call implementation. | 735 // Dont adapt arguments. |
608 // ------------------------------------------- | 736 // ------------------------------------------- |
609 __ bind(&function_prototype_call); | 737 __ bind(&dont_adapt_arguments); |
610 | 738 __ jmp(Operand(edx)); |
611 // 1. Make sure we have at least one argument. | |
612 { Label done; | |
613 __ test(eax, Operand(eax)); | |
614 __ j(not_zero, &done, taken); | |
615 __ pop(ebx); | |
616 __ push(Immediate(Factory::undefined_value())); | |
617 __ push(ebx); | |
618 __ inc(eax); | |
619 __ bind(&done); | |
620 } | |
621 | |
622 // 2. Get the function to call from the stack. | |
623 { Label done, non_function, function; | |
624 // +1 ~ return address. | |
625 __ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize)); | |
626 __ test(edi, Immediate(kSmiTagMask)); | |
627 __ j(zero, &non_function, not_taken); | |
628 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); // get the map | |
629 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | |
630 __ cmp(ecx, JS_FUNCTION_TYPE); | |
631 __ j(equal, &function, taken); | |
632 | |
633 // Non-function called: Clear the function to force exception. | |
634 __ bind(&non_function); | |
635 __ xor_(edi, Operand(edi)); | |
636 __ jmp(&done); | |
637 | |
638 // Function called: Change context eagerly to get the right global object. | |
639 __ bind(&function); | |
640 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | |
641 | |
642 __ bind(&done); | |
643 } | |
644 | |
645 // 3. Make sure first argument is an object; convert if necessary. | |
646 { Label call_to_object, use_global_receiver, patch_receiver, done; | |
647 __ mov(ebx, Operand(esp, eax, times_4, 0)); | |
648 | |
649 __ test(ebx, Immediate(kSmiTagMask)); | |
650 __ j(zero, &call_to_object); | |
651 | |
652 __ cmp(ebx, Factory::null_value()); | |
653 __ j(equal, &use_global_receiver); | |
654 __ cmp(ebx, Factory::undefined_value()); | |
655 __ j(equal, &use_global_receiver); | |
656 | |
657 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset)); | |
658 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | |
659 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | |
660 __ j(less, &call_to_object); | |
661 __ cmp(ecx, LAST_JS_OBJECT_TYPE); | |
662 __ j(less_equal, &done); | |
663 | |
664 __ bind(&call_to_object); | |
665 __ EnterInternalFrame(); // preserves eax, ebx, edi | |
666 | |
667 // Store the arguments count on the stack (smi tagged). | |
668 ASSERT(kSmiTag == 0); | |
669 __ shl(eax, kSmiTagSize); | |
670 __ push(eax); | |
671 | |
672 __ push(edi); // save edi across the call | |
673 __ push(ebx); | |
674 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | |
675 __ mov(Operand(ebx), eax); | |
676 __ pop(edi); // restore edi after the call | |
677 | |
678 // Get the arguments count and untag it. | |
679 __ pop(eax); | |
680 __ shr(eax, kSmiTagSize); | |
681 | |
682 __ ExitInternalFrame(); | |
683 __ jmp(&patch_receiver); | |
684 | |
685 // Use the global object from the called function as the receiver. | |
686 __ bind(&use_global_receiver); | |
687 const int kGlobalIndex = | |
688 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; | |
689 __ mov(ebx, FieldOperand(esi, kGlobalIndex)); | |
690 | |
691 __ bind(&patch_receiver); | |
692 __ mov(Operand(esp, eax, times_4, 0), ebx); | |
693 | |
694 __ bind(&done); | |
695 } | |
696 | |
697 // 4. Shift stuff one slot down the stack. | |
698 { Label loop; | |
699 __ lea(ecx, Operand(eax, +1)); // +1 ~ copy receiver too | |
700 __ bind(&loop); | |
701 __ mov(ebx, Operand(esp, ecx, times_4, 0)); | |
702 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx); | |
703 __ dec(ecx); | |
704 __ j(not_zero, &loop); | |
705 } | |
706 | |
707 // 5. Remove TOS (copy of last arguments), but keep return address. | |
708 __ pop(ebx); | |
709 __ pop(ecx); | |
710 __ push(ebx); | |
711 __ dec(eax); | |
712 | |
713 // 6. Check that function really was a function and get the code to | |
714 // call from the function and check that the number of expected | |
715 // arguments matches what we're providing. | |
716 { Label invoke; | |
717 __ test(edi, Operand(edi)); | |
718 __ j(not_zero, &invoke, taken); | |
719 __ xor_(ebx, Operand(ebx)); | |
720 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); | |
721 __ jmp(&enough); | |
722 | |
723 __ bind(&invoke); | |
724 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | |
725 __ mov(ebx, | |
726 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); | |
727 __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); | |
728 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); | |
729 __ cmp(eax, Operand(ebx)); | |
730 __ j(not_equal, &entry); | |
731 } | |
732 | |
733 // 7. Jump (tail-call) to the code in register edx without checking arguments. | |
734 ParameterCount expected(0); | |
735 __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION); | |
736 } | 739 } |
737 | 740 |
738 | 741 |
739 static void Generate_DebugBreakCallHelper(MacroAssembler* masm, | 742 static void Generate_DebugBreakCallHelper(MacroAssembler* masm, |
740 RegList pointer_regs, | 743 RegList pointer_regs, |
741 bool convert_call_to_jmp) { | 744 bool convert_call_to_jmp) { |
742 // Save the content of all general purpose registers in memory. This copy in | 745 // Save the content of all general purpose registers in memory. This copy in |
743 // memory is later pushed onto the JS expression stack for the fake JS frame | 746 // memory is later pushed onto the JS expression stack for the fake JS frame |
744 // generated and also to the C frame generated on top of that. In the JS | 747 // generated and also to the C frame generated on top of that. In the JS |
745 // frame ONLY the registers containing pointers will be pushed on the | 748 // frame ONLY the registers containing pointers will be pushed on the |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
873 // Register state for stub CallFunction (from CallFunctionStub in ic-ia32.cc). | 876 // Register state for stub CallFunction (from CallFunctionStub in ic-ia32.cc). |
874 // ----------- S t a t e ------------- | 877 // ----------- S t a t e ------------- |
875 // No registers used on entry. | 878 // No registers used on entry. |
876 // ----------------------------------- | 879 // ----------------------------------- |
877 Generate_DebugBreakCallHelper(masm, 0, false); | 880 Generate_DebugBreakCallHelper(masm, 0, false); |
878 } | 881 } |
879 | 882 |
880 #undef __ | 883 #undef __ |
881 | 884 |
882 } } // namespace v8::internal | 885 } } // namespace v8::internal |
OLD | NEW |