OLD | NEW |
---|---|
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 461 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
472 ExternalReference ref = ExternalReference( | 472 ExternalReference ref = ExternalReference( |
473 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); | 473 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); |
474 __ TailCallRuntime(ref, 5, 1); | 474 __ TailCallRuntime(ref, 5, 1); |
475 } | 475 } |
476 | 476 |
477 private: | 477 private: |
478 Register name_; | 478 Register name_; |
479 }; | 479 }; |
480 | 480 |
481 | 481 |
482 // Holds information about possible function call optimizations. | |
483 class CallOptimization BASE_EMBEDDED { | |
484 public: | |
485 explicit CallOptimization(LookupResult* lookup) | |
486 : constant_function_(NULL), | |
487 is_simple_api_call_(false), | |
488 expected_receiver_type_(NULL), | |
489 api_call_info_(NULL) { | |
490 if (!lookup->IsValid() || !lookup->IsCacheable()) return; | |
491 | |
492 // We only optimize constant function calls. | |
493 if (lookup->type() != CONSTANT_FUNCTION) return; | |
494 | |
495 Initialize(lookup->GetConstantFunction()); | |
496 } | |
497 | |
498 explicit CallOptimization(JSFunction* function) { | |
499 Initialize(function); | |
500 } | |
501 | |
502 bool is_constant_call() const { | |
503 return constant_function_ != NULL; | |
504 } | |
505 | |
506 JSFunction* constant_function() const { | |
507 ASSERT(constant_function_ != NULL); | |
508 return constant_function_; | |
509 } | |
510 | |
511 bool is_simple_api_call() const { | |
512 return is_simple_api_call_; | |
513 } | |
514 | |
515 FunctionTemplateInfo* expected_receiver_type() const { | |
516 ASSERT(is_simple_api_call_); | |
517 return expected_receiver_type_; | |
518 } | |
519 | |
520 CallHandlerInfo* api_call_info() const { | |
521 ASSERT(is_simple_api_call_); | |
522 return api_call_info_; | |
523 } | |
524 | |
525 // Returns the depth of the object having the expected type in the | |
526 // prototype chain between the two arguments. | |
527 int GetPrototypeDepthOfExpectedType(JSObject* object, | |
528 JSObject* holder) const { | |
529 ASSERT(is_simple_api_call_); | |
530 if (expected_receiver_type_ == NULL) return 0; | |
531 int depth = 0; | |
532 while (object != holder) { | |
533 if (object->IsInstanceOf(expected_receiver_type_)) return depth; | |
534 object = JSObject::cast(object->GetPrototype()); | |
535 ++depth; | |
536 } | |
537 if (holder->IsInstanceOf(expected_receiver_type_)) return depth; | |
538 return kInvalidProtoDepth; | |
539 } | |
540 | |
541 private: | |
542 void Initialize(JSFunction* function) { | |
543 if (!function->is_compiled()) return; | |
544 | |
545 constant_function_ = function; | |
546 is_simple_api_call_ = false; | |
547 | |
548 AnalyzePossibleApiFunction(function); | |
549 } | |
550 | |
551 // Determines whether the given function can be called using the | |
552 // fast api call builtin. | |
553 void AnalyzePossibleApiFunction(JSFunction* function) { | |
554 SharedFunctionInfo* sfi = function->shared(); | |
555 if (sfi->function_data()->IsUndefined()) return; | |
556 FunctionTemplateInfo* info = | |
557 FunctionTemplateInfo::cast(sfi->function_data()); | |
558 | |
559 // Require a C++ callback. | |
560 if (info->call_code()->IsUndefined()) return; | |
561 api_call_info_ = CallHandlerInfo::cast(info->call_code()); | |
562 | |
563 // Accept signatures that either have no restrictions at all or | |
564 // only have restrictions on the receiver. | |
565 if (!info->signature()->IsUndefined()) { | |
566 SignatureInfo* signature = SignatureInfo::cast(info->signature()); | |
567 if (!signature->args()->IsUndefined()) return; | |
568 if (!signature->receiver()->IsUndefined()) { | |
569 expected_receiver_type_ = | |
570 FunctionTemplateInfo::cast(signature->receiver()); | |
571 } | |
572 } | |
573 | |
574 is_simple_api_call_ = true; | |
575 } | |
576 | |
577 JSFunction* constant_function_; | |
578 bool is_simple_api_call_; | |
579 FunctionTemplateInfo* expected_receiver_type_; | |
580 CallHandlerInfo* api_call_info_; | |
581 }; | |
582 | |
583 | |
584 // Reserves space for the extra arguments to FastHandleApiCall in the | |
585 // caller's frame. | |
586 // | |
587 // These arguments are set by CheckPrototypes and GenerateFastApiCall. | |
588 static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { | |
589 // ----------- S t a t e ------------- | |
590 // -- esp[0] : return address | |
591 // -- esp[4] : last argument in the internal frame of the caller | |
592 // ----------------------------------- | |
593 __ pop(scratch); | |
594 __ push(Immediate(Smi::FromInt(0))); | |
595 __ push(Immediate(Smi::FromInt(0))); | |
596 __ push(Immediate(Smi::FromInt(0))); | |
597 __ push(Immediate(Smi::FromInt(0))); | |
598 __ push(scratch); | |
599 } | |
600 | |
601 | |
602 // Undoes the effects of ReserveSpaceForFastApiCall. | |
603 static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { | |
604 // ----------- S t a t e ------------- | |
605 // -- esp[0] : return address | |
606 // -- esp[4] : last fast api call extra argument | |
607 // -- ... | |
608 // -- esp[16] : first fast api call extra argument | |
609 // -- esp[20] : last argument in the internal frame | |
610 // ----------------------------------- | |
611 __ pop(scratch); | |
612 __ add(Operand(esp), Immediate(kPointerSize * 4)); | |
613 __ push(scratch); | |
614 } | |
615 | |
616 | |
617 // Generates call to FastHandleApiCall builtin. | |
618 static void GenerateFastApiCall(MacroAssembler* masm, | |
619 const CallOptimization& optimization, | |
620 int argc) { | |
621 // ----------- S t a t e ------------- | |
622 // -- esp[0] : return address | |
623 // -- esp[4] : object passing the type check | |
624 // (last fast api call extra argument, | |
625 // set by CheckPrototypes) | |
626 // -- esp[8] : api call data | |
627 // -- esp[12] : api callback | |
628 // -- esp[16] : api function | |
629 // (first fast api call extra argument) | |
630 // -- esp[20] : last argument | |
631 // -- ... | |
632 // -- esp[(argc + 5) * 4] : first argument | |
633 // -- esp[(argc + 6) * 4] : receiver | |
634 // ----------------------------------- | |
635 | |
636 // Get the function and setup the context. | |
637 JSFunction* function = optimization.constant_function(); | |
638 __ mov(edi, Immediate(Handle<JSFunction>(function))); | |
639 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | |
640 | |
641 // Pass the additional arguments FastHandleApiCall expects. | |
642 __ mov(Operand(esp, 4 * kPointerSize), edi); | |
643 bool info_loaded = false; | |
644 Object* callback = optimization.api_call_info()->callback(); | |
645 if (Heap::InNewSpace(callback)) { | |
646 info_loaded = true; | |
647 __ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info())); | |
648 __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kCallbackOffset)); | |
649 __ mov(Operand(esp, 3 * kPointerSize), ebx); | |
650 } else { | |
651 __ mov(Operand(esp, 3 * kPointerSize), Immediate(Handle<Object>(callback))); | |
652 } | |
653 Object* call_data = optimization.api_call_info()->data(); | |
654 if (Heap::InNewSpace(call_data)) { | |
655 if (!info_loaded) { | |
656 __ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info())); | |
657 } | |
658 __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset)); | |
659 __ mov(Operand(esp, 2 * kPointerSize), ebx); | |
660 } else { | |
661 __ mov(Operand(esp, 2 * kPointerSize), | |
662 Immediate(Handle<Object>(call_data))); | |
663 } | |
664 | |
665 // Set the number of arguments. | |
666 __ mov(eax, Immediate(argc + 4)); | |
667 | |
668 // Jump to the fast api call builtin (tail call). | |
669 Handle<Code> code = Handle<Code>( | |
670 Builtins::builtin(Builtins::FastHandleApiCall)); | |
671 ParameterCount expected(0); | |
672 __ InvokeCode(code, expected, expected, | |
673 RelocInfo::CODE_TARGET, JUMP_FUNCTION); | |
674 } | |
675 | |
676 | |
482 class CallInterceptorCompiler BASE_EMBEDDED { | 677 class CallInterceptorCompiler BASE_EMBEDDED { |
483 public: | 678 public: |
484 CallInterceptorCompiler(const ParameterCount& arguments, Register name) | 679 CallInterceptorCompiler(StubCompiler* stub_compiler, |
485 : arguments_(arguments), argc_(arguments.immediate()), name_(name) {} | 680 const ParameterCount& arguments, |
486 | 681 Register name) |
682 : stub_compiler_(stub_compiler), | |
683 arguments_(arguments), | |
684 argc_(arguments.immediate()), | |
685 name_(name) {} | |
686 | |
687 void Compile(MacroAssembler* masm, | |
688 JSObject* object, | |
689 JSObject* holder, | |
690 String* name, | |
691 LookupResult* lookup, | |
692 Register receiver, | |
693 Register scratch1, | |
694 Register scratch2, | |
695 Label* miss) { | |
696 ASSERT(holder->HasNamedInterceptor()); | |
697 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); | |
698 | |
699 // Check that the receiver isn't a smi. | |
700 __ test(receiver, Immediate(kSmiTagMask)); | |
701 __ j(zero, miss, not_taken); | |
702 | |
703 CallOptimization optimization(lookup); | |
704 | |
705 if (optimization.is_constant_call() && | |
706 !Top::CanHaveSpecialFunctions(holder)) { | |
707 CompileCacheable(masm, | |
708 object, | |
709 receiver, | |
710 scratch1, | |
711 scratch2, | |
712 holder, | |
713 lookup, | |
714 name, | |
715 optimization, | |
716 miss); | |
717 } else { | |
718 CompileRegular(masm, | |
719 object, | |
720 receiver, | |
721 scratch1, | |
722 scratch2, | |
723 name, | |
724 holder, | |
725 miss); | |
726 } | |
727 } | |
728 | |
729 private: | |
487 void CompileCacheable(MacroAssembler* masm, | 730 void CompileCacheable(MacroAssembler* masm, |
488 StubCompiler* stub_compiler, | 731 JSObject* object, |
489 Register receiver, | 732 Register receiver, |
490 Register holder, | |
491 Register scratch1, | 733 Register scratch1, |
492 Register scratch2, | 734 Register scratch2, |
493 JSObject* holder_obj, | 735 JSObject* holder_obj, |
494 LookupResult* lookup, | 736 LookupResult* lookup, |
495 String* name, | 737 String* name, |
738 const CallOptimization& optimization, | |
496 Label* miss_label) { | 739 Label* miss_label) { |
497 JSFunction* function = 0; | 740 ASSERT(optimization.is_constant_call()); |
498 bool optimize = false; | 741 |
499 // So far the most popular case for failed interceptor is | 742 int depth1 = kInvalidProtoDepth; |
500 // CONSTANT_FUNCTION sitting below. | 743 int depth2 = kInvalidProtoDepth; |
501 if (lookup->type() == CONSTANT_FUNCTION) { | 744 bool can_do_fast_api_call = false; |
502 function = lookup->GetConstantFunction(); | 745 if (optimization.is_simple_api_call() && |
503 // JSArray holder is a special case for call constant function | 746 !lookup->holder()->IsGlobalObject()) { |
504 // (see the corresponding code). | 747 depth1 = optimization.GetPrototypeDepthOfExpectedType(object, holder_obj); |
505 if (function->is_compiled() && !holder_obj->IsJSArray()) { | 748 if (depth1 == kInvalidProtoDepth) { |
506 optimize = true; | 749 depth2 = optimization.GetPrototypeDepthOfExpectedType(holder_obj, |
750 lookup->holder()); | |
507 } | 751 } |
508 } | 752 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) || |
509 | 753 (depth2 != kInvalidProtoDepth); |
510 if (!optimize) { | 754 } |
511 CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label); | 755 |
512 return; | 756 __ IncrementCounter(&Counters::call_const_interceptor, 1); |
513 } | 757 |
514 | 758 if (can_do_fast_api_call) { |
515 __ EnterInternalFrame(); | 759 __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1); |
516 __ push(holder); // Save the holder. | 760 ReserveSpaceForFastApiCall(masm, scratch1); |
517 __ push(name_); // Save the name. | 761 } |
518 | 762 |
519 CompileCallLoadPropertyWithInterceptor(masm, | 763 Label miss; |
520 receiver, | 764 Register holder = |
521 holder, | 765 stub_compiler_->CheckPrototypes(object, receiver, holder_obj, |
522 name_, | 766 scratch1, scratch2, name, |
523 holder_obj); | 767 depth1, &miss); |
524 | 768 |
525 __ pop(name_); // Restore the name. | 769 Label regular_invoke; |
526 __ pop(receiver); // Restore the holder. | 770 LoadWithInterceptor(masm, receiver, holder, holder_obj, ®ular_invoke); |
527 __ LeaveInternalFrame(); | 771 |
528 | 772 // Generate code for the failed interceptor case. |
529 __ cmp(eax, Factory::no_interceptor_result_sentinel()); | 773 |
530 Label invoke; | 774 // Check the lookup is still valid. |
531 __ j(not_equal, &invoke); | 775 stub_compiler_->CheckPrototypes(holder_obj, receiver, |
532 | 776 lookup->holder(), |
533 stub_compiler->CheckPrototypes(holder_obj, receiver, | 777 scratch1, scratch2, name, |
534 lookup->holder(), scratch1, | 778 depth2, &miss); |
535 scratch2, | 779 |
536 name, | |
537 miss_label); | |
538 if (lookup->holder()->IsGlobalObject()) { | 780 if (lookup->holder()->IsGlobalObject()) { |
781 ASSERT(!can_do_fast_api_call); | |
539 __ mov(edx, Operand(esp, (argc_ + 1) * kPointerSize)); | 782 __ mov(edx, Operand(esp, (argc_ + 1) * kPointerSize)); |
540 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | 783 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); |
541 __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edx); | 784 __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edx); |
542 } | 785 } |
543 | 786 |
544 ASSERT(function->is_compiled()); | 787 if (can_do_fast_api_call) { |
545 // Get the function and setup the context. | 788 GenerateFastApiCall(masm, optimization, argc_); |
546 __ mov(edi, Immediate(Handle<JSFunction>(function))); | 789 } else { |
547 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | 790 // Get the function and setup the context. |
548 | 791 JSFunction* function = optimization.constant_function(); |
549 // Jump to the cached code (tail call). | 792 __ mov(edi, Immediate(Handle<JSFunction>(function))); |
550 Handle<Code> code(function->code()); | 793 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
551 ParameterCount expected(function->shared()->formal_parameter_count()); | 794 |
552 __ InvokeCode(code, expected, arguments_, | 795 // Jump to the cached code (tail call). |
553 RelocInfo::CODE_TARGET, JUMP_FUNCTION); | 796 ASSERT(function->is_compiled()); |
554 | 797 Handle<Code> code(function->code()); |
555 __ bind(&invoke); | 798 ParameterCount expected(function->shared()->formal_parameter_count()); |
799 __ InvokeCode(code, expected, arguments_, | |
800 RelocInfo::CODE_TARGET, JUMP_FUNCTION); | |
801 } | |
802 | |
803 __ bind(&miss); | |
antonm
2010/02/08 12:07:38
feel free to ignore, but in case when !can_do_fast
Vitaly Repeshko
2010/02/09 16:15:24
Done.
| |
804 if (can_do_fast_api_call) { | |
805 FreeSpaceForFastApiCall(masm, scratch1); | |
806 } | |
807 __ jmp(miss_label); | |
808 | |
809 __ bind(®ular_invoke); | |
810 if (can_do_fast_api_call) { | |
811 FreeSpaceForFastApiCall(masm, scratch1); | |
812 } | |
556 } | 813 } |
557 | 814 |
558 void CompileRegular(MacroAssembler* masm, | 815 void CompileRegular(MacroAssembler* masm, |
816 JSObject* object, | |
559 Register receiver, | 817 Register receiver, |
560 Register holder, | 818 Register scratch1, |
561 Register scratch, | 819 Register scratch2, |
820 String* name, | |
562 JSObject* holder_obj, | 821 JSObject* holder_obj, |
563 Label* miss_label) { | 822 Label* miss_label) { |
823 Register holder = | |
824 stub_compiler_->CheckPrototypes(object, receiver, holder_obj, | |
825 scratch1, scratch2, name, | |
826 miss_label); | |
827 | |
564 __ EnterInternalFrame(); | 828 __ EnterInternalFrame(); |
565 // Save the name_ register across the call. | 829 // Save the name_ register across the call. |
566 __ push(name_); | 830 __ push(name_); |
567 | 831 |
568 PushInterceptorArguments(masm, | 832 PushInterceptorArguments(masm, |
569 receiver, | 833 receiver, |
570 holder, | 834 holder, |
571 name_, | 835 name_, |
572 holder_obj); | 836 holder_obj); |
573 | 837 |
574 ExternalReference ref = ExternalReference( | 838 ExternalReference ref = ExternalReference( |
575 IC_Utility(IC::kLoadPropertyWithInterceptorForCall)); | 839 IC_Utility(IC::kLoadPropertyWithInterceptorForCall)); |
576 __ mov(eax, Immediate(5)); | 840 __ mov(eax, Immediate(5)); |
577 __ mov(ebx, Immediate(ref)); | 841 __ mov(ebx, Immediate(ref)); |
578 | 842 |
579 CEntryStub stub(1); | 843 CEntryStub stub(1); |
580 __ CallStub(&stub); | 844 __ CallStub(&stub); |
581 | 845 |
582 // Restore the name_ register. | 846 // Restore the name_ register. |
583 __ pop(name_); | 847 __ pop(name_); |
584 __ LeaveInternalFrame(); | 848 __ LeaveInternalFrame(); |
585 } | 849 } |
586 | 850 |
587 private: | 851 void LoadWithInterceptor(MacroAssembler* masm, |
852 Register receiver, | |
853 Register holder, | |
854 JSObject* holder_obj, | |
855 Label* interceptor_succeeded) { | |
856 __ EnterInternalFrame(); | |
857 __ push(holder); // Save the holder. | |
858 __ push(name_); // Save the name. | |
859 | |
860 CompileCallLoadPropertyWithInterceptor(masm, | |
861 receiver, | |
862 holder, | |
863 name_, | |
864 holder_obj); | |
865 | |
866 __ pop(name_); // Restore the name. | |
867 __ pop(receiver); // Restore the holder. | |
868 __ LeaveInternalFrame(); | |
869 | |
870 __ cmp(eax, Factory::no_interceptor_result_sentinel()); | |
871 __ j(not_equal, interceptor_succeeded); | |
872 } | |
873 | |
874 StubCompiler* stub_compiler_; | |
588 const ParameterCount& arguments_; | 875 const ParameterCount& arguments_; |
589 int argc_; | 876 const int argc_; |
590 Register name_; | 877 Register name_; |
591 }; | 878 }; |
592 | 879 |
593 | 880 |
594 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { | 881 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { |
595 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); | 882 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); |
596 Code* code = NULL; | 883 Code* code = NULL; |
597 if (kind == Code::LOAD_IC) { | 884 if (kind == Code::LOAD_IC) { |
598 code = Builtins::builtin(Builtins::LoadIC_Miss); | 885 code = Builtins::builtin(Builtins::LoadIC_Miss); |
599 } else { | 886 } else { |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
684 #undef __ | 971 #undef __ |
685 #define __ ACCESS_MASM(masm()) | 972 #define __ ACCESS_MASM(masm()) |
686 | 973 |
687 | 974 |
688 Register StubCompiler::CheckPrototypes(JSObject* object, | 975 Register StubCompiler::CheckPrototypes(JSObject* object, |
689 Register object_reg, | 976 Register object_reg, |
690 JSObject* holder, | 977 JSObject* holder, |
691 Register holder_reg, | 978 Register holder_reg, |
692 Register scratch, | 979 Register scratch, |
693 String* name, | 980 String* name, |
981 int push_at_depth, | |
694 Label* miss) { | 982 Label* miss) { |
695 // Check that the maps haven't changed. | 983 // Check that the maps haven't changed. |
696 Register result = | 984 Register result = |
697 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss); | 985 masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, |
986 push_at_depth, miss); | |
698 | 987 |
699 // If we've skipped any global objects, it's not enough to verify | 988 // If we've skipped any global objects, it's not enough to verify |
700 // that their maps haven't changed. | 989 // that their maps haven't changed. |
701 while (object != holder) { | 990 while (object != holder) { |
702 if (object->IsGlobalObject()) { | 991 if (object->IsGlobalObject()) { |
703 GlobalObject* global = GlobalObject::cast(object); | 992 GlobalObject* global = GlobalObject::cast(object); |
704 Object* probe = global->EnsurePropertyCell(name); | 993 Object* probe = global->EnsurePropertyCell(name); |
705 if (probe->IsFailure()) { | 994 if (probe->IsFailure()) { |
706 set_failure(Failure::cast(probe)); | 995 set_failure(Failure::cast(probe)); |
707 return result; | 996 return result; |
708 } | 997 } |
709 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); | 998 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); |
710 ASSERT(cell->value()->IsTheHole()); | 999 ASSERT(cell->value()->IsTheHole()); |
711 __ mov(scratch, Immediate(Handle<Object>(cell))); | 1000 __ mov(scratch, Immediate(Handle<Object>(cell))); |
712 __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset), | 1001 __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset), |
713 Immediate(Factory::the_hole_value())); | 1002 Immediate(Factory::the_hole_value())); |
714 __ j(not_equal, miss, not_taken); | 1003 __ j(not_equal, miss, not_taken); |
715 } | 1004 } |
716 object = JSObject::cast(object->GetPrototype()); | 1005 object = JSObject::cast(object->GetPrototype()); |
717 } | 1006 } |
718 | 1007 |
719 // Return the register containin the holder. | 1008 // Return the register containing the holder. |
720 return result; | 1009 return result; |
721 } | 1010 } |
722 | 1011 |
723 | 1012 |
724 void StubCompiler::GenerateLoadField(JSObject* object, | 1013 void StubCompiler::GenerateLoadField(JSObject* object, |
725 JSObject* holder, | 1014 JSObject* holder, |
726 Register receiver, | 1015 Register receiver, |
727 Register scratch1, | 1016 Register scratch1, |
728 Register scratch2, | 1017 Register scratch2, |
729 int index, | 1018 int index, |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
962 // Check that the receiver isn't a smi. | 1251 // Check that the receiver isn't a smi. |
963 if (check != NUMBER_CHECK) { | 1252 if (check != NUMBER_CHECK) { |
964 __ test(edx, Immediate(kSmiTagMask)); | 1253 __ test(edx, Immediate(kSmiTagMask)); |
965 __ j(zero, &miss, not_taken); | 1254 __ j(zero, &miss, not_taken); |
966 } | 1255 } |
967 | 1256 |
968 // Make sure that it's okay not to patch the on stack receiver | 1257 // Make sure that it's okay not to patch the on stack receiver |
969 // unless we're doing a receiver map check. | 1258 // unless we're doing a receiver map check. |
970 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); | 1259 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); |
971 | 1260 |
1261 CallOptimization optimization(function); | |
1262 int depth = kInvalidProtoDepth; | |
1263 | |
972 switch (check) { | 1264 switch (check) { |
973 case RECEIVER_MAP_CHECK: | 1265 case RECEIVER_MAP_CHECK: |
1266 __ IncrementCounter(&Counters::call_const, 1); | |
1267 | |
1268 if (optimization.is_simple_api_call() && !object->IsGlobalObject()) { | |
1269 depth = optimization.GetPrototypeDepthOfExpectedType( | |
1270 JSObject::cast(object), holder); | |
1271 } | |
1272 | |
1273 if (depth != kInvalidProtoDepth) { | |
1274 __ IncrementCounter(&Counters::call_const_fast_api, 1); | |
1275 ReserveSpaceForFastApiCall(masm(), eax); | |
1276 } | |
1277 | |
974 // Check that the maps haven't changed. | 1278 // Check that the maps haven't changed. |
975 CheckPrototypes(JSObject::cast(object), edx, holder, | 1279 CheckPrototypes(JSObject::cast(object), edx, holder, |
976 ebx, eax, name, &miss); | 1280 ebx, eax, name, depth, &miss); |
977 | 1281 |
978 // Patch the receiver on the stack with the global proxy if | 1282 // Patch the receiver on the stack with the global proxy if |
979 // necessary. | 1283 // necessary. |
980 if (object->IsGlobalObject()) { | 1284 if (object->IsGlobalObject()) { |
1285 ASSERT(depth == kInvalidProtoDepth); | |
981 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | 1286 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); |
982 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); | 1287 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); |
983 } | 1288 } |
984 break; | 1289 break; |
985 | 1290 |
986 case STRING_CHECK: | 1291 case STRING_CHECK: |
987 if (!function->IsBuiltin()) { | 1292 if (!function->IsBuiltin()) { |
988 // Calling non-builtins with a value as receiver requires boxing. | 1293 // Calling non-builtins with a value as receiver requires boxing. |
989 __ jmp(&miss); | 1294 __ jmp(&miss); |
990 } else { | 1295 } else { |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1055 // Check that the object is in fast mode (not dictionary). | 1360 // Check that the object is in fast mode (not dictionary). |
1056 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | 1361 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), |
1057 Immediate(Factory::fixed_array_map())); | 1362 Immediate(Factory::fixed_array_map())); |
1058 __ j(not_equal, &miss, not_taken); | 1363 __ j(not_equal, &miss, not_taken); |
1059 break; | 1364 break; |
1060 | 1365 |
1061 default: | 1366 default: |
1062 UNREACHABLE(); | 1367 UNREACHABLE(); |
1063 } | 1368 } |
1064 | 1369 |
1065 // Get the function and setup the context. | 1370 if (depth != kInvalidProtoDepth) { |
1066 __ mov(edi, Immediate(Handle<JSFunction>(function))); | 1371 GenerateFastApiCall(masm(), optimization, argc); |
1067 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | 1372 } else { |
1373 // Get the function and setup the context. | |
1374 __ mov(edi, Immediate(Handle<JSFunction>(function))); | |
1375 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | |
1068 | 1376 |
1069 // Jump to the cached code (tail call). | 1377 // Jump to the cached code (tail call). |
1070 ASSERT(function->is_compiled()); | 1378 ASSERT(function->is_compiled()); |
1071 Handle<Code> code(function->code()); | 1379 Handle<Code> code(function->code()); |
1072 ParameterCount expected(function->shared()->formal_parameter_count()); | 1380 ParameterCount expected(function->shared()->formal_parameter_count()); |
1073 __ InvokeCode(code, expected, arguments(), | 1381 __ InvokeCode(code, expected, arguments(), |
1074 RelocInfo::CODE_TARGET, JUMP_FUNCTION); | 1382 RelocInfo::CODE_TARGET, JUMP_FUNCTION); |
1383 } | |
1075 | 1384 |
1076 // Handle call cache miss. | 1385 // Handle call cache miss. |
1077 __ bind(&miss); | 1386 __ bind(&miss); |
1387 if (depth != kInvalidProtoDepth) { | |
1388 FreeSpaceForFastApiCall(masm(), eax); | |
1389 } | |
1078 Handle<Code> ic = ComputeCallMiss(arguments().immediate()); | 1390 Handle<Code> ic = ComputeCallMiss(arguments().immediate()); |
1079 __ jmp(ic, RelocInfo::CODE_TARGET); | 1391 __ jmp(ic, RelocInfo::CODE_TARGET); |
1080 | 1392 |
1081 // Return the generated code. | 1393 // Return the generated code. |
1082 String* function_name = NULL; | 1394 String* function_name = NULL; |
1083 if (function->shared()->name()->IsString()) { | 1395 if (function->shared()->name()->IsString()) { |
1084 function_name = String::cast(function->shared()->name()); | 1396 function_name = String::cast(function->shared()->name()); |
1085 } | 1397 } |
1086 return GetCode(CONSTANT_FUNCTION, function_name); | 1398 return GetCode(CONSTANT_FUNCTION, function_name); |
1087 } | 1399 } |
(...skipping 13 matching lines...) Expand all Loading... | |
1101 | 1413 |
1102 // Get the number of arguments. | 1414 // Get the number of arguments. |
1103 const int argc = arguments().immediate(); | 1415 const int argc = arguments().immediate(); |
1104 | 1416 |
1105 LookupResult lookup; | 1417 LookupResult lookup; |
1106 LookupPostInterceptor(holder, name, &lookup); | 1418 LookupPostInterceptor(holder, name, &lookup); |
1107 | 1419 |
1108 // Get the receiver from the stack. | 1420 // Get the receiver from the stack. |
1109 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1421 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
1110 | 1422 |
1111 CallInterceptorCompiler compiler(arguments(), ecx); | 1423 CallInterceptorCompiler compiler(this, arguments(), ecx); |
1112 CompileLoadInterceptor(&compiler, | 1424 compiler.Compile(masm(), |
1113 this, | 1425 JSObject::cast(object), |
1114 masm(), | 1426 holder, |
1115 JSObject::cast(object), | 1427 name, |
1116 holder, | 1428 &lookup, |
1117 name, | 1429 edx, |
1118 &lookup, | 1430 ebx, |
1119 edx, | 1431 edi, |
1120 ebx, | 1432 &miss); |
1121 edi, | |
1122 &miss); | |
1123 | 1433 |
1124 // Restore receiver. | 1434 // Restore receiver. |
1125 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1435 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
1126 | 1436 |
1127 // Check that the function really is a function. | 1437 // Check that the function really is a function. |
1128 __ test(eax, Immediate(kSmiTagMask)); | 1438 __ test(eax, Immediate(kSmiTagMask)); |
1129 __ j(zero, &miss, not_taken); | 1439 __ j(zero, &miss, not_taken); |
1130 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); | 1440 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); |
1131 __ j(not_equal, &miss, not_taken); | 1441 __ j(not_equal, &miss, not_taken); |
1132 | 1442 |
(...skipping 809 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1942 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); | 2252 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); |
1943 | 2253 |
1944 // Return the generated code. | 2254 // Return the generated code. |
1945 return GetCode(); | 2255 return GetCode(); |
1946 } | 2256 } |
1947 | 2257 |
1948 | 2258 |
1949 #undef __ | 2259 #undef __ |
1950 | 2260 |
1951 } } // namespace v8::internal | 2261 } } // namespace v8::internal |
OLD | NEW |