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 2894 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2905 | 2905 |
2906 __ Push(r4, r2, r1); | 2906 __ Push(r4, r2, r1); |
2907 __ RecordWrite(r2, r4, r1, kLRHasNotBeenSaved, kDontSaveFPRegs, | 2907 __ RecordWrite(r2, r4, r1, kLRHasNotBeenSaved, kDontSaveFPRegs, |
2908 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | 2908 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
2909 __ Pop(r4, r2, r1); | 2909 __ Pop(r4, r2, r1); |
2910 | 2910 |
2911 __ bind(&done); | 2911 __ bind(&done); |
2912 } | 2912 } |
2913 | 2913 |
2914 | 2914 |
| 2915 static void EmitContinueIfStrictOrNative(MacroAssembler* masm, Label* cont) { |
| 2916 // Do not transform the receiver for strict mode functions. |
| 2917 __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); |
| 2918 __ ldr(r4, FieldMemOperand(r3, SharedFunctionInfo::kCompilerHintsOffset)); |
| 2919 __ tst(r4, Operand(1 << (SharedFunctionInfo::kStrictModeFunction + |
| 2920 kSmiTagSize))); |
| 2921 __ b(ne, cont); |
| 2922 |
| 2923 // Do not transform the receiver for native (Compilerhints already in r3). |
| 2924 __ tst(r4, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize))); |
| 2925 __ b(ne, cont); |
| 2926 } |
| 2927 |
| 2928 |
| 2929 static void EmitSlowCase(MacroAssembler* masm, |
| 2930 int argc, |
| 2931 Label* non_function) { |
| 2932 // Check for function proxy. |
| 2933 __ cmp(r4, Operand(JS_FUNCTION_PROXY_TYPE)); |
| 2934 __ b(ne, non_function); |
| 2935 __ push(r1); // put proxy as additional argument |
| 2936 __ mov(r0, Operand(argc + 1, RelocInfo::NONE32)); |
| 2937 __ mov(r2, Operand::Zero()); |
| 2938 __ GetBuiltinFunction(r1, Builtins::CALL_FUNCTION_PROXY); |
| 2939 { |
| 2940 Handle<Code> adaptor = |
| 2941 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); |
| 2942 __ Jump(adaptor, RelocInfo::CODE_TARGET); |
| 2943 } |
| 2944 |
| 2945 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead |
| 2946 // of the original receiver from the call site). |
| 2947 __ bind(non_function); |
| 2948 __ str(r1, MemOperand(sp, argc * kPointerSize)); |
| 2949 __ mov(r0, Operand(argc)); // Set up the number of arguments. |
| 2950 __ mov(r2, Operand::Zero()); |
| 2951 __ GetBuiltinFunction(r1, Builtins::CALL_NON_FUNCTION); |
| 2952 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
| 2953 RelocInfo::CODE_TARGET); |
| 2954 } |
| 2955 |
| 2956 |
| 2957 static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) { |
| 2958 // Wrap the receiver and patch it back onto the stack. |
| 2959 { FrameAndConstantPoolScope frame_scope(masm, StackFrame::INTERNAL); |
| 2960 __ Push(r1, r3); |
| 2961 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
| 2962 __ pop(r1); |
| 2963 } |
| 2964 __ str(r0, MemOperand(sp, argc * kPointerSize)); |
| 2965 __ jmp(cont); |
| 2966 } |
| 2967 |
| 2968 |
2915 void CallFunctionStub::Generate(MacroAssembler* masm) { | 2969 void CallFunctionStub::Generate(MacroAssembler* masm) { |
2916 // r1 : the function to call | 2970 // r1 : the function to call |
2917 // r2 : feedback vector | |
2918 // r3 : (only if r2 is not the megamorphic symbol) slot in feedback | |
2919 // vector (Smi) | |
2920 Label slow, non_function, wrap, cont; | 2971 Label slow, non_function, wrap, cont; |
2921 | 2972 |
2922 if (NeedsChecks()) { | 2973 if (NeedsChecks()) { |
2923 // Check that the function is really a JavaScript function. | 2974 // Check that the function is really a JavaScript function. |
2924 // r1: pushed function (to be verified) | 2975 // r1: pushed function (to be verified) |
2925 __ JumpIfSmi(r1, &non_function); | 2976 __ JumpIfSmi(r1, &non_function); |
2926 | 2977 |
2927 // Goto slow case if we do not have a function. | 2978 // Goto slow case if we do not have a function. |
2928 __ CompareObjectType(r1, r4, r4, JS_FUNCTION_TYPE); | 2979 __ CompareObjectType(r1, r4, r4, JS_FUNCTION_TYPE); |
2929 __ b(ne, &slow); | 2980 __ b(ne, &slow); |
2930 | |
2931 if (RecordCallTarget()) { | |
2932 GenerateRecordCallTarget(masm); | |
2933 // Type information was updated. Because we may call Array, which | |
2934 // expects either undefined or an AllocationSite in ebx we need | |
2935 // to set ebx to undefined. | |
2936 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); | |
2937 } | |
2938 } | 2981 } |
2939 | 2982 |
2940 // Fast-case: Invoke the function now. | 2983 // Fast-case: Invoke the function now. |
2941 // r1: pushed function | 2984 // r1: pushed function |
2942 ParameterCount actual(argc_); | 2985 int argc = argc_; |
| 2986 ParameterCount actual(argc); |
2943 | 2987 |
2944 if (CallAsMethod()) { | 2988 if (CallAsMethod()) { |
2945 if (NeedsChecks()) { | 2989 if (NeedsChecks()) { |
2946 // Do not transform the receiver for strict mode functions. | 2990 EmitContinueIfStrictOrNative(masm, &cont); |
2947 __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); | |
2948 __ ldr(r4, FieldMemOperand(r3, SharedFunctionInfo::kCompilerHintsOffset)); | |
2949 __ tst(r4, Operand(1 << (SharedFunctionInfo::kStrictModeFunction + | |
2950 kSmiTagSize))); | |
2951 __ b(ne, &cont); | |
2952 | |
2953 // Do not transform the receiver for native (Compilerhints already in r3). | |
2954 __ tst(r4, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize))); | |
2955 __ b(ne, &cont); | |
2956 } | 2991 } |
2957 | 2992 |
2958 // Compute the receiver in sloppy mode. | 2993 // Compute the receiver in sloppy mode. |
2959 __ ldr(r3, MemOperand(sp, argc_ * kPointerSize)); | 2994 __ ldr(r3, MemOperand(sp, argc * kPointerSize)); |
2960 | 2995 |
2961 if (NeedsChecks()) { | 2996 if (NeedsChecks()) { |
2962 __ JumpIfSmi(r3, &wrap); | 2997 __ JumpIfSmi(r3, &wrap); |
2963 __ CompareObjectType(r3, r4, r4, FIRST_SPEC_OBJECT_TYPE); | 2998 __ CompareObjectType(r3, r4, r4, FIRST_SPEC_OBJECT_TYPE); |
2964 __ b(lt, &wrap); | 2999 __ b(lt, &wrap); |
2965 } else { | 3000 } else { |
2966 __ jmp(&wrap); | 3001 __ jmp(&wrap); |
2967 } | 3002 } |
2968 | 3003 |
2969 __ bind(&cont); | 3004 __ bind(&cont); |
2970 } | 3005 } |
| 3006 |
2971 __ InvokeFunction(r1, actual, JUMP_FUNCTION, NullCallWrapper()); | 3007 __ InvokeFunction(r1, actual, JUMP_FUNCTION, NullCallWrapper()); |
2972 | 3008 |
2973 if (NeedsChecks()) { | 3009 if (NeedsChecks()) { |
2974 // Slow-case: Non-function called. | 3010 // Slow-case: Non-function called. |
2975 __ bind(&slow); | 3011 __ bind(&slow); |
2976 if (RecordCallTarget()) { | 3012 EmitSlowCase(masm, argc, &non_function); |
2977 // If there is a call target cache, mark it megamorphic in the | |
2978 // non-function case. MegamorphicSentinel is an immortal immovable | |
2979 // object (megamorphic symbol) so no write barrier is needed. | |
2980 ASSERT_EQ(*TypeFeedbackInfo::MegamorphicSentinel(masm->isolate()), | |
2981 masm->isolate()->heap()->megamorphic_symbol()); | |
2982 __ add(r5, r2, Operand::PointerOffsetFromSmiKey(r3)); | |
2983 __ LoadRoot(ip, Heap::kMegamorphicSymbolRootIndex); | |
2984 __ str(ip, FieldMemOperand(r5, FixedArray::kHeaderSize)); | |
2985 } | |
2986 // Check for function proxy. | |
2987 __ cmp(r4, Operand(JS_FUNCTION_PROXY_TYPE)); | |
2988 __ b(ne, &non_function); | |
2989 __ push(r1); // put proxy as additional argument | |
2990 __ mov(r0, Operand(argc_ + 1, RelocInfo::NONE32)); | |
2991 __ mov(r2, Operand::Zero()); | |
2992 __ GetBuiltinFunction(r1, Builtins::CALL_FUNCTION_PROXY); | |
2993 { | |
2994 Handle<Code> adaptor = | |
2995 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); | |
2996 __ Jump(adaptor, RelocInfo::CODE_TARGET); | |
2997 } | |
2998 | |
2999 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead | |
3000 // of the original receiver from the call site). | |
3001 __ bind(&non_function); | |
3002 __ str(r1, MemOperand(sp, argc_ * kPointerSize)); | |
3003 __ mov(r0, Operand(argc_)); // Set up the number of arguments. | |
3004 __ mov(r2, Operand::Zero()); | |
3005 __ GetBuiltinFunction(r1, Builtins::CALL_NON_FUNCTION); | |
3006 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | |
3007 RelocInfo::CODE_TARGET); | |
3008 } | 3013 } |
3009 | 3014 |
3010 if (CallAsMethod()) { | 3015 if (CallAsMethod()) { |
3011 __ bind(&wrap); | 3016 __ bind(&wrap); |
3012 // Wrap the receiver and patch it back onto the stack. | 3017 EmitWrapCase(masm, argc, &cont); |
3013 { FrameAndConstantPoolScope frame_scope(masm, StackFrame::INTERNAL); | |
3014 __ Push(r1, r3); | |
3015 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | |
3016 __ pop(r1); | |
3017 } | |
3018 __ str(r0, MemOperand(sp, argc_ * kPointerSize)); | |
3019 __ jmp(&cont); | |
3020 } | 3018 } |
3021 } | 3019 } |
3022 | 3020 |
3023 | 3021 |
3024 void CallConstructStub::Generate(MacroAssembler* masm) { | 3022 void CallConstructStub::Generate(MacroAssembler* masm) { |
3025 // r0 : number of arguments | 3023 // r0 : number of arguments |
3026 // r1 : the function to call | 3024 // r1 : the function to call |
3027 // r2 : feedback vector | 3025 // r2 : feedback vector |
3028 // r3 : (only if r2 is not the megamorphic symbol) slot in feedback | 3026 // r3 : (only if r2 is not the megamorphic symbol) slot in feedback |
3029 // vector (Smi) | 3027 // vector (Smi) |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3078 __ bind(&non_function_call); | 3076 __ bind(&non_function_call); |
3079 __ GetBuiltinFunction(r1, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); | 3077 __ GetBuiltinFunction(r1, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); |
3080 __ bind(&do_call); | 3078 __ bind(&do_call); |
3081 // Set expected number of arguments to zero (not changing r0). | 3079 // Set expected number of arguments to zero (not changing r0). |
3082 __ mov(r2, Operand::Zero()); | 3080 __ mov(r2, Operand::Zero()); |
3083 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | 3081 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
3084 RelocInfo::CODE_TARGET); | 3082 RelocInfo::CODE_TARGET); |
3085 } | 3083 } |
3086 | 3084 |
3087 | 3085 |
| 3086 static void EmitLoadTypeFeedbackVector(MacroAssembler* masm, Register vector) { |
| 3087 __ ldr(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
| 3088 __ ldr(vector, FieldMemOperand(vector, |
| 3089 JSFunction::kSharedFunctionInfoOffset)); |
| 3090 __ ldr(vector, FieldMemOperand(vector, |
| 3091 SharedFunctionInfo::kFeedbackVectorOffset)); |
| 3092 } |
| 3093 |
| 3094 |
| 3095 void CallICStub::Generate(MacroAssembler* masm) { |
| 3096 // r1 - function |
| 3097 // r3 - slot id (Smi) |
| 3098 Label extra_checks_or_miss, slow_start; |
| 3099 Label slow, non_function, wrap, cont; |
| 3100 Label have_js_function; |
| 3101 int argc = state_.arg_count(); |
| 3102 ParameterCount actual(argc); |
| 3103 |
| 3104 EmitLoadTypeFeedbackVector(masm, r2); |
| 3105 |
| 3106 // The checks. First, does r1 match the recorded monomorphic target? |
| 3107 __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3)); |
| 3108 __ ldr(r4, FieldMemOperand(r4, FixedArray::kHeaderSize)); |
| 3109 __ cmp(r1, r4); |
| 3110 __ b(ne, &extra_checks_or_miss); |
| 3111 |
| 3112 __ bind(&have_js_function); |
| 3113 if (state_.CallAsMethod()) { |
| 3114 EmitContinueIfStrictOrNative(masm, &cont); |
| 3115 // Compute the receiver in sloppy mode. |
| 3116 __ ldr(r3, MemOperand(sp, argc * kPointerSize)); |
| 3117 |
| 3118 __ JumpIfSmi(r3, &wrap); |
| 3119 __ CompareObjectType(r3, r4, r4, FIRST_SPEC_OBJECT_TYPE); |
| 3120 __ b(lt, &wrap); |
| 3121 |
| 3122 __ bind(&cont); |
| 3123 } |
| 3124 |
| 3125 __ InvokeFunction(r1, actual, JUMP_FUNCTION, NullCallWrapper()); |
| 3126 |
| 3127 __ bind(&slow); |
| 3128 EmitSlowCase(masm, argc, &non_function); |
| 3129 |
| 3130 if (state_.CallAsMethod()) { |
| 3131 __ bind(&wrap); |
| 3132 EmitWrapCase(masm, argc, &cont); |
| 3133 } |
| 3134 |
| 3135 __ bind(&extra_checks_or_miss); |
| 3136 Label miss; |
| 3137 |
| 3138 __ CompareRoot(r4, Heap::kMegamorphicSymbolRootIndex); |
| 3139 __ b(eq, &slow_start); |
| 3140 __ CompareRoot(r4, Heap::kUninitializedSymbolRootIndex); |
| 3141 __ b(eq, &miss); |
| 3142 |
| 3143 if (!FLAG_trace_ic) { |
| 3144 // We are going megamorphic, and we don't want to visit the runtime. |
| 3145 __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3)); |
| 3146 __ LoadRoot(ip, Heap::kMegamorphicSymbolRootIndex); |
| 3147 __ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize)); |
| 3148 __ jmp(&slow_start); |
| 3149 } |
| 3150 |
| 3151 // We are here because tracing is on or we are going monomorphic. |
| 3152 __ bind(&miss); |
| 3153 GenerateMiss(masm); |
| 3154 |
| 3155 // the slow case |
| 3156 __ bind(&slow_start); |
| 3157 // Check that the function is really a JavaScript function. |
| 3158 // r1: pushed function (to be verified) |
| 3159 __ JumpIfSmi(r1, &non_function); |
| 3160 |
| 3161 // Goto slow case if we do not have a function. |
| 3162 __ CompareObjectType(r1, r4, r4, JS_FUNCTION_TYPE); |
| 3163 __ b(ne, &slow); |
| 3164 __ jmp(&have_js_function); |
| 3165 } |
| 3166 |
| 3167 |
| 3168 void CallICStub::GenerateMiss(MacroAssembler* masm) { |
| 3169 // Get the receiver of the function from the stack; 1 ~ return address. |
| 3170 __ ldr(r4, MemOperand(sp, (state_.arg_count() + 1) * kPointerSize)); |
| 3171 |
| 3172 { |
| 3173 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); |
| 3174 |
| 3175 // Push the receiver and the function and feedback info. |
| 3176 __ Push(r4, r1, r2, r3); |
| 3177 |
| 3178 // Call the entry. |
| 3179 ExternalReference miss = ExternalReference(IC_Utility(IC::kCallIC_Miss), |
| 3180 masm->isolate()); |
| 3181 __ CallExternalReference(miss, 4); |
| 3182 |
| 3183 // Move result to edi and exit the internal frame. |
| 3184 __ mov(r1, r0); |
| 3185 } |
| 3186 } |
| 3187 |
| 3188 |
3088 // StringCharCodeAtGenerator | 3189 // StringCharCodeAtGenerator |
3089 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { | 3190 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
3090 Label flat_string; | 3191 Label flat_string; |
3091 Label ascii_string; | 3192 Label ascii_string; |
3092 Label got_char_code; | 3193 Label got_char_code; |
3093 Label sliced_string; | 3194 Label sliced_string; |
3094 | 3195 |
3095 // If the receiver is a smi trigger the non-string case. | 3196 // If the receiver is a smi trigger the non-string case. |
3096 __ JumpIfSmi(object_, receiver_not_string_); | 3197 __ JumpIfSmi(object_, receiver_not_string_); |
3097 | 3198 |
(...skipping 2092 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5190 MemOperand(fp, 6 * kPointerSize), | 5291 MemOperand(fp, 6 * kPointerSize), |
5191 NULL); | 5292 NULL); |
5192 } | 5293 } |
5193 | 5294 |
5194 | 5295 |
5195 #undef __ | 5296 #undef __ |
5196 | 5297 |
5197 } } // namespace v8::internal | 5298 } } // namespace v8::internal |
5198 | 5299 |
5199 #endif // V8_TARGET_ARCH_ARM | 5300 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |