Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: src/builtins-ia32.cc

Issue 2850: Generalize the Function.prototype.call hooks in the... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 12 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/builtins-arm.cc ('k') | src/codegen.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/builtins-arm.cc ('k') | src/codegen.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698