Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(139)

Side by Side Diff: src/arm/builtins-arm.cc

Issue 1609893003: [es6] Tail calls support. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Rebasing Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | src/arm/code-stubs-arm.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | src/arm/code-stubs-arm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698