| 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 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 401 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); | 401 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); |
| 402 | 402 |
| 403 // Jump to the cached code (tail call). | 403 // Jump to the cached code (tail call). |
| 404 Handle<Code> code(function->code()); | 404 Handle<Code> code(function->code()); |
| 405 ParameterCount expected(function->shared()->formal_parameter_count()); | 405 ParameterCount expected(function->shared()->formal_parameter_count()); |
| 406 __ InvokeCode(code, expected, arguments, | 406 __ InvokeCode(code, expected, arguments, |
| 407 RelocInfo::CODE_TARGET, JUMP_FUNCTION); | 407 RelocInfo::CODE_TARGET, JUMP_FUNCTION); |
| 408 } | 408 } |
| 409 | 409 |
| 410 | 410 |
| 411 template <class Compiler> | |
| 412 static void CompileLoadInterceptor(Compiler* compiler, | |
| 413 StubCompiler* stub_compiler, | |
| 414 MacroAssembler* masm, | |
| 415 JSObject* object, | |
| 416 JSObject* holder, | |
| 417 String* name, | |
| 418 LookupResult* lookup, | |
| 419 Register receiver, | |
| 420 Register scratch1, | |
| 421 Register scratch2, | |
| 422 Label* miss) { | |
| 423 ASSERT(holder->HasNamedInterceptor()); | |
| 424 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); | |
| 425 | |
| 426 // Check that the receiver isn't a smi. | |
| 427 __ BranchOnSmi(receiver, miss); | |
| 428 | |
| 429 // Check that the maps haven't changed. | |
| 430 Register reg = | |
| 431 stub_compiler->CheckPrototypes(object, receiver, holder, | |
| 432 scratch1, scratch2, name, miss); | |
| 433 | |
| 434 if (lookup->IsValid() && lookup->IsCacheable()) { | |
| 435 compiler->CompileCacheable(masm, | |
| 436 stub_compiler, | |
| 437 receiver, | |
| 438 reg, | |
| 439 scratch1, | |
| 440 scratch2, | |
| 441 holder, | |
| 442 lookup, | |
| 443 name, | |
| 444 miss); | |
| 445 } else { | |
| 446 compiler->CompileRegular(masm, | |
| 447 receiver, | |
| 448 reg, | |
| 449 scratch2, | |
| 450 holder, | |
| 451 miss); | |
| 452 } | |
| 453 } | |
| 454 | |
| 455 | |
| 456 static void PushInterceptorArguments(MacroAssembler* masm, | 411 static void PushInterceptorArguments(MacroAssembler* masm, |
| 457 Register receiver, | 412 Register receiver, |
| 458 Register holder, | 413 Register holder, |
| 459 Register name, | 414 Register name, |
| 460 JSObject* holder_obj) { | 415 JSObject* holder_obj) { |
| 461 __ push(receiver); | 416 __ push(receiver); |
| 462 __ push(holder); | 417 __ push(holder); |
| 463 __ push(name); | 418 __ push(name); |
| 464 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor(); | 419 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor(); |
| 465 ASSERT(!Heap::InNewSpace(interceptor)); | 420 ASSERT(!Heap::InNewSpace(interceptor)); |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 612 ExternalReference ref = ExternalReference( | 567 ExternalReference ref = ExternalReference( |
| 613 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); | 568 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); |
| 614 __ TailCallRuntime(ref, 5, 1); | 569 __ TailCallRuntime(ref, 5, 1); |
| 615 } | 570 } |
| 616 | 571 |
| 617 private: | 572 private: |
| 618 Register name_; | 573 Register name_; |
| 619 }; | 574 }; |
| 620 | 575 |
| 621 | 576 |
| 622 class CallInterceptorCompiler BASE_EMBEDDED { | 577 static void CompileLoadInterceptor(LoadInterceptorCompiler* compiler, |
| 623 public: | 578 StubCompiler* stub_compiler, |
| 624 CallInterceptorCompiler(const ParameterCount& arguments, Register name) | 579 MacroAssembler* masm, |
| 625 : arguments_(arguments), argc_(arguments.immediate()), name_(name) {} | 580 JSObject* object, |
| 581 JSObject* holder, |
| 582 String* name, |
| 583 LookupResult* lookup, |
| 584 Register receiver, |
| 585 Register scratch1, |
| 586 Register scratch2, |
| 587 Label* miss) { |
| 588 ASSERT(holder->HasNamedInterceptor()); |
| 589 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); |
| 626 | 590 |
| 627 void CompileCacheable(MacroAssembler* masm, | 591 // Check that the receiver isn't a smi. |
| 628 StubCompiler* stub_compiler, | 592 __ BranchOnSmi(receiver, miss); |
| 629 Register receiver, | |
| 630 Register holder, | |
| 631 Register scratch1, | |
| 632 Register scratch2, | |
| 633 JSObject* holder_obj, | |
| 634 LookupResult* lookup, | |
| 635 String* name, | |
| 636 Label* miss_label) { | |
| 637 JSFunction* function = 0; | |
| 638 bool optimize = false; | |
| 639 // So far the most popular case for failed interceptor is | |
| 640 // CONSTANT_FUNCTION sitting below. | |
| 641 if (lookup->type() == CONSTANT_FUNCTION) { | |
| 642 function = lookup->GetConstantFunction(); | |
| 643 // JSArray holder is a special case for call constant function | |
| 644 // (see the corresponding code). | |
| 645 if (function->is_compiled() && !holder_obj->IsJSArray()) { | |
| 646 optimize = true; | |
| 647 } | |
| 648 } | |
| 649 | 593 |
| 650 if (!optimize) { | 594 // Check that the maps haven't changed. |
| 651 CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label); | 595 Register reg = |
| 652 return; | 596 stub_compiler->CheckPrototypes(object, receiver, holder, |
| 653 } | 597 scratch1, scratch2, name, miss); |
| 654 | 598 |
| 655 // Constant functions cannot sit on global object. | 599 if (lookup->IsValid() && lookup->IsCacheable()) { |
| 656 ASSERT(!lookup->holder()->IsGlobalObject()); | 600 compiler->CompileCacheable(masm, |
| 657 | 601 stub_compiler, |
| 658 __ EnterInternalFrame(); | 602 receiver, |
| 659 __ push(holder); // Save the holder. | 603 reg, |
| 660 __ push(name_); // Save the name. | 604 scratch1, |
| 661 | 605 scratch2, |
| 662 CompileCallLoadPropertyWithInterceptor(masm, | 606 holder, |
| 663 receiver, | 607 lookup, |
| 664 holder, | 608 name, |
| 665 name_, | 609 miss); |
| 666 holder_obj); | 610 } else { |
| 667 | 611 compiler->CompileRegular(masm, |
| 668 ASSERT(!r0.is(name_)); | 612 receiver, |
| 669 ASSERT(!r0.is(scratch1)); | 613 reg, |
| 670 __ pop(name_); // Restore the name. | 614 scratch2, |
| 671 __ pop(scratch1); // Restore the holder. | 615 holder, |
| 672 __ LeaveInternalFrame(); | 616 miss); |
| 673 | |
| 674 // Compare with no_interceptor_result_sentinel. | |
| 675 __ LoadRoot(scratch2, Heap::kNoInterceptorResultSentinelRootIndex); | |
| 676 __ cmp(r0, scratch2); | |
| 677 Label invoke; | |
| 678 __ b(ne, &invoke); | |
| 679 | |
| 680 stub_compiler->CheckPrototypes(holder_obj, scratch1, | |
| 681 lookup->holder(), scratch1, | |
| 682 scratch2, | |
| 683 name, | |
| 684 miss_label); | |
| 685 GenerateCallConstFunction(masm, function, arguments_); | |
| 686 | |
| 687 __ bind(&invoke); | |
| 688 } | 617 } |
| 689 | 618 } |
| 690 void CompileRegular(MacroAssembler* masm, | |
| 691 Register receiver, | |
| 692 Register holder, | |
| 693 Register scratch, | |
| 694 JSObject* holder_obj, | |
| 695 Label* miss_label) { | |
| 696 __ EnterInternalFrame(); | |
| 697 // Save the name_ register across the call. | |
| 698 __ push(name_); | |
| 699 | |
| 700 PushInterceptorArguments(masm, | |
| 701 receiver, | |
| 702 holder, | |
| 703 name_, | |
| 704 holder_obj); | |
| 705 | |
| 706 ExternalReference ref = ExternalReference( | |
| 707 IC_Utility(IC::kLoadPropertyWithInterceptorForCall)); | |
| 708 __ mov(r0, Operand(5)); | |
| 709 __ mov(r1, Operand(ref)); | |
| 710 | |
| 711 CEntryStub stub(1); | |
| 712 __ CallStub(&stub); | |
| 713 | |
| 714 // Restore the name_ register. | |
| 715 __ pop(name_); | |
| 716 __ LeaveInternalFrame(); | |
| 717 } | |
| 718 | |
| 719 private: | |
| 720 const ParameterCount& arguments_; | |
| 721 int argc_; | |
| 722 Register name_; | |
| 723 }; | |
| 724 | 619 |
| 725 | 620 |
| 726 #undef __ | 621 #undef __ |
| 727 #define __ ACCESS_MASM(masm()) | 622 #define __ ACCESS_MASM(masm()) |
| 728 | 623 |
| 729 | 624 |
| 730 Register StubCompiler::CheckPrototypes(JSObject* object, | 625 Register StubCompiler::CheckPrototypes(JSObject* object, |
| 731 Register object_reg, | 626 Register object_reg, |
| 732 JSObject* holder, | 627 JSObject* holder, |
| 733 Register holder_reg, | 628 Register holder_reg, |
| (...skipping 23 matching lines...) Expand all Loading... |
| 757 __ mov(scratch, Operand(Handle<Object>(cell))); | 652 __ mov(scratch, Operand(Handle<Object>(cell))); |
| 758 __ ldr(scratch, | 653 __ ldr(scratch, |
| 759 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); | 654 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); |
| 760 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 655 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 761 __ cmp(scratch, ip); | 656 __ cmp(scratch, ip); |
| 762 __ b(ne, miss); | 657 __ b(ne, miss); |
| 763 } | 658 } |
| 764 object = JSObject::cast(object->GetPrototype()); | 659 object = JSObject::cast(object->GetPrototype()); |
| 765 } | 660 } |
| 766 | 661 |
| 767 // Return the register containin the holder. | 662 // Return the register containing the holder. |
| 768 return result; | 663 return result; |
| 769 } | 664 } |
| 770 | 665 |
| 771 | 666 |
| 772 void StubCompiler::GenerateLoadField(JSObject* object, | 667 void StubCompiler::GenerateLoadField(JSObject* object, |
| 773 JSObject* holder, | 668 JSObject* holder, |
| 774 Register receiver, | 669 Register receiver, |
| 775 Register scratch1, | 670 Register scratch1, |
| 776 Register scratch2, | 671 Register scratch2, |
| 777 int index, | 672 int index, |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1068 return GetCode(CONSTANT_FUNCTION, function_name); | 963 return GetCode(CONSTANT_FUNCTION, function_name); |
| 1069 } | 964 } |
| 1070 | 965 |
| 1071 | 966 |
| 1072 Object* CallStubCompiler::CompileCallInterceptor(Object* object, | 967 Object* CallStubCompiler::CompileCallInterceptor(Object* object, |
| 1073 JSObject* holder, | 968 JSObject* holder, |
| 1074 String* name) { | 969 String* name) { |
| 1075 // ----------- S t a t e ------------- | 970 // ----------- S t a t e ------------- |
| 1076 // -- lr: return address | 971 // -- lr: return address |
| 1077 // ----------------------------------- | 972 // ----------------------------------- |
| 973 ASSERT(holder->HasNamedInterceptor()); |
| 974 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); |
| 1078 Label miss; | 975 Label miss; |
| 1079 | 976 |
| 977 const Register receiver = r0; |
| 978 const Register name_reg = r1; |
| 979 const Register holder_reg = r2; |
| 980 const Register scratch = r3; |
| 981 |
| 1080 // Get the number of arguments. | 982 // Get the number of arguments. |
| 1081 const int argc = arguments().immediate(); | 983 const int argc = arguments().immediate(); |
| 1082 | 984 |
| 1083 LookupResult lookup; | 985 LookupResult lookup; |
| 1084 LookupPostInterceptor(holder, name, &lookup); | 986 LookupPostInterceptor(holder, name, &lookup); |
| 1085 | 987 |
| 1086 // Get the receiver from the stack into r0. | 988 // Load the receiver from the stack. |
| 1087 __ ldr(r0, MemOperand(sp, argc * kPointerSize)); | 989 __ ldr(receiver, MemOperand(sp, argc * kPointerSize)); |
| 1088 // Load the name from the stack into r1. | 990 // Load the name from the stack. |
| 1089 __ ldr(r1, MemOperand(sp, (argc + 1) * kPointerSize)); | 991 __ ldr(name_reg, MemOperand(sp, (argc + 1) * kPointerSize)); |
| 1090 | 992 |
| 1091 CallInterceptorCompiler compiler(arguments(), r1); | 993 // Check that the receiver isn't a smi. |
| 1092 CompileLoadInterceptor(&compiler, | 994 __ BranchOnSmi(receiver, &miss); |
| 1093 this, | 995 |
| 1094 masm(), | 996 // Check that the maps haven't changed. |
| 1095 JSObject::cast(object), | 997 Register reg = |
| 1096 holder, | 998 CheckPrototypes(JSObject::cast(object), receiver, holder, |
| 1097 name, | 999 holder_reg, scratch, name, &miss); |
| 1098 &lookup, | 1000 if (!reg.is(holder_reg)) { |
| 1099 r0, | 1001 __ mov(holder_reg, reg); |
| 1100 r2, | 1002 } |
| 1101 r3, | 1003 |
| 1102 &miss); | 1004 // If we call a constant function when the interceptor returns |
| 1005 // the no-result sentinel, generate code that optimizes this case. |
| 1006 if (lookup.IsValid() && |
| 1007 lookup.IsCacheable() && |
| 1008 lookup.type() == CONSTANT_FUNCTION && |
| 1009 lookup.GetConstantFunction()->is_compiled() && |
| 1010 !holder->IsJSArray()) { |
| 1011 // Constant functions cannot sit on global object. |
| 1012 ASSERT(!lookup.holder()->IsGlobalObject()); |
| 1013 |
| 1014 // Call the interceptor. |
| 1015 __ EnterInternalFrame(); |
| 1016 __ push(holder_reg); |
| 1017 __ push(name_reg); |
| 1018 CompileCallLoadPropertyWithInterceptor(masm(), |
| 1019 receiver, |
| 1020 holder_reg, |
| 1021 name_reg, |
| 1022 holder); |
| 1023 __ pop(name_reg); |
| 1024 __ pop(holder_reg); |
| 1025 __ LeaveInternalFrame(); |
| 1026 // r0 no longer contains the receiver. |
| 1027 |
| 1028 // If interceptor returns no-result sentinal, call the constant function. |
| 1029 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex); |
| 1030 __ cmp(r0, scratch); |
| 1031 Label invoke; |
| 1032 __ b(ne, &invoke); |
| 1033 // Check the prototypes between the interceptor's holder and the |
| 1034 // constant function's holder. |
| 1035 CheckPrototypes(holder, holder_reg, |
| 1036 lookup.holder(), r0, |
| 1037 scratch, |
| 1038 name, |
| 1039 &miss); |
| 1040 GenerateCallConstFunction(masm(), |
| 1041 lookup.GetConstantFunction(), |
| 1042 arguments()); |
| 1043 __ bind(&invoke); |
| 1044 |
| 1045 } else { |
| 1046 // Call a runtime function to load the interceptor property. |
| 1047 __ EnterInternalFrame(); |
| 1048 __ push(name_reg); |
| 1049 |
| 1050 PushInterceptorArguments(masm(), receiver, holder_reg, name_reg, holder); |
| 1051 |
| 1052 ExternalReference ref = ExternalReference( |
| 1053 IC_Utility(IC::kLoadPropertyWithInterceptorForCall)); |
| 1054 __ mov(r0, Operand(5)); |
| 1055 __ mov(r1, Operand(ref)); |
| 1056 |
| 1057 CEntryStub stub(1); |
| 1058 __ CallStub(&stub); |
| 1059 |
| 1060 __ pop(name_reg); |
| 1061 __ LeaveInternalFrame(); |
| 1062 } |
| 1063 |
| 1103 | 1064 |
| 1104 // Move returned value, the function to call, to r1. | 1065 // Move returned value, the function to call, to r1. |
| 1066 // Neither receiver nor name contain their original value at this point. |
| 1105 __ mov(r1, r0); | 1067 __ mov(r1, r0); |
| 1106 // Restore receiver. | 1068 // Restore receiver. |
| 1107 __ ldr(r0, MemOperand(sp, argc * kPointerSize)); | 1069 __ ldr(receiver, MemOperand(sp, argc * kPointerSize)); |
| 1108 | 1070 |
| 1109 GenerateCallFunction(masm(), object, arguments(), &miss); | 1071 GenerateCallFunction(masm(), object, arguments(), &miss); |
| 1110 | 1072 |
| 1111 // Handle call cache miss. | 1073 // Handle call cache miss. |
| 1112 __ bind(&miss); | 1074 __ bind(&miss); |
| 1113 Handle<Code> ic = ComputeCallMiss(arguments().immediate()); | 1075 Handle<Code> ic = ComputeCallMiss(arguments().immediate()); |
| 1114 __ Jump(ic, RelocInfo::CODE_TARGET); | 1076 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 1115 | 1077 |
| 1116 // Return the generated code. | 1078 // Return the generated code. |
| 1117 return GetCode(INTERCEPTOR, name); | 1079 return GetCode(INTERCEPTOR, name); |
| (...skipping 742 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1860 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); | 1822 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); |
| 1861 | 1823 |
| 1862 // Return the generated code. | 1824 // Return the generated code. |
| 1863 return GetCode(); | 1825 return GetCode(); |
| 1864 } | 1826 } |
| 1865 | 1827 |
| 1866 | 1828 |
| 1867 #undef __ | 1829 #undef __ |
| 1868 | 1830 |
| 1869 } } // namespace v8::internal | 1831 } } // namespace v8::internal |
| OLD | NEW |