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

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

Issue 1609893003: [es6] Tail calls support. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Rebasing Created 4 years, 11 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 | « src/parsing/parser.cc ('k') | src/x64/code-stubs-x64.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_X64 5 #if V8_TARGET_ARCH_X64
6 6
7 #include "src/code-factory.h" 7 #include "src/code-factory.h"
8 #include "src/codegen.h" 8 #include "src/codegen.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 1183 matching lines...) Expand 10 before | Expand all | Expand 10 after
1194 __ JumpIfRoot(rax, Heap::kNullValueRootIndex, &no_arguments, Label::kNear); 1194 __ JumpIfRoot(rax, Heap::kNullValueRootIndex, &no_arguments, Label::kNear);
1195 __ JumpIfRoot(rax, Heap::kUndefinedValueRootIndex, &no_arguments, 1195 __ JumpIfRoot(rax, Heap::kUndefinedValueRootIndex, &no_arguments,
1196 Label::kNear); 1196 Label::kNear);
1197 1197
1198 // 4a. Apply the receiver to the given argArray (passing undefined for 1198 // 4a. Apply the receiver to the given argArray (passing undefined for
1199 // new.target). 1199 // new.target).
1200 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); 1200 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
1201 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET); 1201 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1202 1202
1203 // 4b. The argArray is either null or undefined, so we tail call without any 1203 // 4b. The argArray is either null or undefined, so we tail call without any
1204 // arguments to the receiver. 1204 // arguments to the receiver. Since we did not create a frame for
1205 // Function.prototype.apply() yet, we use a normal Call builtin here.
1205 __ bind(&no_arguments); 1206 __ bind(&no_arguments);
1206 { 1207 {
1207 __ Set(rax, 0); 1208 __ Set(rax, 0);
1208 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); 1209 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1209 } 1210 }
1210 1211
1211 // 4c. The receiver is not callable, throw an appropriate TypeError. 1212 // 4c. The receiver is not callable, throw an appropriate TypeError.
1212 __ bind(&receiver_not_callable); 1213 __ bind(&receiver_not_callable);
1213 { 1214 {
1214 StackArgumentsAccessor args(rsp, 0); 1215 StackArgumentsAccessor args(rsp, 0);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1258 __ bind(&loop); 1259 __ bind(&loop);
1259 __ movp(rbx, args.GetArgumentOperand(1)); 1260 __ movp(rbx, args.GetArgumentOperand(1));
1260 __ movp(args.GetArgumentOperand(0), rbx); 1261 __ movp(args.GetArgumentOperand(0), rbx);
1261 __ decp(rcx); 1262 __ decp(rcx);
1262 __ j(not_zero, &loop); // While non-zero. 1263 __ j(not_zero, &loop); // While non-zero.
1263 __ DropUnderReturnAddress(1, rbx); // Drop one slot under return address. 1264 __ DropUnderReturnAddress(1, rbx); // Drop one slot under return address.
1264 __ decp(rax); // One fewer argument (first argument is new receiver). 1265 __ decp(rax); // One fewer argument (first argument is new receiver).
1265 } 1266 }
1266 1267
1267 // 4. Call the callable. 1268 // 4. Call the callable.
1269 // Since we did not create a frame for Function.prototype.call() yet,
1270 // we use a normal Call builtin here.
1268 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); 1271 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1269 } 1272 }
1270 1273
1271 1274
1272 void Builtins::Generate_ReflectApply(MacroAssembler* masm) { 1275 void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
1273 // ----------- S t a t e ------------- 1276 // ----------- S t a t e -------------
1274 // -- rax : argc 1277 // -- rax : argc
1275 // -- rsp[0] : return address 1278 // -- rsp[0] : return address
1276 // -- rsp[8] : argumentsList 1279 // -- rsp[8] : argumentsList
1277 // -- rsp[16] : thisArgument 1280 // -- rsp[16] : thisArgument
(...skipping 760 matching lines...) Expand 10 before | Expand all | Expand 10 after
2038 } 2041 }
2039 2042
2040 // Dispatch to Call or Construct depending on whether new.target is undefined. 2043 // Dispatch to Call or Construct depending on whether new.target is undefined.
2041 { 2044 {
2042 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); 2045 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
2043 __ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); 2046 __ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
2044 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); 2047 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
2045 } 2048 }
2046 } 2049 }
2047 2050
2051 namespace {
2052
2053 // Drops top JavaScript frame and an arguments adaptor frame below it (if
2054 // present) preserving all the arguments prepared for current call.
2055 // Does nothing if debugger is currently active.
2056 // ES6 14.6.3. PrepareForTailCall
2057 //
2058 // Stack structure for the function g() tail calling f():
2059 //
2060 // ------- Caller frame: -------
2061 // | ...
2062 // | g()'s arg M
2063 // | ...
2064 // | g()'s arg 1
2065 // | g()'s receiver arg
2066 // | g()'s caller pc
2067 // ------- g()'s frame: -------
2068 // | g()'s caller fp <- fp
2069 // | g()'s context
2070 // | function pointer: g
2071 // | -------------------------
2072 // | ...
2073 // | ...
2074 // | f()'s arg N
2075 // | ...
2076 // | f()'s arg 1
2077 // | f()'s receiver arg
2078 // | f()'s caller pc <- sp
2079 // ----------------------
2080 //
2081 void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
2082 Register scratch1, Register scratch2,
2083 Register scratch3) {
2084 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
2085 Comment cmnt(masm, "[ PrepareForTailCall");
2086
2087 // Prepare for tail call only if the debugger is not active.
2088 Label done;
2089 ExternalReference debug_is_active =
2090 ExternalReference::debug_is_active_address(masm->isolate());
2091 __ Move(kScratchRegister, debug_is_active);
2092 __ cmpb(Operand(kScratchRegister, 0), Immediate(0));
2093 __ j(not_equal, &done, Label::kNear);
2094
2095 // Check if next frame is an arguments adaptor frame.
2096 Label no_arguments_adaptor, formal_parameter_count_loaded;
2097 __ movp(scratch2, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
2098 __ Cmp(Operand(scratch2, StandardFrameConstants::kContextOffset),
2099 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
2100 __ j(not_equal, &no_arguments_adaptor, Label::kNear);
2101
2102 // Drop arguments adaptor frame and load arguments count.
2103 __ movp(rbp, scratch2);
2104 __ SmiToInteger32(
2105 scratch1, Operand(rbp, ArgumentsAdaptorFrameConstants::kLengthOffset));
2106 __ jmp(&formal_parameter_count_loaded, Label::kNear);
2107
2108 __ bind(&no_arguments_adaptor);
2109 // Load caller's formal parameter count
2110 __ movp(scratch1, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
2111 __ movp(scratch1,
2112 FieldOperand(scratch1, JSFunction::kSharedFunctionInfoOffset));
2113 __ LoadSharedFunctionInfoSpecialField(
2114 scratch1, scratch1, SharedFunctionInfo::kFormalParameterCountOffset);
2115
2116 __ bind(&formal_parameter_count_loaded);
2117
2118 // Calculate the destination address where we will put the return address
2119 // after we drop current frame.
2120 Register new_sp_reg = scratch2;
2121 __ subp(scratch1, args_reg);
2122 __ leap(new_sp_reg, Operand(rbp, scratch1, times_pointer_size,
2123 StandardFrameConstants::kCallerPCOffset));
2124
2125 if (FLAG_debug_code) {
2126 __ cmpp(rsp, new_sp_reg);
2127 __ Check(below, kStackAccessBelowStackPointer);
2128 }
2129
2130 // Copy receiver and return address as well.
2131 Register count_reg = scratch1;
2132 __ leap(count_reg, Operand(args_reg, 2));
2133
2134 // Copy return address from caller's frame to current frame's return address
2135 // to avoid its trashing and let the following loop copy it to the right
2136 // place.
2137 Register tmp_reg = scratch3;
2138 __ movp(tmp_reg, Operand(rbp, StandardFrameConstants::kCallerPCOffset));
2139 __ movp(Operand(rsp, 0), tmp_reg);
2140
2141 // Restore caller's frame pointer now as it could be overwritten by
2142 // the copying loop.
2143 __ movp(rbp, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
2144
2145 Operand src(rsp, count_reg, times_pointer_size, 0);
2146 Operand dst(new_sp_reg, count_reg, times_pointer_size, 0);
2147
2148 // Now copy callee arguments to the caller frame going backwards to avoid
2149 // callee arguments corruption (source and destination areas could overlap).
2150 Label loop, entry;
2151 __ jmp(&entry, Label::kNear);
2152 __ bind(&loop);
2153 __ decp(count_reg);
2154 __ movp(tmp_reg, src);
2155 __ movp(dst, tmp_reg);
2156 __ bind(&entry);
2157 __ cmpp(count_reg, Immediate(0));
2158 __ j(not_equal, &loop, Label::kNear);
2159
2160 // Leave current frame.
2161 __ movp(rsp, new_sp_reg);
2162
2163 __ bind(&done);
2164 }
2165 } // namespace
2048 2166
2049 // static 2167 // static
2050 void Builtins::Generate_CallFunction(MacroAssembler* masm, 2168 void Builtins::Generate_CallFunction(MacroAssembler* masm,
2051 ConvertReceiverMode mode) { 2169 ConvertReceiverMode mode,
2170 TailCallMode tail_call_mode) {
2052 // ----------- S t a t e ------------- 2171 // ----------- S t a t e -------------
2053 // -- rax : the number of arguments (not including the receiver) 2172 // -- rax : the number of arguments (not including the receiver)
2054 // -- rdi : the function to call (checked to be a JSFunction) 2173 // -- rdi : the function to call (checked to be a JSFunction)
2055 // ----------------------------------- 2174 // -----------------------------------
2056 StackArgumentsAccessor args(rsp, rax); 2175 StackArgumentsAccessor args(rsp, rax);
2057 __ AssertFunction(rdi); 2176 __ AssertFunction(rdi);
2058 2177
2059 // ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList) 2178 // ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
2060 // Check that the function is not a "classConstructor". 2179 // Check that the function is not a "classConstructor".
2061 Label class_constructor; 2180 Label class_constructor;
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
2137 } 2256 }
2138 __ bind(&done_convert); 2257 __ bind(&done_convert);
2139 2258
2140 // ----------- S t a t e ------------- 2259 // ----------- S t a t e -------------
2141 // -- rax : the number of arguments (not including the receiver) 2260 // -- rax : the number of arguments (not including the receiver)
2142 // -- rdx : the shared function info. 2261 // -- rdx : the shared function info.
2143 // -- rdi : the function to call (checked to be a JSFunction) 2262 // -- rdi : the function to call (checked to be a JSFunction)
2144 // -- rsi : the function context. 2263 // -- rsi : the function context.
2145 // ----------------------------------- 2264 // -----------------------------------
2146 2265
2266 if (tail_call_mode == TailCallMode::kAllow) {
2267 PrepareForTailCall(masm, rax, rbx, rcx, r8);
2268 }
2269
2147 __ LoadSharedFunctionInfoSpecialField( 2270 __ LoadSharedFunctionInfoSpecialField(
2148 rbx, rdx, SharedFunctionInfo::kFormalParameterCountOffset); 2271 rbx, rdx, SharedFunctionInfo::kFormalParameterCountOffset);
2149 ParameterCount actual(rax); 2272 ParameterCount actual(rax);
2150 ParameterCount expected(rbx); 2273 ParameterCount expected(rbx);
2151 2274
2152 __ InvokeFunctionCode(rdi, no_reg, expected, actual, JUMP_FUNCTION, 2275 __ InvokeFunctionCode(rdi, no_reg, expected, actual, JUMP_FUNCTION,
2153 CheckDebugStepCallWrapper()); 2276 CheckDebugStepCallWrapper());
2154 2277
2155 // The function is a "classConstructor", need to raise an exception. 2278 // The function is a "classConstructor", need to raise an exception.
2156 __ bind(&class_constructor); 2279 __ bind(&class_constructor);
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
2241 // [[BoundArguments]]), so we need to subtract one for the return address. 2364 // [[BoundArguments]]), so we need to subtract one for the return address.
2242 __ decl(rax); 2365 __ decl(rax);
2243 } 2366 }
2244 __ bind(&no_bound_arguments); 2367 __ bind(&no_bound_arguments);
2245 } 2368 }
2246 2369
2247 } // namespace 2370 } // namespace
2248 2371
2249 2372
2250 // static 2373 // static
2251 void Builtins::Generate_CallBoundFunction(MacroAssembler* masm) { 2374 void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
2375 TailCallMode tail_call_mode) {
2252 // ----------- S t a t e ------------- 2376 // ----------- S t a t e -------------
2253 // -- rax : the number of arguments (not including the receiver) 2377 // -- rax : the number of arguments (not including the receiver)
2254 // -- rdi : the function to call (checked to be a JSBoundFunction) 2378 // -- rdi : the function to call (checked to be a JSBoundFunction)
2255 // ----------------------------------- 2379 // -----------------------------------
2256 __ AssertBoundFunction(rdi); 2380 __ AssertBoundFunction(rdi);
2257 2381
2382 if (tail_call_mode == TailCallMode::kAllow) {
2383 PrepareForTailCall(masm, rax, rbx, rcx, r8);
2384 }
2385
2258 // Patch the receiver to [[BoundThis]]. 2386 // Patch the receiver to [[BoundThis]].
2259 StackArgumentsAccessor args(rsp, rax); 2387 StackArgumentsAccessor args(rsp, rax);
2260 __ movp(rbx, FieldOperand(rdi, JSBoundFunction::kBoundThisOffset)); 2388 __ movp(rbx, FieldOperand(rdi, JSBoundFunction::kBoundThisOffset));
2261 __ movp(args.GetReceiverOperand(), rbx); 2389 __ movp(args.GetReceiverOperand(), rbx);
2262 2390
2263 // Push the [[BoundArguments]] onto the stack. 2391 // Push the [[BoundArguments]] onto the stack.
2264 Generate_PushBoundArguments(masm); 2392 Generate_PushBoundArguments(masm);
2265 2393
2266 // Call the [[BoundTargetFunction]] via the Call builtin. 2394 // Call the [[BoundTargetFunction]] via the Call builtin.
2267 __ movp(rdi, FieldOperand(rdi, JSBoundFunction::kBoundTargetFunctionOffset)); 2395 __ movp(rdi, FieldOperand(rdi, JSBoundFunction::kBoundTargetFunctionOffset));
2268 __ Load(rcx, 2396 __ Load(rcx,
2269 ExternalReference(Builtins::kCall_ReceiverIsAny, masm->isolate())); 2397 ExternalReference(Builtins::kCall_ReceiverIsAny, masm->isolate()));
2270 __ leap(rcx, FieldOperand(rcx, Code::kHeaderSize)); 2398 __ leap(rcx, FieldOperand(rcx, Code::kHeaderSize));
2271 __ jmp(rcx); 2399 __ jmp(rcx);
2272 } 2400 }
2273 2401
2274 2402
2275 // static 2403 // static
2276 void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { 2404 void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
2405 TailCallMode tail_call_mode) {
2277 // ----------- S t a t e ------------- 2406 // ----------- S t a t e -------------
2278 // -- rax : the number of arguments (not including the receiver) 2407 // -- rax : the number of arguments (not including the receiver)
2279 // -- rdi : the target to call (can be any Object) 2408 // -- rdi : the target to call (can be any Object)
2280 // ----------------------------------- 2409 // -----------------------------------
2281 StackArgumentsAccessor args(rsp, rax); 2410 StackArgumentsAccessor args(rsp, rax);
2282 2411
2283 Label non_callable, non_function, non_smi; 2412 Label non_callable, non_function, non_smi;
2284 __ JumpIfSmi(rdi, &non_callable); 2413 __ JumpIfSmi(rdi, &non_callable);
2285 __ bind(&non_smi); 2414 __ bind(&non_smi);
2286 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); 2415 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
2287 __ j(equal, masm->isolate()->builtins()->CallFunction(mode), 2416 __ j(equal, masm->isolate()->builtins()->CallFunction(mode, tail_call_mode),
2288 RelocInfo::CODE_TARGET); 2417 RelocInfo::CODE_TARGET);
2289 __ CmpInstanceType(rcx, JS_BOUND_FUNCTION_TYPE); 2418 __ CmpInstanceType(rcx, JS_BOUND_FUNCTION_TYPE);
2290 __ j(equal, masm->isolate()->builtins()->CallBoundFunction(), 2419 __ j(equal, masm->isolate()->builtins()->CallBoundFunction(tail_call_mode),
2291 RelocInfo::CODE_TARGET); 2420 RelocInfo::CODE_TARGET);
2292 __ CmpInstanceType(rcx, JS_PROXY_TYPE); 2421 __ CmpInstanceType(rcx, JS_PROXY_TYPE);
2293 __ j(not_equal, &non_function); 2422 __ j(not_equal, &non_function);
2294 2423
2424 // 0. Prepare for tail call if necessary.
2425 if (tail_call_mode == TailCallMode::kAllow) {
2426 PrepareForTailCall(masm, rax, rbx, rcx, r8);
2427 }
2428
2295 // 1. Runtime fallback for Proxy [[Call]]. 2429 // 1. Runtime fallback for Proxy [[Call]].
2296 __ PopReturnAddressTo(kScratchRegister); 2430 __ PopReturnAddressTo(kScratchRegister);
2297 __ Push(rdi); 2431 __ Push(rdi);
2298 __ PushReturnAddressFrom(kScratchRegister); 2432 __ PushReturnAddressFrom(kScratchRegister);
2299 // Increase the arguments size to include the pushed function and the 2433 // Increase the arguments size to include the pushed function and the
2300 // existing receiver on the stack. 2434 // existing receiver on the stack.
2301 __ addp(rax, Immediate(2)); 2435 __ addp(rax, Immediate(2));
2302 // Tail-call to the runtime. 2436 // Tail-call to the runtime.
2303 __ JumpToExternalReference( 2437 __ JumpToExternalReference(
2304 ExternalReference(Runtime::kJSProxyCall, masm->isolate())); 2438 ExternalReference(Runtime::kJSProxyCall, masm->isolate()));
2305 2439
2306 // 2. Call to something else, which might have a [[Call]] internal method (if 2440 // 2. Call to something else, which might have a [[Call]] internal method (if
2307 // not we raise an exception). 2441 // not we raise an exception).
2308 __ bind(&non_function); 2442 __ bind(&non_function);
2309 // Check if target has a [[Call]] internal method. 2443 // Check if target has a [[Call]] internal method.
2310 __ testb(FieldOperand(rcx, Map::kBitFieldOffset), 2444 __ testb(FieldOperand(rcx, Map::kBitFieldOffset),
2311 Immediate(1 << Map::kIsCallable)); 2445 Immediate(1 << Map::kIsCallable));
2312 __ j(zero, &non_callable, Label::kNear); 2446 __ j(zero, &non_callable, Label::kNear);
2313 // Overwrite the original receiver with the (original) target. 2447 // Overwrite the original receiver with the (original) target.
2314 __ movp(args.GetReceiverOperand(), rdi); 2448 __ movp(args.GetReceiverOperand(), rdi);
2315 // Let the "call_as_function_delegate" take care of the rest. 2449 // Let the "call_as_function_delegate" take care of the rest.
2316 __ LoadNativeContextSlot(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, rdi); 2450 __ LoadNativeContextSlot(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, rdi);
2317 __ Jump(masm->isolate()->builtins()->CallFunction( 2451 __ Jump(masm->isolate()->builtins()->CallFunction(
2318 ConvertReceiverMode::kNotNullOrUndefined), 2452 ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode),
2319 RelocInfo::CODE_TARGET); 2453 RelocInfo::CODE_TARGET);
2320 2454
2321 // 3. Call to something that is not callable. 2455 // 3. Call to something that is not callable.
2322 __ bind(&non_callable); 2456 __ bind(&non_callable);
2323 { 2457 {
2324 FrameScope scope(masm, StackFrame::INTERNAL); 2458 FrameScope scope(masm, StackFrame::INTERNAL);
2325 __ Push(rdi); 2459 __ Push(rdi);
2326 __ CallRuntime(Runtime::kThrowCalledNonCallable); 2460 __ CallRuntime(Runtime::kThrowCalledNonCallable);
2327 } 2461 }
2328 } 2462 }
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
2619 __ ret(0); 2753 __ ret(0);
2620 } 2754 }
2621 2755
2622 2756
2623 #undef __ 2757 #undef __
2624 2758
2625 } // namespace internal 2759 } // namespace internal
2626 } // namespace v8 2760 } // namespace v8
2627 2761
2628 #endif // V8_TARGET_ARCH_X64 2762 #endif // V8_TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « src/parsing/parser.cc ('k') | src/x64/code-stubs-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698