OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "v8.h" | 5 #include "v8.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_ARM | 7 #if V8_TARGET_ARCH_ARM |
8 | 8 |
9 #include "bootstrapper.h" | 9 #include "bootstrapper.h" |
10 #include "code-stubs.h" | 10 #include "code-stubs.h" |
(...skipping 2838 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2849 | 2849 |
2850 __ Push(r4, r2, r1); | 2850 __ Push(r4, r2, r1); |
2851 __ RecordWrite(r2, r4, r1, kLRHasNotBeenSaved, kDontSaveFPRegs, | 2851 __ RecordWrite(r2, r4, r1, kLRHasNotBeenSaved, kDontSaveFPRegs, |
2852 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | 2852 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
2853 __ Pop(r4, r2, r1); | 2853 __ Pop(r4, r2, r1); |
2854 | 2854 |
2855 __ bind(&done); | 2855 __ bind(&done); |
2856 } | 2856 } |
2857 | 2857 |
2858 | 2858 |
| 2859 static void EmitContinueIfStrictOrNative(MacroAssembler* masm, Label* cont) { |
| 2860 // Do not transform the receiver for strict mode functions. |
| 2861 __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); |
| 2862 __ ldr(r4, FieldMemOperand(r3, SharedFunctionInfo::kCompilerHintsOffset)); |
| 2863 __ tst(r4, Operand(1 << (SharedFunctionInfo::kStrictModeFunction + |
| 2864 kSmiTagSize))); |
| 2865 __ b(ne, cont); |
| 2866 |
| 2867 // Do not transform the receiver for native (Compilerhints already in r3). |
| 2868 __ tst(r4, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize))); |
| 2869 __ b(ne, cont); |
| 2870 } |
| 2871 |
| 2872 |
| 2873 static void EmitSlowCase(MacroAssembler* masm, |
| 2874 int argc, |
| 2875 Label* non_function) { |
| 2876 // Check for function proxy. |
| 2877 __ cmp(r4, Operand(JS_FUNCTION_PROXY_TYPE)); |
| 2878 __ b(ne, non_function); |
| 2879 __ push(r1); // put proxy as additional argument |
| 2880 __ mov(r0, Operand(argc + 1, RelocInfo::NONE32)); |
| 2881 __ mov(r2, Operand::Zero()); |
| 2882 __ GetBuiltinFunction(r1, Builtins::CALL_FUNCTION_PROXY); |
| 2883 { |
| 2884 Handle<Code> adaptor = |
| 2885 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); |
| 2886 __ Jump(adaptor, RelocInfo::CODE_TARGET); |
| 2887 } |
| 2888 |
| 2889 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead |
| 2890 // of the original receiver from the call site). |
| 2891 __ bind(non_function); |
| 2892 __ str(r1, MemOperand(sp, argc * kPointerSize)); |
| 2893 __ mov(r0, Operand(argc)); // Set up the number of arguments. |
| 2894 __ mov(r2, Operand::Zero()); |
| 2895 __ GetBuiltinFunction(r1, Builtins::CALL_NON_FUNCTION); |
| 2896 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
| 2897 RelocInfo::CODE_TARGET); |
| 2898 } |
| 2899 |
| 2900 |
| 2901 static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) { |
| 2902 // Wrap the receiver and patch it back onto the stack. |
| 2903 { FrameAndConstantPoolScope frame_scope(masm, StackFrame::INTERNAL); |
| 2904 __ Push(r1, r3); |
| 2905 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
| 2906 __ pop(r1); |
| 2907 } |
| 2908 __ str(r0, MemOperand(sp, argc * kPointerSize)); |
| 2909 __ jmp(cont); |
| 2910 } |
| 2911 |
| 2912 |
2859 void CallFunctionStub::Generate(MacroAssembler* masm) { | 2913 void CallFunctionStub::Generate(MacroAssembler* masm) { |
2860 // r1 : the function to call | 2914 // r1 : the function to call |
2861 // r2 : feedback vector | |
2862 // r3 : (only if r2 is not the megamorphic symbol) slot in feedback | |
2863 // vector (Smi) | |
2864 Label slow, non_function, wrap, cont; | 2915 Label slow, non_function, wrap, cont; |
2865 | 2916 |
2866 if (NeedsChecks()) { | 2917 if (NeedsChecks()) { |
2867 // Check that the function is really a JavaScript function. | 2918 // Check that the function is really a JavaScript function. |
2868 // r1: pushed function (to be verified) | 2919 // r1: pushed function (to be verified) |
2869 __ JumpIfSmi(r1, &non_function); | 2920 __ JumpIfSmi(r1, &non_function); |
2870 | 2921 |
2871 // Goto slow case if we do not have a function. | 2922 // Goto slow case if we do not have a function. |
2872 __ CompareObjectType(r1, r4, r4, JS_FUNCTION_TYPE); | 2923 __ CompareObjectType(r1, r4, r4, JS_FUNCTION_TYPE); |
2873 __ b(ne, &slow); | 2924 __ b(ne, &slow); |
2874 | |
2875 if (RecordCallTarget()) { | |
2876 GenerateRecordCallTarget(masm); | |
2877 // Type information was updated. Because we may call Array, which | |
2878 // expects either undefined or an AllocationSite in ebx we need | |
2879 // to set ebx to undefined. | |
2880 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); | |
2881 } | |
2882 } | 2925 } |
2883 | 2926 |
2884 // Fast-case: Invoke the function now. | 2927 // Fast-case: Invoke the function now. |
2885 // r1: pushed function | 2928 // r1: pushed function |
2886 ParameterCount actual(argc_); | 2929 int argc = argc_; |
| 2930 ParameterCount actual(argc); |
2887 | 2931 |
2888 if (CallAsMethod()) { | 2932 if (CallAsMethod()) { |
2889 if (NeedsChecks()) { | 2933 if (NeedsChecks()) { |
2890 // Do not transform the receiver for strict mode functions. | 2934 EmitContinueIfStrictOrNative(masm, &cont); |
2891 __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); | |
2892 __ ldr(r4, FieldMemOperand(r3, SharedFunctionInfo::kCompilerHintsOffset)); | |
2893 __ tst(r4, Operand(1 << (SharedFunctionInfo::kStrictModeFunction + | |
2894 kSmiTagSize))); | |
2895 __ b(ne, &cont); | |
2896 | |
2897 // Do not transform the receiver for native (Compilerhints already in r3). | |
2898 __ tst(r4, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize))); | |
2899 __ b(ne, &cont); | |
2900 } | 2935 } |
2901 | 2936 |
2902 // Compute the receiver in sloppy mode. | 2937 // Compute the receiver in sloppy mode. |
2903 __ ldr(r3, MemOperand(sp, argc_ * kPointerSize)); | 2938 __ ldr(r3, MemOperand(sp, argc * kPointerSize)); |
2904 | 2939 |
2905 if (NeedsChecks()) { | 2940 if (NeedsChecks()) { |
2906 __ JumpIfSmi(r3, &wrap); | 2941 __ JumpIfSmi(r3, &wrap); |
2907 __ CompareObjectType(r3, r4, r4, FIRST_SPEC_OBJECT_TYPE); | 2942 __ CompareObjectType(r3, r4, r4, FIRST_SPEC_OBJECT_TYPE); |
2908 __ b(lt, &wrap); | 2943 __ b(lt, &wrap); |
2909 } else { | 2944 } else { |
2910 __ jmp(&wrap); | 2945 __ jmp(&wrap); |
2911 } | 2946 } |
2912 | 2947 |
2913 __ bind(&cont); | 2948 __ bind(&cont); |
2914 } | 2949 } |
| 2950 |
2915 __ InvokeFunction(r1, actual, JUMP_FUNCTION, NullCallWrapper()); | 2951 __ InvokeFunction(r1, actual, JUMP_FUNCTION, NullCallWrapper()); |
2916 | 2952 |
2917 if (NeedsChecks()) { | 2953 if (NeedsChecks()) { |
2918 // Slow-case: Non-function called. | 2954 // Slow-case: Non-function called. |
2919 __ bind(&slow); | 2955 __ bind(&slow); |
2920 if (RecordCallTarget()) { | 2956 EmitSlowCase(masm, argc, &non_function); |
2921 // If there is a call target cache, mark it megamorphic in the | |
2922 // non-function case. MegamorphicSentinel is an immortal immovable | |
2923 // object (megamorphic symbol) so no write barrier is needed. | |
2924 ASSERT_EQ(*TypeFeedbackInfo::MegamorphicSentinel(isolate()), | |
2925 isolate()->heap()->megamorphic_symbol()); | |
2926 __ add(r5, r2, Operand::PointerOffsetFromSmiKey(r3)); | |
2927 __ LoadRoot(ip, Heap::kMegamorphicSymbolRootIndex); | |
2928 __ str(ip, FieldMemOperand(r5, FixedArray::kHeaderSize)); | |
2929 } | |
2930 // Check for function proxy. | |
2931 __ cmp(r4, Operand(JS_FUNCTION_PROXY_TYPE)); | |
2932 __ b(ne, &non_function); | |
2933 __ push(r1); // put proxy as additional argument | |
2934 __ mov(r0, Operand(argc_ + 1, RelocInfo::NONE32)); | |
2935 __ mov(r2, Operand::Zero()); | |
2936 __ GetBuiltinFunction(r1, Builtins::CALL_FUNCTION_PROXY); | |
2937 { | |
2938 Handle<Code> adaptor = | |
2939 isolate()->builtins()->ArgumentsAdaptorTrampoline(); | |
2940 __ Jump(adaptor, RelocInfo::CODE_TARGET); | |
2941 } | |
2942 | |
2943 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead | |
2944 // of the original receiver from the call site). | |
2945 __ bind(&non_function); | |
2946 __ str(r1, MemOperand(sp, argc_ * kPointerSize)); | |
2947 __ mov(r0, Operand(argc_)); // Set up the number of arguments. | |
2948 __ mov(r2, Operand::Zero()); | |
2949 __ GetBuiltinFunction(r1, Builtins::CALL_NON_FUNCTION); | |
2950 __ Jump(isolate()->builtins()->ArgumentsAdaptorTrampoline(), | |
2951 RelocInfo::CODE_TARGET); | |
2952 } | 2957 } |
2953 | 2958 |
2954 if (CallAsMethod()) { | 2959 if (CallAsMethod()) { |
2955 __ bind(&wrap); | 2960 __ bind(&wrap); |
2956 // Wrap the receiver and patch it back onto the stack. | 2961 EmitWrapCase(masm, argc, &cont); |
2957 { FrameAndConstantPoolScope frame_scope(masm, StackFrame::INTERNAL); | |
2958 __ Push(r1, r3); | |
2959 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | |
2960 __ pop(r1); | |
2961 } | |
2962 __ str(r0, MemOperand(sp, argc_ * kPointerSize)); | |
2963 __ jmp(&cont); | |
2964 } | 2962 } |
2965 } | 2963 } |
2966 | 2964 |
2967 | 2965 |
2968 void CallConstructStub::Generate(MacroAssembler* masm) { | 2966 void CallConstructStub::Generate(MacroAssembler* masm) { |
2969 // r0 : number of arguments | 2967 // r0 : number of arguments |
2970 // r1 : the function to call | 2968 // r1 : the function to call |
2971 // r2 : feedback vector | 2969 // r2 : feedback vector |
2972 // r3 : (only if r2 is not the megamorphic symbol) slot in feedback | 2970 // r3 : (only if r2 is not the megamorphic symbol) slot in feedback |
2973 // vector (Smi) | 2971 // vector (Smi) |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3022 __ bind(&non_function_call); | 3020 __ bind(&non_function_call); |
3023 __ GetBuiltinFunction(r1, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); | 3021 __ GetBuiltinFunction(r1, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); |
3024 __ bind(&do_call); | 3022 __ bind(&do_call); |
3025 // Set expected number of arguments to zero (not changing r0). | 3023 // Set expected number of arguments to zero (not changing r0). |
3026 __ mov(r2, Operand::Zero()); | 3024 __ mov(r2, Operand::Zero()); |
3027 __ Jump(isolate()->builtins()->ArgumentsAdaptorTrampoline(), | 3025 __ Jump(isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
3028 RelocInfo::CODE_TARGET); | 3026 RelocInfo::CODE_TARGET); |
3029 } | 3027 } |
3030 | 3028 |
3031 | 3029 |
| 3030 static void EmitLoadTypeFeedbackVector(MacroAssembler* masm, Register vector) { |
| 3031 __ ldr(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
| 3032 __ ldr(vector, FieldMemOperand(vector, |
| 3033 JSFunction::kSharedFunctionInfoOffset)); |
| 3034 __ ldr(vector, FieldMemOperand(vector, |
| 3035 SharedFunctionInfo::kFeedbackVectorOffset)); |
| 3036 } |
| 3037 |
| 3038 |
| 3039 void CallICStub::Generate(MacroAssembler* masm) { |
| 3040 // r1 - function |
| 3041 // r3 - slot id (Smi) |
| 3042 Label extra_checks_or_miss, slow_start; |
| 3043 Label slow, non_function, wrap, cont; |
| 3044 Label have_js_function; |
| 3045 int argc = state_.arg_count(); |
| 3046 ParameterCount actual(argc); |
| 3047 |
| 3048 EmitLoadTypeFeedbackVector(masm, r2); |
| 3049 |
| 3050 // The checks. First, does r1 match the recorded monomorphic target? |
| 3051 __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3)); |
| 3052 __ ldr(r4, FieldMemOperand(r4, FixedArray::kHeaderSize)); |
| 3053 __ cmp(r1, r4); |
| 3054 __ b(ne, &extra_checks_or_miss); |
| 3055 |
| 3056 __ bind(&have_js_function); |
| 3057 if (state_.CallAsMethod()) { |
| 3058 EmitContinueIfStrictOrNative(masm, &cont); |
| 3059 // Compute the receiver in sloppy mode. |
| 3060 __ ldr(r3, MemOperand(sp, argc * kPointerSize)); |
| 3061 |
| 3062 __ JumpIfSmi(r3, &wrap); |
| 3063 __ CompareObjectType(r3, r4, r4, FIRST_SPEC_OBJECT_TYPE); |
| 3064 __ b(lt, &wrap); |
| 3065 |
| 3066 __ bind(&cont); |
| 3067 } |
| 3068 |
| 3069 __ InvokeFunction(r1, actual, JUMP_FUNCTION, NullCallWrapper()); |
| 3070 |
| 3071 __ bind(&slow); |
| 3072 EmitSlowCase(masm, argc, &non_function); |
| 3073 |
| 3074 if (state_.CallAsMethod()) { |
| 3075 __ bind(&wrap); |
| 3076 EmitWrapCase(masm, argc, &cont); |
| 3077 } |
| 3078 |
| 3079 __ bind(&extra_checks_or_miss); |
| 3080 Label miss; |
| 3081 |
| 3082 __ CompareRoot(r4, Heap::kMegamorphicSymbolRootIndex); |
| 3083 __ b(eq, &slow_start); |
| 3084 __ CompareRoot(r4, Heap::kUninitializedSymbolRootIndex); |
| 3085 __ b(eq, &miss); |
| 3086 |
| 3087 if (!FLAG_trace_ic) { |
| 3088 // We are going megamorphic, and we don't want to visit the runtime. |
| 3089 __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3)); |
| 3090 __ LoadRoot(ip, Heap::kMegamorphicSymbolRootIndex); |
| 3091 __ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize)); |
| 3092 __ jmp(&slow_start); |
| 3093 } |
| 3094 |
| 3095 // We are here because tracing is on or we are going monomorphic. |
| 3096 __ bind(&miss); |
| 3097 GenerateMiss(masm); |
| 3098 |
| 3099 // the slow case |
| 3100 __ bind(&slow_start); |
| 3101 // Check that the function is really a JavaScript function. |
| 3102 // r1: pushed function (to be verified) |
| 3103 __ JumpIfSmi(r1, &non_function); |
| 3104 |
| 3105 // Goto slow case if we do not have a function. |
| 3106 __ CompareObjectType(r1, r4, r4, JS_FUNCTION_TYPE); |
| 3107 __ b(ne, &slow); |
| 3108 __ jmp(&have_js_function); |
| 3109 } |
| 3110 |
| 3111 |
| 3112 void CallICStub::GenerateMiss(MacroAssembler* masm) { |
| 3113 // Get the receiver of the function from the stack; 1 ~ return address. |
| 3114 __ ldr(r4, MemOperand(sp, (state_.arg_count() + 1) * kPointerSize)); |
| 3115 |
| 3116 { |
| 3117 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); |
| 3118 |
| 3119 // Push the receiver and the function and feedback info. |
| 3120 __ Push(r4, r1, r2, r3); |
| 3121 |
| 3122 // Call the entry. |
| 3123 ExternalReference miss = ExternalReference(IC_Utility(IC::kCallIC_Miss), |
| 3124 masm->isolate()); |
| 3125 __ CallExternalReference(miss, 4); |
| 3126 |
| 3127 // Move result to edi and exit the internal frame. |
| 3128 __ mov(r1, r0); |
| 3129 } |
| 3130 } |
| 3131 |
| 3132 |
3032 // StringCharCodeAtGenerator | 3133 // StringCharCodeAtGenerator |
3033 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { | 3134 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
3034 Label flat_string; | 3135 Label flat_string; |
3035 Label ascii_string; | 3136 Label ascii_string; |
3036 Label got_char_code; | 3137 Label got_char_code; |
3037 Label sliced_string; | 3138 Label sliced_string; |
3038 | 3139 |
3039 // If the receiver is a smi trigger the non-string case. | 3140 // If the receiver is a smi trigger the non-string case. |
3040 __ JumpIfSmi(object_, receiver_not_string_); | 3141 __ JumpIfSmi(object_, receiver_not_string_); |
3041 | 3142 |
(...skipping 2081 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5123 MemOperand(fp, 6 * kPointerSize), | 5224 MemOperand(fp, 6 * kPointerSize), |
5124 NULL); | 5225 NULL); |
5125 } | 5226 } |
5126 | 5227 |
5127 | 5228 |
5128 #undef __ | 5229 #undef __ |
5129 | 5230 |
5130 } } // namespace v8::internal | 5231 } } // namespace v8::internal |
5131 | 5232 |
5132 #endif // V8_TARGET_ARCH_ARM | 5233 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |