| 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 553 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 564 | 564 |
| 565 ExternalReference ref = | 565 ExternalReference ref = |
| 566 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly)); | 566 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly)); |
| 567 __ mov(r0, Operand(5)); | 567 __ mov(r0, Operand(5)); |
| 568 __ mov(r1, Operand(ref)); | 568 __ mov(r1, Operand(ref)); |
| 569 | 569 |
| 570 CEntryStub stub(1); | 570 CEntryStub stub(1); |
| 571 __ CallStub(&stub); | 571 __ CallStub(&stub); |
| 572 } | 572 } |
| 573 | 573 |
| 574 #ifdef USE_SIMULATOR |
| 575 static const int kFastApiCallArguments = 4; |
| 576 #else |
| 577 static const int kFastApiCallArguments = 3; |
| 578 #endif |
| 574 | 579 |
| 575 // Reserves space for the extra arguments to FastHandleApiCall in the | 580 // Reserves space for the extra arguments to FastHandleApiCall in the |
| 576 // caller's frame. | 581 // caller's frame. |
| 577 // | 582 // |
| 578 // These arguments are set by CheckPrototypes and GenerateFastApiCall. | 583 // These arguments are set by CheckPrototypes and GenerateFastApiCall. |
| 579 static void ReserveSpaceForFastApiCall(MacroAssembler* masm, | 584 static void ReserveSpaceForFastApiCall(MacroAssembler* masm, |
| 580 Register scratch) { | 585 Register scratch) { |
| 581 __ mov(scratch, Operand(Smi::FromInt(0))); | 586 __ mov(scratch, Operand(Smi::FromInt(0))); |
| 582 __ push(scratch); | 587 for (int i = 0; i < kFastApiCallArguments; i++) { |
| 583 __ push(scratch); | 588 __ push(scratch); |
| 584 __ push(scratch); | 589 } |
| 585 __ push(scratch); | |
| 586 } | 590 } |
| 587 | 591 |
| 588 | 592 |
| 589 // Undoes the effects of ReserveSpaceForFastApiCall. | 593 // Undoes the effects of ReserveSpaceForFastApiCall. |
| 590 static void FreeSpaceForFastApiCall(MacroAssembler* masm) { | 594 static void FreeSpaceForFastApiCall(MacroAssembler* masm) { |
| 591 __ Drop(4); | 595 __ Drop(kFastApiCallArguments); |
| 592 } | 596 } |
| 593 | 597 |
| 594 | 598 |
| 595 // Generates call to FastHandleApiCall builtin. | 599 // Generates call to FastHandleApiCall builtin. |
| 596 static void GenerateFastApiCall(MacroAssembler* masm, | 600 static void GenerateFastApiCall(MacroAssembler* masm, |
| 597 const CallOptimization& optimization, | 601 const CallOptimization& optimization, |
| 598 int argc) { | 602 int argc) { |
| 599 // Get the function and setup the context. | 603 // Get the function and setup the context. |
| 600 JSFunction* function = optimization.constant_function(); | 604 JSFunction* function = optimization.constant_function(); |
| 601 __ mov(r5, Operand(Handle<JSFunction>(function))); | 605 __ mov(r5, Operand(Handle<JSFunction>(function))); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 629 __ mov(r0, Operand(argc + 4)); | 633 __ mov(r0, Operand(argc + 4)); |
| 630 | 634 |
| 631 // Jump to the fast api call builtin (tail call). | 635 // Jump to the fast api call builtin (tail call). |
| 632 Handle<Code> code = Handle<Code>( | 636 Handle<Code> code = Handle<Code>( |
| 633 Builtins::builtin(Builtins::FastHandleApiCall)); | 637 Builtins::builtin(Builtins::FastHandleApiCall)); |
| 634 ParameterCount expected(0); | 638 ParameterCount expected(0); |
| 635 __ InvokeCode(code, expected, expected, | 639 __ InvokeCode(code, expected, expected, |
| 636 RelocInfo::CODE_TARGET, JUMP_FUNCTION); | 640 RelocInfo::CODE_TARGET, JUMP_FUNCTION); |
| 637 } | 641 } |
| 638 | 642 |
| 643 #ifndef USE_SIMULATOR |
| 644 static bool GenerateFastApiDirectCall(MacroAssembler* masm, |
| 645 const CallOptimization& optimization, |
| 646 int argc, |
| 647 Failure** failure) { |
| 648 // ----------- S t a t e ------------- |
| 649 // -- sp[0] : holder (set by CheckPrototypes) |
| 650 // -- sp[4] : callee js function |
| 651 // -- sp[8] : call data |
| 652 // -- sp[12] : last js argument |
| 653 // -- ... |
| 654 // -- sp[(argc + 3) * 4] : first js argument |
| 655 // -- sp[(argc + 4) * 4] : receiver |
| 656 // ----------------------------------- |
| 657 // Get the function and setup the context. |
| 658 JSFunction* function = optimization.constant_function(); |
| 659 __ mov(r5, Operand(Handle<JSFunction>(function))); |
| 660 __ ldr(cp, FieldMemOperand(r5, JSFunction::kContextOffset)); |
| 661 |
| 662 // Pass the additional arguments FastHandleApiCall expects. |
| 663 Object* call_data = optimization.api_call_info()->data(); |
| 664 Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info()); |
| 665 if (Heap::InNewSpace(call_data)) { |
| 666 __ Move(r0, api_call_info_handle); |
| 667 __ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kDataOffset)); |
| 668 } else { |
| 669 __ Move(r6, Handle<Object>(call_data)); |
| 670 } |
| 671 __ stm(ib, sp, r5.bit() | r6.bit()); |
| 672 |
| 673 // r2 points to calldata as expected by Arguments class (refer layout above) |
| 674 __ add(r2, sp, Operand(2 * kPointerSize)); |
| 675 |
| 676 Object* callback = optimization.api_call_info()->callback(); |
| 677 Address api_function_address = v8::ToCData<Address>(callback); |
| 678 ApiFunction fun(api_function_address); |
| 679 |
| 680 const int kApiStackSpace = 4; |
| 681 __ PrepareCallApiFunction(kApiStackSpace, |
| 682 argc + kFastApiCallArguments + 1); |
| 683 // v8::Arguments::implicit_args = data |
| 684 __ str(r2, MemOperand(sp)); |
| 685 // v8::Arguments::values = last argument |
| 686 __ add(ip, r2, Operand(argc * kPointerSize)); |
| 687 __ str(ip, MemOperand(sp, 1 * kPointerSize)); |
| 688 // v8::Arguments::length_ = argc |
| 689 __ mov(ip, Operand(argc)); |
| 690 __ str(ip, MemOperand(sp, 2 * kPointerSize)); |
| 691 // v8::Arguments::is_construct_call = 0 |
| 692 __ mov(ip, Operand(0)); |
| 693 __ str(ip, MemOperand(sp, 3 * kPointerSize)); |
| 694 // r0 = v8::Arguments& |
| 695 __ mov(r0, sp); |
| 696 |
| 697 // Emitting a stub call may try to allocate (if the code is not |
| 698 // already generated). Do not allow the assembler to perform a |
| 699 // garbage collection but instead return the allocation failure |
| 700 // object. |
| 701 MaybeObject* result = |
| 702 masm->TryCallApiFunctionAndReturn(&fun); |
| 703 if (result->IsFailure()) { |
| 704 *failure = Failure::cast(result); |
| 705 return false; |
| 706 } |
| 707 return true; |
| 708 } |
| 709 #endif |
| 710 |
| 639 | 711 |
| 640 class CallInterceptorCompiler BASE_EMBEDDED { | 712 class CallInterceptorCompiler BASE_EMBEDDED { |
| 641 public: | 713 public: |
| 642 CallInterceptorCompiler(StubCompiler* stub_compiler, | 714 CallInterceptorCompiler(StubCompiler* stub_compiler, |
| 643 const ParameterCount& arguments, | 715 const ParameterCount& arguments, |
| 644 Register name) | 716 Register name) |
| 645 : stub_compiler_(stub_compiler), | 717 : stub_compiler_(stub_compiler), |
| 646 arguments_(arguments), | 718 arguments_(arguments), |
| 647 name_(name) {} | 719 name_(name) {} |
| 648 | 720 |
| 649 void Compile(MacroAssembler* masm, | 721 bool Compile(MacroAssembler* masm, |
| 650 JSObject* object, | 722 JSObject* object, |
| 651 JSObject* holder, | 723 JSObject* holder, |
| 652 String* name, | 724 String* name, |
| 653 LookupResult* lookup, | 725 LookupResult* lookup, |
| 654 Register receiver, | 726 Register receiver, |
| 655 Register scratch1, | 727 Register scratch1, |
| 656 Register scratch2, | 728 Register scratch2, |
| 657 Register scratch3, | 729 Register scratch3, |
| 658 Label* miss) { | 730 Label* miss, |
| 731 Failure **failure) { |
| 659 ASSERT(holder->HasNamedInterceptor()); | 732 ASSERT(holder->HasNamedInterceptor()); |
| 660 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); | 733 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); |
| 661 | 734 |
| 662 // Check that the receiver isn't a smi. | 735 // Check that the receiver isn't a smi. |
| 663 __ BranchOnSmi(receiver, miss); | 736 __ BranchOnSmi(receiver, miss); |
| 664 | 737 |
| 665 CallOptimization optimization(lookup); | 738 CallOptimization optimization(lookup); |
| 666 | 739 |
| 667 if (optimization.is_constant_call()) { | 740 if (optimization.is_constant_call()) { |
| 668 CompileCacheable(masm, | 741 return CompileCacheable(masm, |
| 669 object, | 742 object, |
| 670 receiver, | 743 receiver, |
| 671 scratch1, | 744 scratch1, |
| 672 scratch2, | 745 scratch2, |
| 673 scratch3, | 746 scratch3, |
| 674 holder, | 747 holder, |
| 675 lookup, | 748 lookup, |
| 676 name, | 749 name, |
| 677 optimization, | 750 optimization, |
| 678 miss); | 751 miss, |
| 752 failure); |
| 679 } else { | 753 } else { |
| 680 CompileRegular(masm, | 754 CompileRegular(masm, |
| 681 object, | 755 object, |
| 682 receiver, | 756 receiver, |
| 683 scratch1, | 757 scratch1, |
| 684 scratch2, | 758 scratch2, |
| 685 scratch3, | 759 scratch3, |
| 686 name, | 760 name, |
| 687 holder, | 761 holder, |
| 688 miss); | 762 miss); |
| 763 return true; |
| 689 } | 764 } |
| 690 } | 765 } |
| 691 | 766 |
| 692 private: | 767 private: |
| 693 void CompileCacheable(MacroAssembler* masm, | 768 bool CompileCacheable(MacroAssembler* masm, |
| 694 JSObject* object, | 769 JSObject* object, |
| 695 Register receiver, | 770 Register receiver, |
| 696 Register scratch1, | 771 Register scratch1, |
| 697 Register scratch2, | 772 Register scratch2, |
| 698 Register scratch3, | 773 Register scratch3, |
| 699 JSObject* interceptor_holder, | 774 JSObject* interceptor_holder, |
| 700 LookupResult* lookup, | 775 LookupResult* lookup, |
| 701 String* name, | 776 String* name, |
| 702 const CallOptimization& optimization, | 777 const CallOptimization& optimization, |
| 703 Label* miss_label) { | 778 Label* miss_label, |
| 779 Failure **failure) { |
| 704 ASSERT(optimization.is_constant_call()); | 780 ASSERT(optimization.is_constant_call()); |
| 705 ASSERT(!lookup->holder()->IsGlobalObject()); | 781 ASSERT(!lookup->holder()->IsGlobalObject()); |
| 706 | 782 |
| 707 int depth1 = kInvalidProtoDepth; | 783 int depth1 = kInvalidProtoDepth; |
| 708 int depth2 = kInvalidProtoDepth; | 784 int depth2 = kInvalidProtoDepth; |
| 709 bool can_do_fast_api_call = false; | 785 bool can_do_fast_api_call = false; |
| 710 if (optimization.is_simple_api_call() && | 786 if (optimization.is_simple_api_call() && |
| 711 !lookup->holder()->IsGlobalObject()) { | 787 !lookup->holder()->IsGlobalObject()) { |
| 712 depth1 = | 788 depth1 = |
| 713 optimization.GetPrototypeDepthOfExpectedType(object, | 789 optimization.GetPrototypeDepthOfExpectedType(object, |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 757 } else { | 833 } else { |
| 758 // CheckPrototypes has a side effect of fetching a 'holder' | 834 // CheckPrototypes has a side effect of fetching a 'holder' |
| 759 // for API (object which is instanceof for the signature). It's | 835 // for API (object which is instanceof for the signature). It's |
| 760 // safe to omit it here, as if present, it should be fetched | 836 // safe to omit it here, as if present, it should be fetched |
| 761 // by the previous CheckPrototypes. | 837 // by the previous CheckPrototypes. |
| 762 ASSERT(depth2 == kInvalidProtoDepth); | 838 ASSERT(depth2 == kInvalidProtoDepth); |
| 763 } | 839 } |
| 764 | 840 |
| 765 // Invoke function. | 841 // Invoke function. |
| 766 if (can_do_fast_api_call) { | 842 if (can_do_fast_api_call) { |
| 843 #ifdef USE_SIMULATOR |
| 767 GenerateFastApiCall(masm, optimization, arguments_.immediate()); | 844 GenerateFastApiCall(masm, optimization, arguments_.immediate()); |
| 845 #else |
| 846 bool success = GenerateFastApiDirectCall(masm, |
| 847 optimization, |
| 848 arguments_.immediate(), |
| 849 failure); |
| 850 if (!success) { |
| 851 return false; |
| 852 } |
| 853 #endif |
| 768 } else { | 854 } else { |
| 769 __ InvokeFunction(optimization.constant_function(), arguments_, | 855 __ InvokeFunction(optimization.constant_function(), arguments_, |
| 770 JUMP_FUNCTION); | 856 JUMP_FUNCTION); |
| 771 } | 857 } |
| 772 | 858 |
| 773 // Deferred code for fast API call case---clean preallocated space. | 859 // Deferred code for fast API call case---clean preallocated space. |
| 774 if (can_do_fast_api_call) { | 860 if (can_do_fast_api_call) { |
| 775 __ bind(&miss_cleanup); | 861 __ bind(&miss_cleanup); |
| 776 FreeSpaceForFastApiCall(masm); | 862 FreeSpaceForFastApiCall(masm); |
| 777 __ b(miss_label); | 863 __ b(miss_label); |
| 778 } | 864 } |
| 779 | 865 |
| 780 // Invoke a regular function. | 866 // Invoke a regular function. |
| 781 __ bind(®ular_invoke); | 867 __ bind(®ular_invoke); |
| 782 if (can_do_fast_api_call) { | 868 if (can_do_fast_api_call) { |
| 783 FreeSpaceForFastApiCall(masm); | 869 FreeSpaceForFastApiCall(masm); |
| 784 } | 870 } |
| 871 |
| 872 return true; |
| 785 } | 873 } |
| 786 | 874 |
| 787 void CompileRegular(MacroAssembler* masm, | 875 void CompileRegular(MacroAssembler* masm, |
| 788 JSObject* object, | 876 JSObject* object, |
| 789 Register receiver, | 877 Register receiver, |
| 790 Register scratch1, | 878 Register scratch1, |
| 791 Register scratch2, | 879 Register scratch2, |
| 792 Register scratch3, | 880 Register scratch3, |
| 793 String* name, | 881 String* name, |
| 794 JSObject* interceptor_holder, | 882 JSObject* interceptor_holder, |
| (...skipping 1436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2231 r1, r4, name, &miss); | 2319 r1, r4, name, &miss); |
| 2232 } | 2320 } |
| 2233 break; | 2321 break; |
| 2234 } | 2322 } |
| 2235 | 2323 |
| 2236 default: | 2324 default: |
| 2237 UNREACHABLE(); | 2325 UNREACHABLE(); |
| 2238 } | 2326 } |
| 2239 | 2327 |
| 2240 if (depth != kInvalidProtoDepth) { | 2328 if (depth != kInvalidProtoDepth) { |
| 2329 #ifdef USE_SIMULATOR |
| 2241 GenerateFastApiCall(masm(), optimization, argc); | 2330 GenerateFastApiCall(masm(), optimization, argc); |
| 2331 #else |
| 2332 Failure* failure; |
| 2333 bool success = GenerateFastApiDirectCall(masm(), |
| 2334 optimization, |
| 2335 argc, |
| 2336 &failure); |
| 2337 if (!success) { |
| 2338 return failure; |
| 2339 } |
| 2340 #endif |
| 2242 } else { | 2341 } else { |
| 2243 __ InvokeFunction(function, arguments(), JUMP_FUNCTION); | 2342 __ InvokeFunction(function, arguments(), JUMP_FUNCTION); |
| 2244 } | 2343 } |
| 2245 | 2344 |
| 2246 // Handle call cache miss. | 2345 // Handle call cache miss. |
| 2247 __ bind(&miss); | 2346 __ bind(&miss); |
| 2248 if (depth != kInvalidProtoDepth) { | 2347 if (depth != kInvalidProtoDepth) { |
| 2249 FreeSpaceForFastApiCall(masm()); | 2348 FreeSpaceForFastApiCall(masm()); |
| 2250 } | 2349 } |
| 2251 | 2350 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2275 // Get the number of arguments. | 2374 // Get the number of arguments. |
| 2276 const int argc = arguments().immediate(); | 2375 const int argc = arguments().immediate(); |
| 2277 | 2376 |
| 2278 LookupResult lookup; | 2377 LookupResult lookup; |
| 2279 LookupPostInterceptor(holder, name, &lookup); | 2378 LookupPostInterceptor(holder, name, &lookup); |
| 2280 | 2379 |
| 2281 // Get the receiver from the stack. | 2380 // Get the receiver from the stack. |
| 2282 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); | 2381 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); |
| 2283 | 2382 |
| 2284 CallInterceptorCompiler compiler(this, arguments(), r2); | 2383 CallInterceptorCompiler compiler(this, arguments(), r2); |
| 2285 compiler.Compile(masm(), | 2384 Failure *failure; |
| 2385 bool success = compiler.Compile(masm(), |
| 2286 object, | 2386 object, |
| 2287 holder, | 2387 holder, |
| 2288 name, | 2388 name, |
| 2289 &lookup, | 2389 &lookup, |
| 2290 r1, | 2390 r1, |
| 2291 r3, | 2391 r3, |
| 2292 r4, | 2392 r4, |
| 2293 r0, | 2393 r0, |
| 2294 &miss); | 2394 &miss, |
| 2395 &failure); |
| 2396 if (!success) { |
| 2397 return false; |
| 2398 } |
| 2295 | 2399 |
| 2296 // Move returned value, the function to call, to r1. | 2400 // Move returned value, the function to call, to r1. |
| 2297 __ mov(r1, r0); | 2401 __ mov(r1, r0); |
| 2298 // Restore receiver. | 2402 // Restore receiver. |
| 2299 __ ldr(r0, MemOperand(sp, argc * kPointerSize)); | 2403 __ ldr(r0, MemOperand(sp, argc * kPointerSize)); |
| 2300 | 2404 |
| 2301 GenerateCallFunction(masm(), object, arguments(), &miss); | 2405 GenerateCallFunction(masm(), object, arguments(), &miss); |
| 2302 | 2406 |
| 2303 // Handle call cache miss. | 2407 // Handle call cache miss. |
| 2304 __ bind(&miss); | 2408 __ bind(&miss); |
| (...skipping 895 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3200 // Return the generated code. | 3304 // Return the generated code. |
| 3201 return GetCode(); | 3305 return GetCode(); |
| 3202 } | 3306 } |
| 3203 | 3307 |
| 3204 | 3308 |
| 3205 #undef __ | 3309 #undef __ |
| 3206 | 3310 |
| 3207 } } // namespace v8::internal | 3311 } } // namespace v8::internal |
| 3208 | 3312 |
| 3209 #endif // V8_TARGET_ARCH_ARM | 3313 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |