| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset)); | 288 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset)); |
| 289 } | 289 } |
| 290 | 290 |
| 291 | 291 |
| 292 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( | 292 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( |
| 293 MacroAssembler* masm, | 293 MacroAssembler* masm, |
| 294 int index, | 294 int index, |
| 295 Register prototype, | 295 Register prototype, |
| 296 Label* miss) { | 296 Label* miss) { |
| 297 Isolate* isolate = masm->isolate(); | 297 Isolate* isolate = masm->isolate(); |
| 298 // Check we're still in the same context. | |
| 299 __ ldr(prototype, | |
| 300 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); | |
| 301 __ Move(ip, isolate->global_object()); | |
| 302 __ cmp(prototype, ip); | |
| 303 __ b(ne, miss); | |
| 304 // Get the global function with the given index. | 298 // Get the global function with the given index. |
| 305 Handle<JSFunction> function( | 299 Handle<JSFunction> function( |
| 306 JSFunction::cast(isolate->native_context()->get(index))); | 300 JSFunction::cast(isolate->native_context()->get(index))); |
| 301 |
| 302 // Check we're still in the same context. |
| 303 Register scratch = prototype; |
| 304 const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX); |
| 305 __ ldr(scratch, MemOperand(cp, offset)); |
| 306 __ ldr(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset)); |
| 307 __ ldr(scratch, MemOperand(scratch, Context::SlotOffset(index))); |
| 308 __ Move(ip, function); |
| 309 __ cmp(ip, scratch); |
| 310 __ b(ne, miss); |
| 311 |
| 307 // Load its initial map. The global functions all have initial maps. | 312 // Load its initial map. The global functions all have initial maps. |
| 308 __ Move(prototype, Handle<Map>(function->initial_map())); | 313 __ Move(prototype, Handle<Map>(function->initial_map())); |
| 309 // Load the prototype from the initial map. | 314 // Load the prototype from the initial map. |
| 310 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset)); | 315 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset)); |
| 311 } | 316 } |
| 312 | 317 |
| 313 | 318 |
| 314 void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, | 319 void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, |
| 315 Register dst, | 320 Register dst, |
| 316 Register src, | 321 Register src, |
| (...skipping 453 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 770 Register name, | 775 Register name, |
| 771 Handle<JSObject> holder_obj, | 776 Handle<JSObject> holder_obj, |
| 772 IC::UtilityId id) { | 777 IC::UtilityId id) { |
| 773 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); | 778 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); |
| 774 __ CallExternalReference( | 779 __ CallExternalReference( |
| 775 ExternalReference(IC_Utility(id), masm->isolate()), | 780 ExternalReference(IC_Utility(id), masm->isolate()), |
| 776 StubCache::kInterceptorArgsLength); | 781 StubCache::kInterceptorArgsLength); |
| 777 } | 782 } |
| 778 | 783 |
| 779 | 784 |
| 780 static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength; | 785 // Generate call to api function. |
| 786 void StubCompiler::GenerateFastApiCall(MacroAssembler* masm, |
| 787 const CallOptimization& optimization, |
| 788 Handle<Map> receiver_map, |
| 789 Register receiver, |
| 790 Register scratch_in, |
| 791 bool is_store, |
| 792 int argc, |
| 793 Register* values) { |
| 794 ASSERT(!receiver.is(scratch_in)); |
| 795 __ push(receiver); |
| 796 // Write the arguments to stack frame. |
| 797 for (int i = 0; i < argc; i++) { |
| 798 Register arg = values[argc-1-i]; |
| 799 ASSERT(!receiver.is(arg)); |
| 800 ASSERT(!scratch_in.is(arg)); |
| 801 __ push(arg); |
| 802 } |
| 803 ASSERT(optimization.is_simple_api_call()); |
| 781 | 804 |
| 782 // Reserves space for the extra arguments to API function in the | 805 // Abi for CallApiFunctionStub. |
| 783 // caller's frame. | 806 Register callee = r0; |
| 784 // | 807 Register call_data = r4; |
| 785 // These arguments are set by CheckPrototypes and GenerateFastApiDirectCall. | 808 Register holder = r2; |
| 786 static void ReserveSpaceForFastApiCall(MacroAssembler* masm, | 809 Register api_function_address = r1; |
| 787 Register scratch) { | 810 |
| 788 __ mov(scratch, Operand(Smi::FromInt(0))); | 811 // Put holder in place. |
| 789 for (int i = 0; i < kFastApiCallArguments; i++) { | 812 CallOptimization::HolderLookup holder_lookup; |
| 790 __ push(scratch); | 813 Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType( |
| 814 receiver_map, |
| 815 &holder_lookup); |
| 816 switch (holder_lookup) { |
| 817 case CallOptimization::kHolderIsReceiver: |
| 818 __ Move(holder, receiver); |
| 819 break; |
| 820 case CallOptimization::kHolderFound: |
| 821 __ Move(holder, api_holder); |
| 822 break; |
| 823 case CallOptimization::kHolderNotFound: |
| 824 UNREACHABLE(); |
| 825 break; |
| 791 } | 826 } |
| 792 } | |
| 793 | 827 |
| 828 Isolate* isolate = masm->isolate(); |
| 829 Handle<JSFunction> function = optimization.constant_function(); |
| 830 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); |
| 831 Handle<Object> call_data_obj(api_call_info->data(), isolate); |
| 794 | 832 |
| 795 // Undoes the effects of ReserveSpaceForFastApiCall. | 833 // Put callee in place. |
| 796 static void FreeSpaceForFastApiCall(MacroAssembler* masm) { | 834 __ Move(callee, function); |
| 797 __ Drop(kFastApiCallArguments); | |
| 798 } | |
| 799 | 835 |
| 836 bool call_data_undefined = false; |
| 837 // Put call_data in place. |
| 838 if (isolate->heap()->InNewSpace(*call_data_obj)) { |
| 839 __ Move(call_data, api_call_info); |
| 840 __ ldr(call_data, FieldMemOperand(call_data, CallHandlerInfo::kDataOffset)); |
| 841 } else if (call_data_obj->IsUndefined()) { |
| 842 call_data_undefined = true; |
| 843 __ LoadRoot(call_data, Heap::kUndefinedValueRootIndex); |
| 844 } else { |
| 845 __ Move(call_data, call_data_obj); |
| 846 } |
| 800 | 847 |
| 801 static void GenerateFastApiDirectCall(MacroAssembler* masm, | 848 // Put api_function_address in place. |
| 802 const CallOptimization& optimization, | |
| 803 int argc, | |
| 804 bool restore_context) { | |
| 805 // ----------- S t a t e ------------- | |
| 806 // -- sp[0] - sp[24] : FunctionCallbackInfo, incl. | |
| 807 // : holder (set by CheckPrototypes) | |
| 808 // -- sp[28] : last JS argument | |
| 809 // -- ... | |
| 810 // -- sp[(argc + 6) * 4] : first JS argument | |
| 811 // -- sp[(argc + 7) * 4] : receiver | |
| 812 // ----------------------------------- | |
| 813 typedef FunctionCallbackArguments FCA; | |
| 814 // Save calling context. | |
| 815 __ str(cp, MemOperand(sp, FCA::kContextSaveIndex * kPointerSize)); | |
| 816 // Get the function and setup the context. | |
| 817 Handle<JSFunction> function = optimization.constant_function(); | |
| 818 __ Move(r5, function); | |
| 819 __ ldr(cp, FieldMemOperand(r5, JSFunction::kContextOffset)); | |
| 820 __ str(r5, MemOperand(sp, FCA::kCalleeIndex * kPointerSize)); | |
| 821 | |
| 822 // Construct the FunctionCallbackInfo. | |
| 823 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); | |
| 824 Handle<Object> call_data(api_call_info->data(), masm->isolate()); | |
| 825 if (masm->isolate()->heap()->InNewSpace(*call_data)) { | |
| 826 __ Move(r0, api_call_info); | |
| 827 __ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kDataOffset)); | |
| 828 } else { | |
| 829 __ Move(r6, call_data); | |
| 830 } | |
| 831 // Store call data. | |
| 832 __ str(r6, MemOperand(sp, FCA::kDataIndex * kPointerSize)); | |
| 833 // Store isolate. | |
| 834 __ mov(r5, Operand(ExternalReference::isolate_address(masm->isolate()))); | |
| 835 __ str(r5, MemOperand(sp, FCA::kIsolateIndex * kPointerSize)); | |
| 836 // Store ReturnValue default and ReturnValue. | |
| 837 __ LoadRoot(r5, Heap::kUndefinedValueRootIndex); | |
| 838 __ str(r5, MemOperand(sp, FCA::kReturnValueOffset * kPointerSize)); | |
| 839 __ str(r5, MemOperand(sp, FCA::kReturnValueDefaultValueIndex * kPointerSize)); | |
| 840 | |
| 841 // Prepare arguments. | |
| 842 __ mov(r2, sp); | |
| 843 | |
| 844 // Allocate the v8::Arguments structure in the arguments' space since | |
| 845 // it's not controlled by GC. | |
| 846 const int kApiStackSpace = 4; | |
| 847 | |
| 848 FrameScope frame_scope(masm, StackFrame::MANUAL); | |
| 849 __ EnterExitFrame(false, kApiStackSpace); | |
| 850 | |
| 851 // r0 = FunctionCallbackInfo& | |
| 852 // Arguments is after the return address. | |
| 853 __ add(r0, sp, Operand(1 * kPointerSize)); | |
| 854 // FunctionCallbackInfo::implicit_args_ | |
| 855 __ str(r2, MemOperand(r0, 0 * kPointerSize)); | |
| 856 // FunctionCallbackInfo::values_ | |
| 857 __ add(ip, r2, Operand((kFastApiCallArguments - 1 + argc) * kPointerSize)); | |
| 858 __ str(ip, MemOperand(r0, 1 * kPointerSize)); | |
| 859 // FunctionCallbackInfo::length_ = argc | |
| 860 __ mov(ip, Operand(argc)); | |
| 861 __ str(ip, MemOperand(r0, 2 * kPointerSize)); | |
| 862 // FunctionCallbackInfo::is_construct_call = 0 | |
| 863 __ mov(ip, Operand::Zero()); | |
| 864 __ str(ip, MemOperand(r0, 3 * kPointerSize)); | |
| 865 | |
| 866 const int kStackUnwindSpace = argc + kFastApiCallArguments + 1; | |
| 867 Address function_address = v8::ToCData<Address>(api_call_info->callback()); | 849 Address function_address = v8::ToCData<Address>(api_call_info->callback()); |
| 868 ApiFunction fun(function_address); | 850 ApiFunction fun(function_address); |
| 869 ExternalReference::Type type = ExternalReference::DIRECT_API_CALL; | 851 ExternalReference::Type type = ExternalReference::DIRECT_API_CALL; |
| 870 ExternalReference ref = ExternalReference(&fun, | 852 ExternalReference ref = ExternalReference(&fun, |
| 871 type, | 853 type, |
| 872 masm->isolate()); | 854 masm->isolate()); |
| 873 Address thunk_address = FUNCTION_ADDR(&InvokeFunctionCallback); | 855 __ mov(api_function_address, Operand(ref)); |
| 874 ExternalReference::Type thunk_type = ExternalReference::PROFILING_API_CALL; | |
| 875 ApiFunction thunk_fun(thunk_address); | |
| 876 ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type, | |
| 877 masm->isolate()); | |
| 878 | 856 |
| 879 AllowExternalCallThatCantCauseGC scope(masm); | 857 // Jump to stub. |
| 880 MemOperand context_restore_operand( | 858 CallApiFunctionStub stub(is_store, call_data_undefined, argc); |
| 881 fp, (2 + FCA::kContextSaveIndex) * kPointerSize); | 859 __ TailCallStub(&stub); |
| 882 MemOperand return_value_operand(fp, | |
| 883 (2 + FCA::kReturnValueOffset) * kPointerSize); | |
| 884 | |
| 885 __ CallApiFunctionAndReturn(ref, | |
| 886 function_address, | |
| 887 thunk_ref, | |
| 888 r1, | |
| 889 kStackUnwindSpace, | |
| 890 return_value_operand, | |
| 891 restore_context ? | |
| 892 &context_restore_operand : NULL); | |
| 893 } | 860 } |
| 894 | 861 |
| 895 | 862 |
| 896 // Generate call to api function. | |
| 897 static void GenerateFastApiCall(MacroAssembler* masm, | |
| 898 const CallOptimization& optimization, | |
| 899 Register receiver, | |
| 900 Register scratch, | |
| 901 int argc, | |
| 902 Register* values) { | |
| 903 ASSERT(optimization.is_simple_api_call()); | |
| 904 ASSERT(!receiver.is(scratch)); | |
| 905 | |
| 906 typedef FunctionCallbackArguments FCA; | |
| 907 const int stack_space = kFastApiCallArguments + argc + 1; | |
| 908 // Assign stack space for the call arguments. | |
| 909 __ sub(sp, sp, Operand(stack_space * kPointerSize)); | |
| 910 // Write holder to stack frame. | |
| 911 __ str(receiver, MemOperand(sp, FCA::kHolderIndex * kPointerSize)); | |
| 912 // Write receiver to stack frame. | |
| 913 int index = stack_space - 1; | |
| 914 __ str(receiver, MemOperand(sp, index-- * kPointerSize)); | |
| 915 // Write the arguments to stack frame. | |
| 916 for (int i = 0; i < argc; i++) { | |
| 917 ASSERT(!receiver.is(values[i])); | |
| 918 ASSERT(!scratch.is(values[i])); | |
| 919 __ str(values[i], MemOperand(sp, index-- * kPointerSize)); | |
| 920 } | |
| 921 | |
| 922 GenerateFastApiDirectCall(masm, optimization, argc, true); | |
| 923 } | |
| 924 | |
| 925 | |
| 926 class CallInterceptorCompiler BASE_EMBEDDED { | |
| 927 public: | |
| 928 CallInterceptorCompiler(CallStubCompiler* stub_compiler, | |
| 929 const ParameterCount& arguments, | |
| 930 Register name) | |
| 931 : stub_compiler_(stub_compiler), | |
| 932 arguments_(arguments), | |
| 933 name_(name) {} | |
| 934 | |
| 935 void Compile(MacroAssembler* masm, | |
| 936 Handle<JSObject> object, | |
| 937 Handle<JSObject> holder, | |
| 938 Handle<Name> name, | |
| 939 LookupResult* lookup, | |
| 940 Register receiver, | |
| 941 Register scratch1, | |
| 942 Register scratch2, | |
| 943 Register scratch3, | |
| 944 Label* miss) { | |
| 945 ASSERT(holder->HasNamedInterceptor()); | |
| 946 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); | |
| 947 | |
| 948 // Check that the receiver isn't a smi. | |
| 949 __ JumpIfSmi(receiver, miss); | |
| 950 CallOptimization optimization(lookup); | |
| 951 if (optimization.is_constant_call()) { | |
| 952 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3, | |
| 953 holder, lookup, name, optimization, miss); | |
| 954 } else { | |
| 955 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3, | |
| 956 name, holder, miss); | |
| 957 } | |
| 958 } | |
| 959 | |
| 960 private: | |
| 961 void CompileCacheable(MacroAssembler* masm, | |
| 962 Handle<JSObject> object, | |
| 963 Register receiver, | |
| 964 Register scratch1, | |
| 965 Register scratch2, | |
| 966 Register scratch3, | |
| 967 Handle<JSObject> interceptor_holder, | |
| 968 LookupResult* lookup, | |
| 969 Handle<Name> name, | |
| 970 const CallOptimization& optimization, | |
| 971 Label* miss_label) { | |
| 972 ASSERT(optimization.is_constant_call()); | |
| 973 ASSERT(!lookup->holder()->IsGlobalObject()); | |
| 974 Counters* counters = masm->isolate()->counters(); | |
| 975 int depth1 = kInvalidProtoDepth; | |
| 976 int depth2 = kInvalidProtoDepth; | |
| 977 bool can_do_fast_api_call = false; | |
| 978 if (optimization.is_simple_api_call() && | |
| 979 !lookup->holder()->IsGlobalObject()) { | |
| 980 depth1 = optimization.GetPrototypeDepthOfExpectedType( | |
| 981 object, interceptor_holder); | |
| 982 if (depth1 == kInvalidProtoDepth) { | |
| 983 depth2 = optimization.GetPrototypeDepthOfExpectedType( | |
| 984 interceptor_holder, Handle<JSObject>(lookup->holder())); | |
| 985 } | |
| 986 can_do_fast_api_call = | |
| 987 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth; | |
| 988 } | |
| 989 | |
| 990 __ IncrementCounter(counters->call_const_interceptor(), 1, | |
| 991 scratch1, scratch2); | |
| 992 | |
| 993 if (can_do_fast_api_call) { | |
| 994 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1, | |
| 995 scratch1, scratch2); | |
| 996 ReserveSpaceForFastApiCall(masm, scratch1); | |
| 997 } | |
| 998 | |
| 999 // Check that the maps from receiver to interceptor's holder | |
| 1000 // haven't changed and thus we can invoke interceptor. | |
| 1001 Label miss_cleanup; | |
| 1002 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; | |
| 1003 Register holder = | |
| 1004 stub_compiler_->CheckPrototypes( | |
| 1005 IC::CurrentTypeOf(object, masm->isolate()), receiver, | |
| 1006 interceptor_holder, scratch1, scratch2, scratch3, | |
| 1007 name, depth1, miss); | |
| 1008 | |
| 1009 // Invoke an interceptor and if it provides a value, | |
| 1010 // branch to |regular_invoke|. | |
| 1011 Label regular_invoke; | |
| 1012 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2, | |
| 1013 ®ular_invoke); | |
| 1014 | |
| 1015 // Interceptor returned nothing for this property. Try to use cached | |
| 1016 // constant function. | |
| 1017 | |
| 1018 // Check that the maps from interceptor's holder to constant function's | |
| 1019 // holder haven't changed and thus we can use cached constant function. | |
| 1020 if (*interceptor_holder != lookup->holder()) { | |
| 1021 stub_compiler_->CheckPrototypes( | |
| 1022 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, | |
| 1023 handle(lookup->holder()), scratch1, scratch2, scratch3, | |
| 1024 name, depth2, miss); | |
| 1025 } else { | |
| 1026 // CheckPrototypes has a side effect of fetching a 'holder' | |
| 1027 // for API (object which is instanceof for the signature). It's | |
| 1028 // safe to omit it here, as if present, it should be fetched | |
| 1029 // by the previous CheckPrototypes. | |
| 1030 ASSERT(depth2 == kInvalidProtoDepth); | |
| 1031 } | |
| 1032 | |
| 1033 // Invoke function. | |
| 1034 if (can_do_fast_api_call) { | |
| 1035 GenerateFastApiDirectCall( | |
| 1036 masm, optimization, arguments_.immediate(), false); | |
| 1037 } else { | |
| 1038 Handle<JSFunction> function = optimization.constant_function(); | |
| 1039 __ Move(r0, receiver); | |
| 1040 stub_compiler_->GenerateJumpFunction(object, function); | |
| 1041 } | |
| 1042 | |
| 1043 // Deferred code for fast API call case---clean preallocated space. | |
| 1044 if (can_do_fast_api_call) { | |
| 1045 __ bind(&miss_cleanup); | |
| 1046 FreeSpaceForFastApiCall(masm); | |
| 1047 __ b(miss_label); | |
| 1048 } | |
| 1049 | |
| 1050 // Invoke a regular function. | |
| 1051 __ bind(®ular_invoke); | |
| 1052 if (can_do_fast_api_call) { | |
| 1053 FreeSpaceForFastApiCall(masm); | |
| 1054 } | |
| 1055 } | |
| 1056 | |
| 1057 void CompileRegular(MacroAssembler* masm, | |
| 1058 Handle<JSObject> object, | |
| 1059 Register receiver, | |
| 1060 Register scratch1, | |
| 1061 Register scratch2, | |
| 1062 Register scratch3, | |
| 1063 Handle<Name> name, | |
| 1064 Handle<JSObject> interceptor_holder, | |
| 1065 Label* miss_label) { | |
| 1066 Register holder = | |
| 1067 stub_compiler_->CheckPrototypes( | |
| 1068 IC::CurrentTypeOf(object, masm->isolate()), receiver, | |
| 1069 interceptor_holder, scratch1, scratch2, scratch3, name, miss_label); | |
| 1070 | |
| 1071 // Call a runtime function to load the interceptor property. | |
| 1072 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 1073 // Save the name_ register across the call. | |
| 1074 __ push(name_); | |
| 1075 | |
| 1076 CompileCallLoadPropertyWithInterceptor( | |
| 1077 masm, receiver, holder, name_, interceptor_holder, | |
| 1078 IC::kLoadPropertyWithInterceptorForCall); | |
| 1079 | |
| 1080 // Restore the name_ register. | |
| 1081 __ pop(name_); | |
| 1082 // Leave the internal frame. | |
| 1083 } | |
| 1084 | |
| 1085 void LoadWithInterceptor(MacroAssembler* masm, | |
| 1086 Register receiver, | |
| 1087 Register holder, | |
| 1088 Handle<JSObject> holder_obj, | |
| 1089 Register scratch, | |
| 1090 Label* interceptor_succeeded) { | |
| 1091 { | |
| 1092 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 1093 __ Push(receiver); | |
| 1094 __ Push(holder, name_); | |
| 1095 CompileCallLoadPropertyWithInterceptor( | |
| 1096 masm, receiver, holder, name_, holder_obj, | |
| 1097 IC::kLoadPropertyWithInterceptorOnly); | |
| 1098 __ pop(name_); | |
| 1099 __ pop(holder); | |
| 1100 __ pop(receiver); | |
| 1101 } | |
| 1102 // If interceptor returns no-result sentinel, call the constant function. | |
| 1103 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex); | |
| 1104 __ cmp(r0, scratch); | |
| 1105 __ b(ne, interceptor_succeeded); | |
| 1106 } | |
| 1107 | |
| 1108 CallStubCompiler* stub_compiler_; | |
| 1109 const ParameterCount& arguments_; | |
| 1110 Register name_; | |
| 1111 }; | |
| 1112 | |
| 1113 | |
| 1114 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) { | 863 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) { |
| 1115 __ Jump(code, RelocInfo::CODE_TARGET); | 864 __ Jump(code, RelocInfo::CODE_TARGET); |
| 1116 } | 865 } |
| 1117 | 866 |
| 1118 | 867 |
| 1119 #undef __ | 868 #undef __ |
| 1120 #define __ ACCESS_MASM(masm()) | 869 #define __ ACCESS_MASM(masm()) |
| 1121 | 870 |
| 1122 | 871 |
| 1123 Register StubCompiler::CheckPrototypes(Handle<Type> type, | 872 Register StubCompiler::CheckPrototypes(Handle<HeapType> type, |
| 1124 Register object_reg, | 873 Register object_reg, |
| 1125 Handle<JSObject> holder, | 874 Handle<JSObject> holder, |
| 1126 Register holder_reg, | 875 Register holder_reg, |
| 1127 Register scratch1, | 876 Register scratch1, |
| 1128 Register scratch2, | 877 Register scratch2, |
| 1129 Handle<Name> name, | 878 Handle<Name> name, |
| 1130 int save_at_depth, | |
| 1131 Label* miss, | 879 Label* miss, |
| 1132 PrototypeCheckType check) { | 880 PrototypeCheckType check) { |
| 1133 Handle<Map> receiver_map(IC::TypeToMap(*type, isolate())); | 881 Handle<Map> receiver_map(IC::TypeToMap(*type, isolate())); |
| 1134 // Make sure that the type feedback oracle harvests the receiver map. | |
| 1135 // TODO(svenpanne) Remove this hack when all ICs are reworked. | |
| 1136 __ mov(scratch1, Operand(receiver_map)); | |
| 1137 | 882 |
| 1138 // Make sure there's no overlap between holder and object registers. | 883 // Make sure there's no overlap between holder and object registers. |
| 1139 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); | 884 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); |
| 1140 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) | 885 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) |
| 1141 && !scratch2.is(scratch1)); | 886 && !scratch2.is(scratch1)); |
| 1142 | 887 |
| 1143 // Keep track of the current object in register reg. | 888 // Keep track of the current object in register reg. |
| 1144 Register reg = object_reg; | 889 Register reg = object_reg; |
| 1145 int depth = 0; | 890 int depth = 0; |
| 1146 | 891 |
| 1147 typedef FunctionCallbackArguments FCA; | |
| 1148 if (save_at_depth == depth) { | |
| 1149 __ str(reg, MemOperand(sp, FCA::kHolderIndex * kPointerSize)); | |
| 1150 } | |
| 1151 | |
| 1152 Handle<JSObject> current = Handle<JSObject>::null(); | 892 Handle<JSObject> current = Handle<JSObject>::null(); |
| 1153 if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant()); | 893 if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant()); |
| 1154 Handle<JSObject> prototype = Handle<JSObject>::null(); | 894 Handle<JSObject> prototype = Handle<JSObject>::null(); |
| 1155 Handle<Map> current_map = receiver_map; | 895 Handle<Map> current_map = receiver_map; |
| 1156 Handle<Map> holder_map(holder->map()); | 896 Handle<Map> holder_map(holder->map()); |
| 1157 // Traverse the prototype chain and check the maps in the prototype chain for | 897 // Traverse the prototype chain and check the maps in the prototype chain for |
| 1158 // fast and global objects or do negative lookup for normal objects. | 898 // fast and global objects or do negative lookup for normal objects. |
| 1159 while (!current_map.is_identical_to(holder_map)) { | 899 while (!current_map.is_identical_to(holder_map)) { |
| 1160 ++depth; | 900 ++depth; |
| 1161 | 901 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1207 if (heap()->InNewSpace(*prototype)) { | 947 if (heap()->InNewSpace(*prototype)) { |
| 1208 // The prototype is in new space; we cannot store a reference to it | 948 // The prototype is in new space; we cannot store a reference to it |
| 1209 // in the code. Load it from the map. | 949 // in the code. Load it from the map. |
| 1210 __ ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); | 950 __ ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); |
| 1211 } else { | 951 } else { |
| 1212 // The prototype is in old space; load it directly. | 952 // The prototype is in old space; load it directly. |
| 1213 __ mov(reg, Operand(prototype)); | 953 __ mov(reg, Operand(prototype)); |
| 1214 } | 954 } |
| 1215 } | 955 } |
| 1216 | 956 |
| 1217 if (save_at_depth == depth) { | |
| 1218 __ str(reg, MemOperand(sp, FCA::kHolderIndex * kPointerSize)); | |
| 1219 } | |
| 1220 | |
| 1221 // Go to the next object in the prototype chain. | 957 // Go to the next object in the prototype chain. |
| 1222 current = prototype; | 958 current = prototype; |
| 1223 current_map = handle(current->map()); | 959 current_map = handle(current->map()); |
| 1224 } | 960 } |
| 1225 | 961 |
| 1226 // Log the check depth. | 962 // Log the check depth. |
| 1227 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); | 963 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); |
| 1228 | 964 |
| 1229 if (depth != 0 || check == CHECK_ALL_MAPS) { | 965 if (depth != 0 || check == CHECK_ALL_MAPS) { |
| 1230 // Check the holder map. | 966 // Check the holder map. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1259 Label success; | 995 Label success; |
| 1260 __ b(&success); | 996 __ b(&success); |
| 1261 GenerateRestoreName(masm(), miss, name); | 997 GenerateRestoreName(masm(), miss, name); |
| 1262 TailCallBuiltin(masm(), MissBuiltin(kind())); | 998 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| 1263 __ bind(&success); | 999 __ bind(&success); |
| 1264 } | 1000 } |
| 1265 } | 1001 } |
| 1266 | 1002 |
| 1267 | 1003 |
| 1268 Register LoadStubCompiler::CallbackHandlerFrontend( | 1004 Register LoadStubCompiler::CallbackHandlerFrontend( |
| 1269 Handle<Type> type, | 1005 Handle<HeapType> type, |
| 1270 Register object_reg, | 1006 Register object_reg, |
| 1271 Handle<JSObject> holder, | 1007 Handle<JSObject> holder, |
| 1272 Handle<Name> name, | 1008 Handle<Name> name, |
| 1273 Handle<Object> callback) { | 1009 Handle<Object> callback) { |
| 1274 Label miss; | 1010 Label miss; |
| 1275 | 1011 |
| 1276 Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss); | 1012 Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss); |
| 1277 | 1013 |
| 1278 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { | 1014 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { |
| 1279 ASSERT(!reg.is(scratch2())); | 1015 ASSERT(!reg.is(scratch2())); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1331 | 1067 |
| 1332 | 1068 |
| 1333 void LoadStubCompiler::GenerateLoadConstant(Handle<Object> value) { | 1069 void LoadStubCompiler::GenerateLoadConstant(Handle<Object> value) { |
| 1334 // Return the constant value. | 1070 // Return the constant value. |
| 1335 __ Move(r0, value); | 1071 __ Move(r0, value); |
| 1336 __ Ret(); | 1072 __ Ret(); |
| 1337 } | 1073 } |
| 1338 | 1074 |
| 1339 | 1075 |
| 1340 void LoadStubCompiler::GenerateLoadCallback( | 1076 void LoadStubCompiler::GenerateLoadCallback( |
| 1341 const CallOptimization& call_optimization) { | |
| 1342 GenerateFastApiCall( | |
| 1343 masm(), call_optimization, receiver(), scratch3(), 0, NULL); | |
| 1344 } | |
| 1345 | |
| 1346 | |
| 1347 void LoadStubCompiler::GenerateLoadCallback( | |
| 1348 Register reg, | 1077 Register reg, |
| 1349 Handle<ExecutableAccessorInfo> callback) { | 1078 Handle<ExecutableAccessorInfo> callback) { |
| 1350 // Build AccessorInfo::args_ list on the stack and push property name below | 1079 // Build AccessorInfo::args_ list on the stack and push property name below |
| 1351 // the exit frame to make GC aware of them and store pointers to them. | 1080 // the exit frame to make GC aware of them and store pointers to them. |
| 1352 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0); | 1081 STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == 0); |
| 1353 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1); | 1082 STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == 1); |
| 1354 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2); | 1083 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == 2); |
| 1355 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3); | 1084 STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == 3); |
| 1356 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4); | 1085 STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == 4); |
| 1357 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5); | 1086 STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 5); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1369 } | 1098 } |
| 1370 __ push(scratch3()); | 1099 __ push(scratch3()); |
| 1371 __ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex); | 1100 __ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex); |
| 1372 __ mov(scratch4(), scratch3()); | 1101 __ mov(scratch4(), scratch3()); |
| 1373 __ Push(scratch3(), scratch4()); | 1102 __ Push(scratch3(), scratch4()); |
| 1374 __ mov(scratch4(), | 1103 __ mov(scratch4(), |
| 1375 Operand(ExternalReference::isolate_address(isolate()))); | 1104 Operand(ExternalReference::isolate_address(isolate()))); |
| 1376 __ Push(scratch4(), reg); | 1105 __ Push(scratch4(), reg); |
| 1377 __ mov(scratch2(), sp); // scratch2 = PropertyAccessorInfo::args_ | 1106 __ mov(scratch2(), sp); // scratch2 = PropertyAccessorInfo::args_ |
| 1378 __ push(name()); | 1107 __ push(name()); |
| 1379 __ mov(r0, sp); // r0 = Handle<Name> | |
| 1380 | 1108 |
| 1381 const int kApiStackSpace = 1; | 1109 // Abi for CallApiGetter |
| 1382 FrameScope frame_scope(masm(), StackFrame::MANUAL); | 1110 Register getter_address_reg = r2; |
| 1383 __ EnterExitFrame(false, kApiStackSpace); | |
| 1384 | 1111 |
| 1385 // Create PropertyAccessorInfo instance on the stack above the exit frame with | |
| 1386 // scratch2 (internal::Object** args_) as the data. | |
| 1387 __ str(scratch2(), MemOperand(sp, 1 * kPointerSize)); | |
| 1388 __ add(r1, sp, Operand(1 * kPointerSize)); // r1 = AccessorInfo& | |
| 1389 | |
| 1390 const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1; | |
| 1391 Address getter_address = v8::ToCData<Address>(callback->getter()); | 1112 Address getter_address = v8::ToCData<Address>(callback->getter()); |
| 1392 | |
| 1393 ApiFunction fun(getter_address); | 1113 ApiFunction fun(getter_address); |
| 1394 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL; | 1114 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL; |
| 1395 ExternalReference ref = ExternalReference(&fun, type, isolate()); | 1115 ExternalReference ref = ExternalReference(&fun, type, isolate()); |
| 1116 __ mov(getter_address_reg, Operand(ref)); |
| 1396 | 1117 |
| 1397 Address thunk_address = FUNCTION_ADDR(&InvokeAccessorGetterCallback); | 1118 CallApiGetterStub stub; |
| 1398 ExternalReference::Type thunk_type = | 1119 __ TailCallStub(&stub); |
| 1399 ExternalReference::PROFILING_GETTER_CALL; | |
| 1400 ApiFunction thunk_fun(thunk_address); | |
| 1401 ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type, | |
| 1402 isolate()); | |
| 1403 __ CallApiFunctionAndReturn(ref, | |
| 1404 getter_address, | |
| 1405 thunk_ref, | |
| 1406 r2, | |
| 1407 kStackUnwindSpace, | |
| 1408 MemOperand(fp, 6 * kPointerSize), | |
| 1409 NULL); | |
| 1410 } | 1120 } |
| 1411 | 1121 |
| 1412 | 1122 |
| 1413 void LoadStubCompiler::GenerateLoadInterceptor( | 1123 void LoadStubCompiler::GenerateLoadInterceptor( |
| 1414 Register holder_reg, | 1124 Register holder_reg, |
| 1415 Handle<Object> object, | 1125 Handle<Object> object, |
| 1416 Handle<JSObject> interceptor_holder, | 1126 Handle<JSObject> interceptor_holder, |
| 1417 LookupResult* lookup, | 1127 LookupResult* lookup, |
| 1418 Handle<Name> name) { | 1128 Handle<Name> name) { |
| 1419 ASSERT(interceptor_holder->HasNamedInterceptor()); | 1129 ASSERT(interceptor_holder->HasNamedInterceptor()); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1491 this->name(), interceptor_holder); | 1201 this->name(), interceptor_holder); |
| 1492 | 1202 |
| 1493 ExternalReference ref = | 1203 ExternalReference ref = |
| 1494 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), | 1204 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), |
| 1495 isolate()); | 1205 isolate()); |
| 1496 __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1); | 1206 __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1); |
| 1497 } | 1207 } |
| 1498 } | 1208 } |
| 1499 | 1209 |
| 1500 | 1210 |
| 1501 void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) { | |
| 1502 if (kind_ == Code::KEYED_CALL_IC) { | |
| 1503 __ cmp(r2, Operand(name)); | |
| 1504 __ b(ne, miss); | |
| 1505 } | |
| 1506 } | |
| 1507 | |
| 1508 | |
| 1509 void CallStubCompiler::GenerateFunctionCheck(Register function, | |
| 1510 Register scratch, | |
| 1511 Label* miss) { | |
| 1512 __ JumpIfSmi(function, miss); | |
| 1513 __ CompareObjectType(function, scratch, scratch, JS_FUNCTION_TYPE); | |
| 1514 __ b(ne, miss); | |
| 1515 } | |
| 1516 | |
| 1517 | |
| 1518 void CallStubCompiler::GenerateLoadFunctionFromCell( | |
| 1519 Handle<Cell> cell, | |
| 1520 Handle<JSFunction> function, | |
| 1521 Label* miss) { | |
| 1522 // Get the value from the cell. | |
| 1523 __ mov(r3, Operand(cell)); | |
| 1524 __ ldr(r1, FieldMemOperand(r3, Cell::kValueOffset)); | |
| 1525 | |
| 1526 // Check that the cell contains the same function. | |
| 1527 if (heap()->InNewSpace(*function)) { | |
| 1528 // We can't embed a pointer to a function in new space so we have | |
| 1529 // to verify that the shared function info is unchanged. This has | |
| 1530 // the nice side effect that multiple closures based on the same | |
| 1531 // function can all use this call IC. Before we load through the | |
| 1532 // function, we have to verify that it still is a function. | |
| 1533 GenerateFunctionCheck(r1, r3, miss); | |
| 1534 | |
| 1535 // Check the shared function info. Make sure it hasn't changed. | |
| 1536 __ Move(r3, Handle<SharedFunctionInfo>(function->shared())); | |
| 1537 __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); | |
| 1538 __ cmp(r4, r3); | |
| 1539 } else { | |
| 1540 __ cmp(r1, Operand(function)); | |
| 1541 } | |
| 1542 __ b(ne, miss); | |
| 1543 } | |
| 1544 | |
| 1545 | |
| 1546 void CallStubCompiler::GenerateMissBranch() { | |
| 1547 Handle<Code> code = | |
| 1548 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(), | |
| 1549 kind_, | |
| 1550 extra_state()); | |
| 1551 __ Jump(code, RelocInfo::CODE_TARGET); | |
| 1552 } | |
| 1553 | |
| 1554 | |
| 1555 Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object, | |
| 1556 Handle<JSObject> holder, | |
| 1557 PropertyIndex index, | |
| 1558 Handle<Name> name) { | |
| 1559 Label miss; | |
| 1560 | |
| 1561 Register reg = HandlerFrontendHeader( | |
| 1562 object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 1563 GenerateFastPropertyLoad(masm(), r1, reg, index.is_inobject(holder), | |
| 1564 index.translate(holder), Representation::Tagged()); | |
| 1565 GenerateJumpFunction(object, r1, &miss); | |
| 1566 | |
| 1567 HandlerFrontendFooter(&miss); | |
| 1568 | |
| 1569 // Return the generated code. | |
| 1570 return GetCode(Code::FAST, name); | |
| 1571 } | |
| 1572 | |
| 1573 | |
| 1574 Handle<Code> CallStubCompiler::CompileArrayPushCall( | |
| 1575 Handle<Object> object, | |
| 1576 Handle<JSObject> holder, | |
| 1577 Handle<Cell> cell, | |
| 1578 Handle<JSFunction> function, | |
| 1579 Handle<String> name, | |
| 1580 Code::StubType type) { | |
| 1581 // If object is not an array or is observed or sealed, bail out to regular | |
| 1582 // call. | |
| 1583 if (!object->IsJSArray() || | |
| 1584 !cell.is_null() || | |
| 1585 Handle<JSArray>::cast(object)->map()->is_observed() || | |
| 1586 !Handle<JSArray>::cast(object)->map()->is_extensible()) { | |
| 1587 return Handle<Code>::null(); | |
| 1588 } | |
| 1589 | |
| 1590 Label miss; | |
| 1591 | |
| 1592 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 1593 Register receiver = r0; | |
| 1594 Register scratch = r1; | |
| 1595 | |
| 1596 const int argc = arguments().immediate(); | |
| 1597 if (argc == 0) { | |
| 1598 // Nothing to do, just return the length. | |
| 1599 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1600 __ Drop(argc + 1); | |
| 1601 __ Ret(); | |
| 1602 } else { | |
| 1603 Label call_builtin; | |
| 1604 | |
| 1605 if (argc == 1) { // Otherwise fall through to call the builtin. | |
| 1606 Label attempt_to_grow_elements, with_write_barrier, check_double; | |
| 1607 | |
| 1608 Register elements = r6; | |
| 1609 Register end_elements = r5; | |
| 1610 // Get the elements array of the object. | |
| 1611 __ ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset)); | |
| 1612 | |
| 1613 // Check that the elements are in fast mode and writable. | |
| 1614 __ CheckMap(elements, | |
| 1615 scratch, | |
| 1616 Heap::kFixedArrayMapRootIndex, | |
| 1617 &check_double, | |
| 1618 DONT_DO_SMI_CHECK); | |
| 1619 | |
| 1620 // Get the array's length into scratch and calculate new length. | |
| 1621 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1622 __ add(scratch, scratch, Operand(Smi::FromInt(argc))); | |
| 1623 | |
| 1624 // Get the elements' length. | |
| 1625 __ ldr(r4, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
| 1626 | |
| 1627 // Check if we could survive without allocation. | |
| 1628 __ cmp(scratch, r4); | |
| 1629 __ b(gt, &attempt_to_grow_elements); | |
| 1630 | |
| 1631 // Check if value is a smi. | |
| 1632 __ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize)); | |
| 1633 __ JumpIfNotSmi(r4, &with_write_barrier); | |
| 1634 | |
| 1635 // Save new length. | |
| 1636 __ str(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1637 | |
| 1638 // Store the value. | |
| 1639 // We may need a register containing the address end_elements below, | |
| 1640 // so write back the value in end_elements. | |
| 1641 __ add(end_elements, elements, Operand::PointerOffsetFromSmiKey(scratch)); | |
| 1642 const int kEndElementsOffset = | |
| 1643 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize; | |
| 1644 __ str(r4, MemOperand(end_elements, kEndElementsOffset, PreIndex)); | |
| 1645 | |
| 1646 // Check for a smi. | |
| 1647 __ Drop(argc + 1); | |
| 1648 __ mov(r0, scratch); | |
| 1649 __ Ret(); | |
| 1650 | |
| 1651 __ bind(&check_double); | |
| 1652 | |
| 1653 // Check that the elements are in fast mode and writable. | |
| 1654 __ CheckMap(elements, | |
| 1655 scratch, | |
| 1656 Heap::kFixedDoubleArrayMapRootIndex, | |
| 1657 &call_builtin, | |
| 1658 DONT_DO_SMI_CHECK); | |
| 1659 | |
| 1660 // Get the array's length into scratch and calculate new length. | |
| 1661 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1662 __ add(scratch, scratch, Operand(Smi::FromInt(argc))); | |
| 1663 | |
| 1664 // Get the elements' length. | |
| 1665 __ ldr(r4, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
| 1666 | |
| 1667 // Check if we could survive without allocation. | |
| 1668 __ cmp(scratch, r4); | |
| 1669 __ b(gt, &call_builtin); | |
| 1670 | |
| 1671 __ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize)); | |
| 1672 __ StoreNumberToDoubleElements(r4, scratch, elements, r5, d0, | |
| 1673 &call_builtin, argc * kDoubleSize); | |
| 1674 | |
| 1675 // Save new length. | |
| 1676 __ str(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1677 | |
| 1678 __ Drop(argc + 1); | |
| 1679 __ mov(r0, scratch); | |
| 1680 __ Ret(); | |
| 1681 | |
| 1682 __ bind(&with_write_barrier); | |
| 1683 | |
| 1684 __ ldr(r3, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
| 1685 | |
| 1686 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) { | |
| 1687 Label fast_object, not_fast_object; | |
| 1688 __ CheckFastObjectElements(r3, r9, ¬_fast_object); | |
| 1689 __ jmp(&fast_object); | |
| 1690 // In case of fast smi-only, convert to fast object, otherwise bail out. | |
| 1691 __ bind(¬_fast_object); | |
| 1692 __ CheckFastSmiElements(r3, r9, &call_builtin); | |
| 1693 | |
| 1694 __ ldr(r9, FieldMemOperand(r4, HeapObject::kMapOffset)); | |
| 1695 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); | |
| 1696 __ cmp(r9, ip); | |
| 1697 __ b(eq, &call_builtin); | |
| 1698 // edx: receiver | |
| 1699 // r3: map | |
| 1700 Label try_holey_map; | |
| 1701 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, | |
| 1702 FAST_ELEMENTS, | |
| 1703 r3, | |
| 1704 r9, | |
| 1705 &try_holey_map); | |
| 1706 __ mov(r2, receiver); | |
| 1707 ElementsTransitionGenerator:: | |
| 1708 GenerateMapChangeElementsTransition(masm(), | |
| 1709 DONT_TRACK_ALLOCATION_SITE, | |
| 1710 NULL); | |
| 1711 __ jmp(&fast_object); | |
| 1712 | |
| 1713 __ bind(&try_holey_map); | |
| 1714 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS, | |
| 1715 FAST_HOLEY_ELEMENTS, | |
| 1716 r3, | |
| 1717 r9, | |
| 1718 &call_builtin); | |
| 1719 __ mov(r2, receiver); | |
| 1720 ElementsTransitionGenerator:: | |
| 1721 GenerateMapChangeElementsTransition(masm(), | |
| 1722 DONT_TRACK_ALLOCATION_SITE, | |
| 1723 NULL); | |
| 1724 __ bind(&fast_object); | |
| 1725 } else { | |
| 1726 __ CheckFastObjectElements(r3, r3, &call_builtin); | |
| 1727 } | |
| 1728 | |
| 1729 // Save new length. | |
| 1730 __ str(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1731 | |
| 1732 // Store the value. | |
| 1733 // We may need a register containing the address end_elements below, | |
| 1734 // so write back the value in end_elements. | |
| 1735 __ add(end_elements, elements, Operand::PointerOffsetFromSmiKey(scratch)); | |
| 1736 __ str(r4, MemOperand(end_elements, kEndElementsOffset, PreIndex)); | |
| 1737 | |
| 1738 __ RecordWrite(elements, | |
| 1739 end_elements, | |
| 1740 r4, | |
| 1741 kLRHasNotBeenSaved, | |
| 1742 kDontSaveFPRegs, | |
| 1743 EMIT_REMEMBERED_SET, | |
| 1744 OMIT_SMI_CHECK); | |
| 1745 __ Drop(argc + 1); | |
| 1746 __ mov(r0, scratch); | |
| 1747 __ Ret(); | |
| 1748 | |
| 1749 __ bind(&attempt_to_grow_elements); | |
| 1750 // scratch: array's length + 1. | |
| 1751 | |
| 1752 if (!FLAG_inline_new) { | |
| 1753 __ b(&call_builtin); | |
| 1754 } | |
| 1755 | |
| 1756 __ ldr(r2, MemOperand(sp, (argc - 1) * kPointerSize)); | |
| 1757 // Growing elements that are SMI-only requires special handling in case | |
| 1758 // the new element is non-Smi. For now, delegate to the builtin. | |
| 1759 Label no_fast_elements_check; | |
| 1760 __ JumpIfSmi(r2, &no_fast_elements_check); | |
| 1761 __ ldr(r9, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
| 1762 __ CheckFastObjectElements(r9, r9, &call_builtin); | |
| 1763 __ bind(&no_fast_elements_check); | |
| 1764 | |
| 1765 ExternalReference new_space_allocation_top = | |
| 1766 ExternalReference::new_space_allocation_top_address(isolate()); | |
| 1767 ExternalReference new_space_allocation_limit = | |
| 1768 ExternalReference::new_space_allocation_limit_address(isolate()); | |
| 1769 | |
| 1770 const int kAllocationDelta = 4; | |
| 1771 // Load top and check if it is the end of elements. | |
| 1772 __ add(end_elements, elements, Operand::PointerOffsetFromSmiKey(scratch)); | |
| 1773 __ add(end_elements, end_elements, Operand(kEndElementsOffset)); | |
| 1774 __ mov(r4, Operand(new_space_allocation_top)); | |
| 1775 __ ldr(r3, MemOperand(r4)); | |
| 1776 __ cmp(end_elements, r3); | |
| 1777 __ b(ne, &call_builtin); | |
| 1778 | |
| 1779 __ mov(r9, Operand(new_space_allocation_limit)); | |
| 1780 __ ldr(r9, MemOperand(r9)); | |
| 1781 __ add(r3, r3, Operand(kAllocationDelta * kPointerSize)); | |
| 1782 __ cmp(r3, r9); | |
| 1783 __ b(hi, &call_builtin); | |
| 1784 | |
| 1785 // We fit and could grow elements. | |
| 1786 // Update new_space_allocation_top. | |
| 1787 __ str(r3, MemOperand(r4)); | |
| 1788 // Push the argument. | |
| 1789 __ str(r2, MemOperand(end_elements)); | |
| 1790 // Fill the rest with holes. | |
| 1791 __ LoadRoot(r3, Heap::kTheHoleValueRootIndex); | |
| 1792 for (int i = 1; i < kAllocationDelta; i++) { | |
| 1793 __ str(r3, MemOperand(end_elements, i * kPointerSize)); | |
| 1794 } | |
| 1795 | |
| 1796 // Update elements' and array's sizes. | |
| 1797 __ str(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1798 __ ldr(r4, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
| 1799 __ add(r4, r4, Operand(Smi::FromInt(kAllocationDelta))); | |
| 1800 __ str(r4, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
| 1801 | |
| 1802 // Elements are in new space, so write barrier is not required. | |
| 1803 __ Drop(argc + 1); | |
| 1804 __ mov(r0, scratch); | |
| 1805 __ Ret(); | |
| 1806 } | |
| 1807 __ bind(&call_builtin); | |
| 1808 __ TailCallExternalReference( | |
| 1809 ExternalReference(Builtins::c_ArrayPush, isolate()), argc + 1, 1); | |
| 1810 } | |
| 1811 | |
| 1812 HandlerFrontendFooter(&miss); | |
| 1813 | |
| 1814 // Return the generated code. | |
| 1815 return GetCode(type, name); | |
| 1816 } | |
| 1817 | |
| 1818 | |
| 1819 Handle<Code> CallStubCompiler::CompileArrayPopCall( | |
| 1820 Handle<Object> object, | |
| 1821 Handle<JSObject> holder, | |
| 1822 Handle<Cell> cell, | |
| 1823 Handle<JSFunction> function, | |
| 1824 Handle<String> name, | |
| 1825 Code::StubType type) { | |
| 1826 // If object is not an array or is observed or sealed, bail out to regular | |
| 1827 // call. | |
| 1828 if (!object->IsJSArray() || | |
| 1829 !cell.is_null() || | |
| 1830 Handle<JSArray>::cast(object)->map()->is_observed() || | |
| 1831 !Handle<JSArray>::cast(object)->map()->is_extensible()) { | |
| 1832 return Handle<Code>::null(); | |
| 1833 } | |
| 1834 | |
| 1835 Label miss, return_undefined, call_builtin; | |
| 1836 Register receiver = r0; | |
| 1837 Register scratch = r1; | |
| 1838 Register elements = r3; | |
| 1839 | |
| 1840 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 1841 | |
| 1842 // Get the elements array of the object. | |
| 1843 __ ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset)); | |
| 1844 | |
| 1845 // Check that the elements are in fast mode and writable. | |
| 1846 __ CheckMap(elements, | |
| 1847 scratch, | |
| 1848 Heap::kFixedArrayMapRootIndex, | |
| 1849 &call_builtin, | |
| 1850 DONT_DO_SMI_CHECK); | |
| 1851 | |
| 1852 // Get the array's length into r4 and calculate new length. | |
| 1853 __ ldr(r4, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1854 __ sub(r4, r4, Operand(Smi::FromInt(1)), SetCC); | |
| 1855 __ b(lt, &return_undefined); | |
| 1856 | |
| 1857 // Get the last element. | |
| 1858 __ LoadRoot(r6, Heap::kTheHoleValueRootIndex); | |
| 1859 // We can't address the last element in one operation. Compute the more | |
| 1860 // expensive shift first, and use an offset later on. | |
| 1861 __ add(elements, elements, Operand::PointerOffsetFromSmiKey(r4)); | |
| 1862 __ ldr(scratch, FieldMemOperand(elements, FixedArray::kHeaderSize)); | |
| 1863 __ cmp(scratch, r6); | |
| 1864 __ b(eq, &call_builtin); | |
| 1865 | |
| 1866 // Set the array's length. | |
| 1867 __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1868 | |
| 1869 // Fill with the hole. | |
| 1870 __ str(r6, FieldMemOperand(elements, FixedArray::kHeaderSize)); | |
| 1871 const int argc = arguments().immediate(); | |
| 1872 __ Drop(argc + 1); | |
| 1873 __ mov(r0, scratch); | |
| 1874 __ Ret(); | |
| 1875 | |
| 1876 __ bind(&return_undefined); | |
| 1877 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | |
| 1878 __ Drop(argc + 1); | |
| 1879 __ Ret(); | |
| 1880 | |
| 1881 __ bind(&call_builtin); | |
| 1882 __ TailCallExternalReference( | |
| 1883 ExternalReference(Builtins::c_ArrayPop, isolate()), argc + 1, 1); | |
| 1884 | |
| 1885 HandlerFrontendFooter(&miss); | |
| 1886 | |
| 1887 // Return the generated code. | |
| 1888 return GetCode(type, name); | |
| 1889 } | |
| 1890 | |
| 1891 | |
| 1892 Handle<Code> CallStubCompiler::CompileFastApiCall( | |
| 1893 const CallOptimization& optimization, | |
| 1894 Handle<Object> object, | |
| 1895 Handle<JSObject> holder, | |
| 1896 Handle<Cell> cell, | |
| 1897 Handle<JSFunction> function, | |
| 1898 Handle<String> name) { | |
| 1899 Counters* counters = isolate()->counters(); | |
| 1900 | |
| 1901 ASSERT(optimization.is_simple_api_call()); | |
| 1902 // Bail out if object is a global object as we don't want to | |
| 1903 // repatch it to global receiver. | |
| 1904 if (object->IsGlobalObject()) return Handle<Code>::null(); | |
| 1905 if (!cell.is_null()) return Handle<Code>::null(); | |
| 1906 if (!object->IsJSObject()) return Handle<Code>::null(); | |
| 1907 int depth = optimization.GetPrototypeDepthOfExpectedType( | |
| 1908 Handle<JSObject>::cast(object), holder); | |
| 1909 if (depth == kInvalidProtoDepth) return Handle<Code>::null(); | |
| 1910 | |
| 1911 Label miss, miss_before_stack_reserved; | |
| 1912 GenerateNameCheck(name, &miss_before_stack_reserved); | |
| 1913 | |
| 1914 // Get the receiver from the stack. | |
| 1915 const int argc = arguments().immediate(); | |
| 1916 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); | |
| 1917 | |
| 1918 // Check that the receiver isn't a smi. | |
| 1919 __ JumpIfSmi(r1, &miss_before_stack_reserved); | |
| 1920 | |
| 1921 __ IncrementCounter(counters->call_const(), 1, r0, r3); | |
| 1922 __ IncrementCounter(counters->call_const_fast_api(), 1, r0, r3); | |
| 1923 | |
| 1924 ReserveSpaceForFastApiCall(masm(), r0); | |
| 1925 | |
| 1926 // Check that the maps haven't changed and find a Holder as a side effect. | |
| 1927 CheckPrototypes( | |
| 1928 IC::CurrentTypeOf(object, isolate()), | |
| 1929 r1, holder, r0, r3, r4, name, depth, &miss); | |
| 1930 | |
| 1931 GenerateFastApiDirectCall(masm(), optimization, argc, false); | |
| 1932 | |
| 1933 __ bind(&miss); | |
| 1934 FreeSpaceForFastApiCall(masm()); | |
| 1935 | |
| 1936 HandlerFrontendFooter(&miss_before_stack_reserved); | |
| 1937 | |
| 1938 // Return the generated code. | |
| 1939 return GetCode(function); | |
| 1940 } | |
| 1941 | |
| 1942 | |
| 1943 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { | 1211 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { |
| 1944 Label success; | 1212 Label success; |
| 1945 // Check that the object is a boolean. | 1213 // Check that the object is a boolean. |
| 1946 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 1214 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
| 1947 __ cmp(object, ip); | 1215 __ cmp(object, ip); |
| 1948 __ b(eq, &success); | 1216 __ b(eq, &success); |
| 1949 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | 1217 __ LoadRoot(ip, Heap::kFalseValueRootIndex); |
| 1950 __ cmp(object, ip); | 1218 __ cmp(object, ip); |
| 1951 __ b(ne, miss); | 1219 __ b(ne, miss); |
| 1952 __ bind(&success); | 1220 __ bind(&success); |
| 1953 } | 1221 } |
| 1954 | 1222 |
| 1955 | 1223 |
| 1956 void CallStubCompiler::PatchImplicitReceiver(Handle<Object> object) { | |
| 1957 if (object->IsGlobalObject()) { | |
| 1958 const int argc = arguments().immediate(); | |
| 1959 const int receiver_offset = argc * kPointerSize; | |
| 1960 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); | |
| 1961 __ str(r3, MemOperand(sp, receiver_offset)); | |
| 1962 } | |
| 1963 } | |
| 1964 | |
| 1965 | |
| 1966 Register CallStubCompiler::HandlerFrontendHeader(Handle<Object> object, | |
| 1967 Handle<JSObject> holder, | |
| 1968 Handle<Name> name, | |
| 1969 CheckType check, | |
| 1970 Label* miss) { | |
| 1971 // ----------- S t a t e ------------- | |
| 1972 // -- r2 : name | |
| 1973 // -- lr : return address | |
| 1974 // ----------------------------------- | |
| 1975 GenerateNameCheck(name, miss); | |
| 1976 | |
| 1977 Register reg = r0; | |
| 1978 | |
| 1979 // Get the receiver from the stack | |
| 1980 const int argc = arguments().immediate(); | |
| 1981 const int receiver_offset = argc * kPointerSize; | |
| 1982 __ ldr(r0, MemOperand(sp, receiver_offset)); | |
| 1983 | |
| 1984 // Check that the receiver isn't a smi. | |
| 1985 if (check != NUMBER_CHECK) { | |
| 1986 __ JumpIfSmi(r0, miss); | |
| 1987 } | |
| 1988 | |
| 1989 // Make sure that it's okay not to patch the on stack receiver | |
| 1990 // unless we're doing a receiver map check. | |
| 1991 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); | |
| 1992 switch (check) { | |
| 1993 case RECEIVER_MAP_CHECK: | |
| 1994 __ IncrementCounter(isolate()->counters()->call_const(), 1, r1, r3); | |
| 1995 | |
| 1996 // Check that the maps haven't changed. | |
| 1997 reg = CheckPrototypes( | |
| 1998 IC::CurrentTypeOf(object, isolate()), | |
| 1999 reg, holder, r1, r3, r4, name, miss); | |
| 2000 break; | |
| 2001 | |
| 2002 case STRING_CHECK: { | |
| 2003 // Check that the object is a string. | |
| 2004 __ CompareObjectType(reg, r3, r3, FIRST_NONSTRING_TYPE); | |
| 2005 __ b(ge, miss); | |
| 2006 // Check that the maps starting from the prototype haven't changed. | |
| 2007 GenerateDirectLoadGlobalFunctionPrototype( | |
| 2008 masm(), Context::STRING_FUNCTION_INDEX, r1, miss); | |
| 2009 break; | |
| 2010 } | |
| 2011 case SYMBOL_CHECK: { | |
| 2012 // Check that the object is a symbol. | |
| 2013 __ CompareObjectType(reg, r3, r3, SYMBOL_TYPE); | |
| 2014 __ b(ne, miss); | |
| 2015 // Check that the maps starting from the prototype haven't changed. | |
| 2016 GenerateDirectLoadGlobalFunctionPrototype( | |
| 2017 masm(), Context::SYMBOL_FUNCTION_INDEX, r1, miss); | |
| 2018 break; | |
| 2019 } | |
| 2020 case NUMBER_CHECK: { | |
| 2021 Label fast; | |
| 2022 // Check that the object is a smi or a heap number. | |
| 2023 __ JumpIfSmi(reg, &fast); | |
| 2024 __ CompareObjectType(reg, r3, r3, HEAP_NUMBER_TYPE); | |
| 2025 __ b(ne, miss); | |
| 2026 __ bind(&fast); | |
| 2027 // Check that the maps starting from the prototype haven't changed. | |
| 2028 GenerateDirectLoadGlobalFunctionPrototype( | |
| 2029 masm(), Context::NUMBER_FUNCTION_INDEX, r1, miss); | |
| 2030 break; | |
| 2031 } | |
| 2032 case BOOLEAN_CHECK: { | |
| 2033 GenerateBooleanCheck(reg, miss); | |
| 2034 | |
| 2035 // Check that the maps starting from the prototype haven't changed. | |
| 2036 GenerateDirectLoadGlobalFunctionPrototype( | |
| 2037 masm(), Context::BOOLEAN_FUNCTION_INDEX, r1, miss); | |
| 2038 break; | |
| 2039 } | |
| 2040 } | |
| 2041 | |
| 2042 if (check != RECEIVER_MAP_CHECK) { | |
| 2043 Handle<Object> prototype(object->GetPrototype(isolate()), isolate()); | |
| 2044 reg = CheckPrototypes( | |
| 2045 IC::CurrentTypeOf(prototype, isolate()), | |
| 2046 r1, holder, r1, r3, r4, name, miss); | |
| 2047 } | |
| 2048 | |
| 2049 return reg; | |
| 2050 } | |
| 2051 | |
| 2052 | |
| 2053 void CallStubCompiler::GenerateJumpFunction(Handle<Object> object, | |
| 2054 Register function, | |
| 2055 Label* miss) { | |
| 2056 ASSERT(function.is(r1)); | |
| 2057 // Check that the function really is a function. | |
| 2058 GenerateFunctionCheck(function, r3, miss); | |
| 2059 PatchImplicitReceiver(object); | |
| 2060 | |
| 2061 // Invoke the function. | |
| 2062 __ InvokeFunction(r1, arguments(), JUMP_FUNCTION, NullCallWrapper()); | |
| 2063 } | |
| 2064 | |
| 2065 | |
| 2066 Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object, | |
| 2067 Handle<JSObject> holder, | |
| 2068 Handle<Name> name) { | |
| 2069 Label miss; | |
| 2070 GenerateNameCheck(name, &miss); | |
| 2071 | |
| 2072 // Get the number of arguments. | |
| 2073 const int argc = arguments().immediate(); | |
| 2074 LookupResult lookup(isolate()); | |
| 2075 LookupPostInterceptor(holder, name, &lookup); | |
| 2076 | |
| 2077 // Get the receiver from the stack. | |
| 2078 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); | |
| 2079 | |
| 2080 CallInterceptorCompiler compiler(this, arguments(), r2); | |
| 2081 compiler.Compile(masm(), object, holder, name, &lookup, r1, r3, r4, r0, | |
| 2082 &miss); | |
| 2083 | |
| 2084 // Move returned value, the function to call, to r1. | |
| 2085 __ mov(r1, r0); | |
| 2086 // Restore receiver. | |
| 2087 __ ldr(r0, MemOperand(sp, argc * kPointerSize)); | |
| 2088 | |
| 2089 GenerateJumpFunction(object, r1, &miss); | |
| 2090 | |
| 2091 HandlerFrontendFooter(&miss); | |
| 2092 | |
| 2093 // Return the generated code. | |
| 2094 return GetCode(Code::FAST, name); | |
| 2095 } | |
| 2096 | |
| 2097 | |
| 2098 Handle<Code> CallStubCompiler::CompileCallGlobal( | |
| 2099 Handle<JSObject> object, | |
| 2100 Handle<GlobalObject> holder, | |
| 2101 Handle<PropertyCell> cell, | |
| 2102 Handle<JSFunction> function, | |
| 2103 Handle<Name> name) { | |
| 2104 if (HasCustomCallGenerator(function)) { | |
| 2105 Handle<Code> code = CompileCustomCall( | |
| 2106 object, holder, cell, function, Handle<String>::cast(name), | |
| 2107 Code::NORMAL); | |
| 2108 // A null handle means bail out to the regular compiler code below. | |
| 2109 if (!code.is_null()) return code; | |
| 2110 } | |
| 2111 | |
| 2112 Label miss; | |
| 2113 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 2114 // Potentially loads a closure that matches the shared function info of the | |
| 2115 // function, rather than function. | |
| 2116 GenerateLoadFunctionFromCell(cell, function, &miss); | |
| 2117 | |
| 2118 Counters* counters = isolate()->counters(); | |
| 2119 __ IncrementCounter(counters->call_global_inline(), 1, r3, r4); | |
| 2120 GenerateJumpFunction(object, r1, function); | |
| 2121 HandlerFrontendFooter(&miss); | |
| 2122 | |
| 2123 // Return the generated code. | |
| 2124 return GetCode(Code::NORMAL, name); | |
| 2125 } | |
| 2126 | |
| 2127 | |
| 2128 Handle<Code> StoreStubCompiler::CompileStoreCallback( | 1224 Handle<Code> StoreStubCompiler::CompileStoreCallback( |
| 2129 Handle<JSObject> object, | 1225 Handle<JSObject> object, |
| 2130 Handle<JSObject> holder, | 1226 Handle<JSObject> holder, |
| 2131 Handle<Name> name, | 1227 Handle<Name> name, |
| 2132 Handle<ExecutableAccessorInfo> callback) { | 1228 Handle<ExecutableAccessorInfo> callback) { |
| 2133 Register holder_reg = HandlerFrontend( | 1229 Register holder_reg = HandlerFrontend( |
| 2134 IC::CurrentTypeOf(object, isolate()), receiver(), holder, name); | 1230 IC::CurrentTypeOf(object, isolate()), receiver(), holder, name); |
| 2135 | 1231 |
| 2136 // Stub never generated for non-global objects that require access checks. | 1232 // Stub never generated for non-global objects that require access checks. |
| 2137 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); | 1233 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); |
| 2138 | 1234 |
| 2139 __ push(receiver()); // receiver | 1235 __ push(receiver()); // receiver |
| 2140 __ push(holder_reg); | 1236 __ push(holder_reg); |
| 2141 __ mov(ip, Operand(callback)); // callback info | 1237 __ mov(ip, Operand(callback)); // callback info |
| 2142 __ push(ip); | 1238 __ push(ip); |
| 2143 __ mov(ip, Operand(name)); | 1239 __ mov(ip, Operand(name)); |
| 2144 __ Push(ip, value()); | 1240 __ Push(ip, value()); |
| 2145 | 1241 |
| 2146 // Do tail-call to the runtime system. | 1242 // Do tail-call to the runtime system. |
| 2147 ExternalReference store_callback_property = | 1243 ExternalReference store_callback_property = |
| 2148 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); | 1244 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); |
| 2149 __ TailCallExternalReference(store_callback_property, 5, 1); | 1245 __ TailCallExternalReference(store_callback_property, 5, 1); |
| 2150 | 1246 |
| 2151 // Return the generated code. | 1247 // Return the generated code. |
| 2152 return GetCode(kind(), Code::FAST, name); | 1248 return GetCode(kind(), Code::FAST, name); |
| 2153 } | 1249 } |
| 2154 | 1250 |
| 2155 | 1251 |
| 2156 Handle<Code> StoreStubCompiler::CompileStoreCallback( | |
| 2157 Handle<JSObject> object, | |
| 2158 Handle<JSObject> holder, | |
| 2159 Handle<Name> name, | |
| 2160 const CallOptimization& call_optimization) { | |
| 2161 HandlerFrontend(IC::CurrentTypeOf(object, isolate()), | |
| 2162 receiver(), holder, name); | |
| 2163 | |
| 2164 Register values[] = { value() }; | |
| 2165 GenerateFastApiCall( | |
| 2166 masm(), call_optimization, receiver(), scratch3(), 1, values); | |
| 2167 | |
| 2168 // Return the generated code. | |
| 2169 return GetCode(kind(), Code::FAST, name); | |
| 2170 } | |
| 2171 | |
| 2172 | |
| 2173 #undef __ | 1252 #undef __ |
| 2174 #define __ ACCESS_MASM(masm) | 1253 #define __ ACCESS_MASM(masm) |
| 2175 | 1254 |
| 2176 | 1255 |
| 2177 void StoreStubCompiler::GenerateStoreViaSetter( | 1256 void StoreStubCompiler::GenerateStoreViaSetter( |
| 2178 MacroAssembler* masm, | 1257 MacroAssembler* masm, |
| 1258 Handle<HeapType> type, |
| 2179 Handle<JSFunction> setter) { | 1259 Handle<JSFunction> setter) { |
| 2180 // ----------- S t a t e ------------- | 1260 // ----------- S t a t e ------------- |
| 2181 // -- r0 : value | 1261 // -- r0 : value |
| 2182 // -- r1 : receiver | 1262 // -- r1 : receiver |
| 2183 // -- r2 : name | 1263 // -- r2 : name |
| 2184 // -- lr : return address | 1264 // -- lr : return address |
| 2185 // ----------------------------------- | 1265 // ----------------------------------- |
| 2186 { | 1266 { |
| 2187 FrameScope scope(masm, StackFrame::INTERNAL); | 1267 FrameScope scope(masm, StackFrame::INTERNAL); |
| 1268 Register receiver = r1; |
| 1269 Register value = r0; |
| 2188 | 1270 |
| 2189 // Save value register, so we can restore it later. | 1271 // Save value register, so we can restore it later. |
| 2190 __ push(r0); | 1272 __ push(value); |
| 2191 | 1273 |
| 2192 if (!setter.is_null()) { | 1274 if (!setter.is_null()) { |
| 2193 // Call the JavaScript setter with receiver and value on the stack. | 1275 // Call the JavaScript setter with receiver and value on the stack. |
| 2194 __ Push(r1, r0); | 1276 if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { |
| 1277 // Swap in the global receiver. |
| 1278 __ ldr(receiver, |
| 1279 FieldMemOperand( |
| 1280 receiver, JSGlobalObject::kGlobalReceiverOffset)); |
| 1281 } |
| 1282 __ Push(receiver, value); |
| 2195 ParameterCount actual(1); | 1283 ParameterCount actual(1); |
| 2196 ParameterCount expected(setter); | 1284 ParameterCount expected(setter); |
| 2197 __ InvokeFunction(setter, expected, actual, | 1285 __ InvokeFunction(setter, expected, actual, |
| 2198 CALL_FUNCTION, NullCallWrapper()); | 1286 CALL_FUNCTION, NullCallWrapper()); |
| 2199 } else { | 1287 } else { |
| 2200 // If we generate a global code snippet for deoptimization only, remember | 1288 // If we generate a global code snippet for deoptimization only, remember |
| 2201 // the place to continue after deoptimization. | 1289 // the place to continue after deoptimization. |
| 2202 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); | 1290 masm->isolate()->heap()->SetSetterStubDeoptPCOffset(masm->pc_offset()); |
| 2203 } | 1291 } |
| 2204 | 1292 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2243 | 1331 |
| 2244 // Handle store cache miss. | 1332 // Handle store cache miss. |
| 2245 __ bind(&miss); | 1333 __ bind(&miss); |
| 2246 TailCallBuiltin(masm(), MissBuiltin(kind())); | 1334 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| 2247 | 1335 |
| 2248 // Return the generated code. | 1336 // Return the generated code. |
| 2249 return GetCode(kind(), Code::FAST, name); | 1337 return GetCode(kind(), Code::FAST, name); |
| 2250 } | 1338 } |
| 2251 | 1339 |
| 2252 | 1340 |
| 2253 Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<Type> type, | 1341 Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<HeapType> type, |
| 2254 Handle<JSObject> last, | 1342 Handle<JSObject> last, |
| 2255 Handle<Name> name) { | 1343 Handle<Name> name) { |
| 2256 NonexistentHandlerFrontend(type, last, name); | 1344 NonexistentHandlerFrontend(type, last, name); |
| 2257 | 1345 |
| 2258 // Return undefined if maps of the full prototype chain are still the | 1346 // Return undefined if maps of the full prototype chain are still the |
| 2259 // same and no global property with this name contains a value. | 1347 // same and no global property with this name contains a value. |
| 2260 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 1348 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
| 2261 __ Ret(); | 1349 __ Ret(); |
| 2262 | 1350 |
| 2263 // Return the generated code. | 1351 // Return the generated code. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 2291 static Register registers[] = { r2, r1, r0, r3, r4, r5 }; | 1379 static Register registers[] = { r2, r1, r0, r3, r4, r5 }; |
| 2292 return registers; | 1380 return registers; |
| 2293 } | 1381 } |
| 2294 | 1382 |
| 2295 | 1383 |
| 2296 #undef __ | 1384 #undef __ |
| 2297 #define __ ACCESS_MASM(masm) | 1385 #define __ ACCESS_MASM(masm) |
| 2298 | 1386 |
| 2299 | 1387 |
| 2300 void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm, | 1388 void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm, |
| 1389 Handle<HeapType> type, |
| 2301 Register receiver, | 1390 Register receiver, |
| 2302 Handle<JSFunction> getter) { | 1391 Handle<JSFunction> getter) { |
| 2303 // ----------- S t a t e ------------- | 1392 // ----------- S t a t e ------------- |
| 2304 // -- r0 : receiver | 1393 // -- r0 : receiver |
| 2305 // -- r2 : name | 1394 // -- r2 : name |
| 2306 // -- lr : return address | 1395 // -- lr : return address |
| 2307 // ----------------------------------- | 1396 // ----------------------------------- |
| 2308 { | 1397 { |
| 2309 FrameScope scope(masm, StackFrame::INTERNAL); | 1398 FrameScope scope(masm, StackFrame::INTERNAL); |
| 2310 | 1399 |
| 2311 if (!getter.is_null()) { | 1400 if (!getter.is_null()) { |
| 2312 // Call the JavaScript getter with the receiver on the stack. | 1401 // Call the JavaScript getter with the receiver on the stack. |
| 1402 if (IC::TypeToMap(*type, masm->isolate())->IsJSGlobalObjectMap()) { |
| 1403 // Swap in the global receiver. |
| 1404 __ ldr(receiver, |
| 1405 FieldMemOperand( |
| 1406 receiver, JSGlobalObject::kGlobalReceiverOffset)); |
| 1407 } |
| 2313 __ push(receiver); | 1408 __ push(receiver); |
| 2314 ParameterCount actual(0); | 1409 ParameterCount actual(0); |
| 2315 ParameterCount expected(getter); | 1410 ParameterCount expected(getter); |
| 2316 __ InvokeFunction(getter, expected, actual, | 1411 __ InvokeFunction(getter, expected, actual, |
| 2317 CALL_FUNCTION, NullCallWrapper()); | 1412 CALL_FUNCTION, NullCallWrapper()); |
| 2318 } else { | 1413 } else { |
| 2319 // If we generate a global code snippet for deoptimization only, remember | 1414 // If we generate a global code snippet for deoptimization only, remember |
| 2320 // the place to continue after deoptimization. | 1415 // the place to continue after deoptimization. |
| 2321 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); | 1416 masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset()); |
| 2322 } | 1417 } |
| 2323 | 1418 |
| 2324 // Restore context register. | 1419 // Restore context register. |
| 2325 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 1420 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2326 } | 1421 } |
| 2327 __ Ret(); | 1422 __ Ret(); |
| 2328 } | 1423 } |
| 2329 | 1424 |
| 2330 | 1425 |
| 2331 #undef __ | 1426 #undef __ |
| 2332 #define __ ACCESS_MASM(masm()) | 1427 #define __ ACCESS_MASM(masm()) |
| 2333 | 1428 |
| 2334 | 1429 |
| 2335 Handle<Code> LoadStubCompiler::CompileLoadGlobal( | 1430 Handle<Code> LoadStubCompiler::CompileLoadGlobal( |
| 2336 Handle<Type> type, | 1431 Handle<HeapType> type, |
| 2337 Handle<GlobalObject> global, | 1432 Handle<GlobalObject> global, |
| 2338 Handle<PropertyCell> cell, | 1433 Handle<PropertyCell> cell, |
| 2339 Handle<Name> name, | 1434 Handle<Name> name, |
| 2340 bool is_dont_delete) { | 1435 bool is_dont_delete) { |
| 2341 Label miss; | 1436 Label miss; |
| 2342 | |
| 2343 HandlerFrontendHeader(type, receiver(), global, name, &miss); | 1437 HandlerFrontendHeader(type, receiver(), global, name, &miss); |
| 2344 | 1438 |
| 2345 // Get the value from the cell. | 1439 // Get the value from the cell. |
| 2346 __ mov(r3, Operand(cell)); | 1440 __ mov(r3, Operand(cell)); |
| 2347 __ ldr(r4, FieldMemOperand(r3, Cell::kValueOffset)); | 1441 __ ldr(r4, FieldMemOperand(r3, Cell::kValueOffset)); |
| 2348 | 1442 |
| 2349 // Check for deleted property if property can actually be deleted. | 1443 // Check for deleted property if property can actually be deleted. |
| 2350 if (!is_dont_delete) { | 1444 if (!is_dont_delete) { |
| 2351 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 1445 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 2352 __ cmp(r4, ip); | 1446 __ cmp(r4, ip); |
| 2353 __ b(eq, &miss); | 1447 __ b(eq, &miss); |
| 2354 } | 1448 } |
| 2355 | 1449 |
| 2356 HandlerFrontendFooter(name, &miss); | |
| 2357 | |
| 2358 Counters* counters = isolate()->counters(); | 1450 Counters* counters = isolate()->counters(); |
| 2359 __ IncrementCounter(counters->named_load_global_stub(), 1, r1, r3); | 1451 __ IncrementCounter(counters->named_load_global_stub(), 1, r1, r3); |
| 2360 __ mov(r0, r4); | 1452 __ mov(r0, r4); |
| 2361 __ Ret(); | 1453 __ Ret(); |
| 2362 | 1454 |
| 1455 HandlerFrontendFooter(name, &miss); |
| 1456 |
| 2363 // Return the generated code. | 1457 // Return the generated code. |
| 2364 return GetCode(kind(), Code::NORMAL, name); | 1458 return GetCode(kind(), Code::NORMAL, name); |
| 2365 } | 1459 } |
| 2366 | 1460 |
| 2367 | 1461 |
| 2368 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( | 1462 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( |
| 2369 TypeHandleList* types, | 1463 TypeHandleList* types, |
| 2370 CodeHandleList* handlers, | 1464 CodeHandleList* handlers, |
| 2371 Handle<Name> name, | 1465 Handle<Name> name, |
| 2372 Code::StubType type, | 1466 Code::StubType type, |
| 2373 IcCheckType check) { | 1467 IcCheckType check) { |
| 2374 Label miss; | 1468 Label miss; |
| 2375 | 1469 |
| 2376 if (check == PROPERTY && | 1470 if (check == PROPERTY && |
| 2377 (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) { | 1471 (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) { |
| 2378 __ cmp(this->name(), Operand(name)); | 1472 __ cmp(this->name(), Operand(name)); |
| 2379 __ b(ne, &miss); | 1473 __ b(ne, &miss); |
| 2380 } | 1474 } |
| 2381 | 1475 |
| 2382 Label number_case; | 1476 Label number_case; |
| 2383 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; | 1477 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; |
| 2384 __ JumpIfSmi(receiver(), smi_target); | 1478 __ JumpIfSmi(receiver(), smi_target); |
| 2385 | 1479 |
| 2386 Register map_reg = scratch1(); | 1480 Register map_reg = scratch1(); |
| 2387 | 1481 |
| 2388 int receiver_count = types->length(); | 1482 int receiver_count = types->length(); |
| 2389 int number_of_handled_maps = 0; | 1483 int number_of_handled_maps = 0; |
| 2390 __ ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset)); | 1484 __ ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset)); |
| 2391 for (int current = 0; current < receiver_count; ++current) { | 1485 for (int current = 0; current < receiver_count; ++current) { |
| 2392 Handle<Type> type = types->at(current); | 1486 Handle<HeapType> type = types->at(current); |
| 2393 Handle<Map> map = IC::TypeToMap(*type, isolate()); | 1487 Handle<Map> map = IC::TypeToMap(*type, isolate()); |
| 2394 if (!map->is_deprecated()) { | 1488 if (!map->is_deprecated()) { |
| 2395 number_of_handled_maps++; | 1489 number_of_handled_maps++; |
| 2396 __ mov(ip, Operand(map)); | 1490 __ mov(ip, Operand(map)); |
| 2397 __ cmp(map_reg, ip); | 1491 __ cmp(map_reg, ip); |
| 2398 if (type->Is(Type::Number())) { | 1492 if (type->Is(HeapType::Number())) { |
| 2399 ASSERT(!number_case.is_unused()); | 1493 ASSERT(!number_case.is_unused()); |
| 2400 __ bind(&number_case); | 1494 __ bind(&number_case); |
| 2401 } | 1495 } |
| 2402 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET, eq); | 1496 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET, eq); |
| 2403 } | 1497 } |
| 2404 } | 1498 } |
| 2405 ASSERT(number_of_handled_maps != 0); | 1499 ASSERT(number_of_handled_maps != 0); |
| 2406 | 1500 |
| 2407 __ bind(&miss); | 1501 __ bind(&miss); |
| 2408 TailCallBuiltin(masm(), MissBuiltin(kind())); | 1502 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2489 // ----------------------------------- | 1583 // ----------------------------------- |
| 2490 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 1584 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
| 2491 } | 1585 } |
| 2492 | 1586 |
| 2493 | 1587 |
| 2494 #undef __ | 1588 #undef __ |
| 2495 | 1589 |
| 2496 } } // namespace v8::internal | 1590 } } // namespace v8::internal |
| 2497 | 1591 |
| 2498 #endif // V8_TARGET_ARCH_ARM | 1592 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |