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 #if V8_TARGET_ARCH_ARM | 5 #if V8_TARGET_ARCH_ARM |
6 | 6 |
7 #include "src/codegen.h" | 7 #include "src/codegen.h" |
8 #include "src/debug/debug.h" | 8 #include "src/debug/debug.h" |
9 #include "src/deoptimizer.h" | 9 #include "src/deoptimizer.h" |
10 #include "src/full-codegen/full-codegen.h" | 10 #include "src/full-codegen/full-codegen.h" |
(...skipping 1923 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1934 } | 1934 } |
1935 | 1935 |
1936 // Dispatch to Call or Construct depending on whether new.target is undefined. | 1936 // Dispatch to Call or Construct depending on whether new.target is undefined. |
1937 { | 1937 { |
1938 __ CompareRoot(r3, Heap::kUndefinedValueRootIndex); | 1938 __ CompareRoot(r3, Heap::kUndefinedValueRootIndex); |
1939 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET, eq); | 1939 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET, eq); |
1940 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); | 1940 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); |
1941 } | 1941 } |
1942 } | 1942 } |
1943 | 1943 |
| 1944 namespace { |
| 1945 |
| 1946 // Drops top JavaScript frame and an arguments adaptor frame below it (if |
| 1947 // present) preserving all the arguments prepared for current call. |
| 1948 // Does nothing if debugger is currently active. |
| 1949 // ES6 14.6.3. PrepareForTailCall |
| 1950 // |
| 1951 // Stack structure for the function g() tail calling f(): |
| 1952 // |
| 1953 // ------- Caller frame: ------- |
| 1954 // | ... |
| 1955 // | g()'s arg M |
| 1956 // | ... |
| 1957 // | g()'s arg 1 |
| 1958 // | g()'s receiver arg |
| 1959 // | g()'s caller pc |
| 1960 // ------- g()'s frame: ------- |
| 1961 // | g()'s caller fp <- fp |
| 1962 // | g()'s context |
| 1963 // | function pointer: g |
| 1964 // | ------------------------- |
| 1965 // | ... |
| 1966 // | ... |
| 1967 // | f()'s arg N |
| 1968 // | ... |
| 1969 // | f()'s arg 1 |
| 1970 // | f()'s receiver arg <- sp (f()'s caller pc is not on the stack yet!) |
| 1971 // ---------------------- |
| 1972 // |
| 1973 void PrepareForTailCall(MacroAssembler* masm, Register args_reg, |
| 1974 Register scratch1, Register scratch2, |
| 1975 Register scratch3) { |
| 1976 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3)); |
| 1977 Comment cmnt(masm, "[ PrepareForTailCall"); |
| 1978 |
| 1979 // Prepare for tail call only if the debugger is not active. |
| 1980 Label done; |
| 1981 ExternalReference debug_is_active = |
| 1982 ExternalReference::debug_is_active_address(masm->isolate()); |
| 1983 __ mov(scratch1, Operand(debug_is_active)); |
| 1984 __ ldrb(scratch1, MemOperand(scratch1)); |
| 1985 __ cmp(scratch1, Operand(0)); |
| 1986 __ b(ne, &done); |
| 1987 |
| 1988 // Check if next frame is an arguments adaptor frame. |
| 1989 Label no_arguments_adaptor, formal_parameter_count_loaded; |
| 1990 __ ldr(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
| 1991 __ ldr(scratch3, |
| 1992 MemOperand(scratch2, StandardFrameConstants::kContextOffset)); |
| 1993 __ cmp(scratch3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 1994 __ b(ne, &no_arguments_adaptor); |
| 1995 |
| 1996 // Drop arguments adaptor frame and load arguments count. |
| 1997 __ mov(fp, scratch2); |
| 1998 __ ldr(scratch1, |
| 1999 MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 2000 __ SmiUntag(scratch1); |
| 2001 __ b(&formal_parameter_count_loaded); |
| 2002 |
| 2003 __ bind(&no_arguments_adaptor); |
| 2004 // Load caller's formal parameter count |
| 2005 __ ldr(scratch1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
| 2006 __ ldr(scratch1, |
| 2007 FieldMemOperand(scratch1, JSFunction::kSharedFunctionInfoOffset)); |
| 2008 __ ldr(scratch1, |
| 2009 FieldMemOperand(scratch1, |
| 2010 SharedFunctionInfo::kFormalParameterCountOffset)); |
| 2011 __ SmiUntag(scratch1); |
| 2012 |
| 2013 __ bind(&formal_parameter_count_loaded); |
| 2014 |
| 2015 // Calculate the end of destination area where we will put the arguments |
| 2016 // after we drop current frame. We add kPointerSize to count the receiver |
| 2017 // argument which is not included into formal parameters count. |
| 2018 Register dst_reg = scratch2; |
| 2019 __ add(dst_reg, fp, Operand(scratch1, LSL, kPointerSizeLog2)); |
| 2020 __ add(dst_reg, dst_reg, |
| 2021 Operand(StandardFrameConstants::kCallerSPOffset + kPointerSize)); |
| 2022 |
| 2023 Register src_reg = scratch1; |
| 2024 __ add(src_reg, sp, Operand(args_reg, LSL, kPointerSizeLog2)); |
| 2025 // Count receiver argument as well (not included in args_reg). |
| 2026 __ add(src_reg, src_reg, Operand(kPointerSize)); |
| 2027 |
| 2028 if (FLAG_debug_code) { |
| 2029 __ cmp(src_reg, dst_reg); |
| 2030 __ Check(lo, kStackAccessBelowStackPointer); |
| 2031 } |
| 2032 |
| 2033 // Restore caller's frame pointer and return address now as they will be |
| 2034 // overwritten by the copying loop. |
| 2035 __ ldr(lr, MemOperand(fp, StandardFrameConstants::kCallerPCOffset)); |
| 2036 __ ldr(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
| 2037 |
| 2038 // Now copy callee arguments to the caller frame going backwards to avoid |
| 2039 // callee arguments corruption (source and destination areas could overlap). |
| 2040 |
| 2041 // Both src_reg and dst_reg are pointing to the word after the one to copy, |
| 2042 // so they must be pre-decremented in the loop. |
| 2043 Register tmp_reg = scratch3; |
| 2044 Label loop, entry; |
| 2045 __ b(&entry); |
| 2046 __ bind(&loop); |
| 2047 __ ldr(tmp_reg, MemOperand(src_reg, -kPointerSize, PreIndex)); |
| 2048 __ str(tmp_reg, MemOperand(dst_reg, -kPointerSize, PreIndex)); |
| 2049 __ bind(&entry); |
| 2050 __ cmp(sp, src_reg); |
| 2051 __ b(ne, &loop); |
| 2052 |
| 2053 // Leave current frame. |
| 2054 __ mov(sp, dst_reg); |
| 2055 |
| 2056 __ bind(&done); |
| 2057 } |
| 2058 } // namespace |
1944 | 2059 |
1945 // static | 2060 // static |
1946 void Builtins::Generate_CallFunction(MacroAssembler* masm, | 2061 void Builtins::Generate_CallFunction(MacroAssembler* masm, |
1947 ConvertReceiverMode mode) { | 2062 ConvertReceiverMode mode, |
| 2063 TailCallMode tail_call_mode) { |
1948 // ----------- S t a t e ------------- | 2064 // ----------- S t a t e ------------- |
1949 // -- r0 : the number of arguments (not including the receiver) | 2065 // -- r0 : the number of arguments (not including the receiver) |
1950 // -- r1 : the function to call (checked to be a JSFunction) | 2066 // -- r1 : the function to call (checked to be a JSFunction) |
1951 // ----------------------------------- | 2067 // ----------------------------------- |
1952 __ AssertFunction(r1); | 2068 __ AssertFunction(r1); |
1953 | 2069 |
1954 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList) | 2070 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList) |
1955 // Check that the function is not a "classConstructor". | 2071 // Check that the function is not a "classConstructor". |
1956 Label class_constructor; | 2072 Label class_constructor; |
1957 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); | 2073 __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2023 } | 2139 } |
2024 __ bind(&done_convert); | 2140 __ bind(&done_convert); |
2025 | 2141 |
2026 // ----------- S t a t e ------------- | 2142 // ----------- S t a t e ------------- |
2027 // -- r0 : the number of arguments (not including the receiver) | 2143 // -- r0 : the number of arguments (not including the receiver) |
2028 // -- r1 : the function to call (checked to be a JSFunction) | 2144 // -- r1 : the function to call (checked to be a JSFunction) |
2029 // -- r2 : the shared function info. | 2145 // -- r2 : the shared function info. |
2030 // -- cp : the function context. | 2146 // -- cp : the function context. |
2031 // ----------------------------------- | 2147 // ----------------------------------- |
2032 | 2148 |
| 2149 if (tail_call_mode == TailCallMode::kAllow) { |
| 2150 PrepareForTailCall(masm, r0, r3, r4, r5); |
| 2151 } |
| 2152 |
2033 __ ldr(r2, | 2153 __ ldr(r2, |
2034 FieldMemOperand(r2, SharedFunctionInfo::kFormalParameterCountOffset)); | 2154 FieldMemOperand(r2, SharedFunctionInfo::kFormalParameterCountOffset)); |
2035 __ SmiUntag(r2); | 2155 __ SmiUntag(r2); |
2036 ParameterCount actual(r0); | 2156 ParameterCount actual(r0); |
2037 ParameterCount expected(r2); | 2157 ParameterCount expected(r2); |
2038 __ InvokeFunctionCode(r1, no_reg, expected, actual, JUMP_FUNCTION, | 2158 __ InvokeFunctionCode(r1, no_reg, expected, actual, JUMP_FUNCTION, |
2039 CheckDebugStepCallWrapper()); | 2159 CheckDebugStepCallWrapper()); |
2040 | 2160 |
2041 // The function is a "classConstructor", need to raise an exception. | 2161 // The function is a "classConstructor", need to raise an exception. |
2042 __ bind(&class_constructor); | 2162 __ bind(&class_constructor); |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2121 __ b(gt, &loop); | 2241 __ b(gt, &loop); |
2122 } | 2242 } |
2123 } | 2243 } |
2124 __ bind(&no_bound_arguments); | 2244 __ bind(&no_bound_arguments); |
2125 } | 2245 } |
2126 | 2246 |
2127 } // namespace | 2247 } // namespace |
2128 | 2248 |
2129 | 2249 |
2130 // static | 2250 // static |
2131 void Builtins::Generate_CallBoundFunction(MacroAssembler* masm) { | 2251 void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm, |
| 2252 TailCallMode tail_call_mode) { |
2132 // ----------- S t a t e ------------- | 2253 // ----------- S t a t e ------------- |
2133 // -- r0 : the number of arguments (not including the receiver) | 2254 // -- r0 : the number of arguments (not including the receiver) |
2134 // -- r1 : the function to call (checked to be a JSBoundFunction) | 2255 // -- r1 : the function to call (checked to be a JSBoundFunction) |
2135 // ----------------------------------- | 2256 // ----------------------------------- |
2136 __ AssertBoundFunction(r1); | 2257 __ AssertBoundFunction(r1); |
2137 | 2258 |
| 2259 if (tail_call_mode == TailCallMode::kAllow) { |
| 2260 PrepareForTailCall(masm, r0, r3, r4, r5); |
| 2261 } |
| 2262 |
2138 // Patch the receiver to [[BoundThis]]. | 2263 // Patch the receiver to [[BoundThis]]. |
2139 __ ldr(ip, FieldMemOperand(r1, JSBoundFunction::kBoundThisOffset)); | 2264 __ ldr(ip, FieldMemOperand(r1, JSBoundFunction::kBoundThisOffset)); |
2140 __ str(ip, MemOperand(sp, r0, LSL, kPointerSizeLog2)); | 2265 __ str(ip, MemOperand(sp, r0, LSL, kPointerSizeLog2)); |
2141 | 2266 |
2142 // Push the [[BoundArguments]] onto the stack. | 2267 // Push the [[BoundArguments]] onto the stack. |
2143 Generate_PushBoundArguments(masm); | 2268 Generate_PushBoundArguments(masm); |
2144 | 2269 |
2145 // Call the [[BoundTargetFunction]] via the Call builtin. | 2270 // Call the [[BoundTargetFunction]] via the Call builtin. |
2146 __ ldr(r1, FieldMemOperand(r1, JSBoundFunction::kBoundTargetFunctionOffset)); | 2271 __ ldr(r1, FieldMemOperand(r1, JSBoundFunction::kBoundTargetFunctionOffset)); |
2147 __ mov(ip, Operand(ExternalReference(Builtins::kCall_ReceiverIsAny, | 2272 __ mov(ip, Operand(ExternalReference(Builtins::kCall_ReceiverIsAny, |
2148 masm->isolate()))); | 2273 masm->isolate()))); |
2149 __ ldr(ip, MemOperand(ip)); | 2274 __ ldr(ip, MemOperand(ip)); |
2150 __ add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag)); | 2275 __ add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag)); |
2151 } | 2276 } |
2152 | 2277 |
2153 | 2278 |
2154 // static | 2279 // static |
2155 void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { | 2280 void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode, |
| 2281 TailCallMode tail_call_mode) { |
2156 // ----------- S t a t e ------------- | 2282 // ----------- S t a t e ------------- |
2157 // -- r0 : the number of arguments (not including the receiver) | 2283 // -- r0 : the number of arguments (not including the receiver) |
2158 // -- r1 : the target to call (can be any Object). | 2284 // -- r1 : the target to call (can be any Object). |
2159 // ----------------------------------- | 2285 // ----------------------------------- |
2160 | 2286 |
2161 Label non_callable, non_function, non_smi; | 2287 Label non_callable, non_function, non_smi; |
2162 __ JumpIfSmi(r1, &non_callable); | 2288 __ JumpIfSmi(r1, &non_callable); |
2163 __ bind(&non_smi); | 2289 __ bind(&non_smi); |
2164 __ CompareObjectType(r1, r4, r5, JS_FUNCTION_TYPE); | 2290 __ CompareObjectType(r1, r4, r5, JS_FUNCTION_TYPE); |
2165 __ Jump(masm->isolate()->builtins()->CallFunction(mode), | 2291 __ Jump(masm->isolate()->builtins()->CallFunction(mode, tail_call_mode), |
2166 RelocInfo::CODE_TARGET, eq); | 2292 RelocInfo::CODE_TARGET, eq); |
2167 __ cmp(r5, Operand(JS_BOUND_FUNCTION_TYPE)); | 2293 __ cmp(r5, Operand(JS_BOUND_FUNCTION_TYPE)); |
2168 __ Jump(masm->isolate()->builtins()->CallBoundFunction(), | 2294 __ Jump(masm->isolate()->builtins()->CallBoundFunction(tail_call_mode), |
2169 RelocInfo::CODE_TARGET, eq); | 2295 RelocInfo::CODE_TARGET, eq); |
2170 __ cmp(r5, Operand(JS_PROXY_TYPE)); | 2296 __ cmp(r5, Operand(JS_PROXY_TYPE)); |
2171 __ b(ne, &non_function); | 2297 __ b(ne, &non_function); |
2172 | 2298 |
| 2299 // 0. Prepare for tail call if necessary. |
| 2300 if (tail_call_mode == TailCallMode::kAllow) { |
| 2301 PrepareForTailCall(masm, r0, r3, r4, r5); |
| 2302 } |
| 2303 |
2173 // 1. Runtime fallback for Proxy [[Call]]. | 2304 // 1. Runtime fallback for Proxy [[Call]]. |
2174 __ Push(r1); | 2305 __ Push(r1); |
2175 // Increase the arguments size to include the pushed function and the | 2306 // Increase the arguments size to include the pushed function and the |
2176 // existing receiver on the stack. | 2307 // existing receiver on the stack. |
2177 __ add(r0, r0, Operand(2)); | 2308 __ add(r0, r0, Operand(2)); |
2178 // Tail-call to the runtime. | 2309 // Tail-call to the runtime. |
2179 __ JumpToExternalReference( | 2310 __ JumpToExternalReference( |
2180 ExternalReference(Runtime::kJSProxyCall, masm->isolate())); | 2311 ExternalReference(Runtime::kJSProxyCall, masm->isolate())); |
2181 | 2312 |
2182 // 2. Call to something else, which might have a [[Call]] internal method (if | 2313 // 2. Call to something else, which might have a [[Call]] internal method (if |
2183 // not we raise an exception). | 2314 // not we raise an exception). |
2184 __ bind(&non_function); | 2315 __ bind(&non_function); |
2185 // Check if target has a [[Call]] internal method. | 2316 // Check if target has a [[Call]] internal method. |
2186 __ ldrb(r4, FieldMemOperand(r4, Map::kBitFieldOffset)); | 2317 __ ldrb(r4, FieldMemOperand(r4, Map::kBitFieldOffset)); |
2187 __ tst(r4, Operand(1 << Map::kIsCallable)); | 2318 __ tst(r4, Operand(1 << Map::kIsCallable)); |
2188 __ b(eq, &non_callable); | 2319 __ b(eq, &non_callable); |
2189 // Overwrite the original receiver the (original) target. | 2320 // Overwrite the original receiver the (original) target. |
2190 __ str(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); | 2321 __ str(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); |
2191 // Let the "call_as_function_delegate" take care of the rest. | 2322 // Let the "call_as_function_delegate" take care of the rest. |
2192 __ LoadNativeContextSlot(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, r1); | 2323 __ LoadNativeContextSlot(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, r1); |
2193 __ Jump(masm->isolate()->builtins()->CallFunction( | 2324 __ Jump(masm->isolate()->builtins()->CallFunction( |
2194 ConvertReceiverMode::kNotNullOrUndefined), | 2325 ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode), |
2195 RelocInfo::CODE_TARGET); | 2326 RelocInfo::CODE_TARGET); |
2196 | 2327 |
2197 // 3. Call to something that is not callable. | 2328 // 3. Call to something that is not callable. |
2198 __ bind(&non_callable); | 2329 __ bind(&non_callable); |
2199 { | 2330 { |
2200 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); | 2331 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); |
2201 __ Push(r1); | 2332 __ Push(r1); |
2202 __ CallRuntime(Runtime::kThrowCalledNonCallable); | 2333 __ CallRuntime(Runtime::kThrowCalledNonCallable); |
2203 } | 2334 } |
2204 } | 2335 } |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2467 } | 2598 } |
2468 } | 2599 } |
2469 | 2600 |
2470 | 2601 |
2471 #undef __ | 2602 #undef __ |
2472 | 2603 |
2473 } // namespace internal | 2604 } // namespace internal |
2474 } // namespace v8 | 2605 } // namespace v8 |
2475 | 2606 |
2476 #endif // V8_TARGET_ARCH_ARM | 2607 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |