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

Side by Side Diff: src/ia32/stub-cache-ia32.cc

Issue 573003: ia32: Fuse map and type checks in call ICs for API functions. (Closed)
Patch Set: Rewrote a comment. Created 10 years, 10 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
OLDNEW
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
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, &regular_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(&regular_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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/ia32/macro-assembler-ia32.cc ('k') | src/macro-assembler.h » ('j') | src/stub-cache.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698