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