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

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

Issue 1637163003: X87: [es6] Tail calls support. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: 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 | « src/full-codegen/x87/full-codegen-x87.cc ('k') | src/x87/code-stubs-x87.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_X87 5 #if V8_TARGET_ARCH_X87
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 1839 matching lines...) Expand 10 before | Expand all | Expand 10 after
1850 } 1850 }
1851 1851
1852 // Dispatch to Call or Construct depending on whether new.target is undefined. 1852 // Dispatch to Call or Construct depending on whether new.target is undefined.
1853 { 1853 {
1854 __ CompareRoot(edx, Heap::kUndefinedValueRootIndex); 1854 __ CompareRoot(edx, Heap::kUndefinedValueRootIndex);
1855 __ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); 1855 __ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1856 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); 1856 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
1857 } 1857 }
1858 } 1858 }
1859 1859
1860 namespace {
1861
1862 // Drops top JavaScript frame and an arguments adaptor frame below it (if
1863 // present) preserving all the arguments prepared for current call.
1864 // Does nothing if debugger is currently active.
1865 // ES6 14.6.3. PrepareForTailCall
1866 //
1867 // Stack structure for the function g() tail calling f():
1868 //
1869 // ------- Caller frame: -------
1870 // | ...
1871 // | g()'s arg M
1872 // | ...
1873 // | g()'s arg 1
1874 // | g()'s receiver arg
1875 // | g()'s caller pc
1876 // ------- g()'s frame: -------
1877 // | g()'s caller fp <- fp
1878 // | g()'s context
1879 // | function pointer: g
1880 // | -------------------------
1881 // | ...
1882 // | ...
1883 // | f()'s arg N
1884 // | ...
1885 // | f()'s arg 1
1886 // | f()'s receiver arg
1887 // | f()'s caller pc <- sp
1888 // ----------------------
1889 //
1890 void PrepareForTailCall(MacroAssembler* masm, Register args_reg,
1891 Register scratch1, Register scratch2,
1892 Register scratch3) {
1893 DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
1894 Comment cmnt(masm, "[ PrepareForTailCall");
1895
1896 // Prepare for tail call only if the debugger is not active.
1897 Label done;
1898 ExternalReference debug_is_active =
1899 ExternalReference::debug_is_active_address(masm->isolate());
1900 __ movzx_b(scratch1, Operand::StaticVariable(debug_is_active));
1901 __ cmp(scratch1, Immediate(0));
1902 __ j(not_equal, &done, Label::kNear);
1903
1904 // Check if next frame is an arguments adaptor frame.
1905 Label no_arguments_adaptor, formal_parameter_count_loaded;
1906 __ mov(scratch2, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
1907 __ cmp(Operand(scratch2, StandardFrameConstants::kContextOffset),
1908 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1909 __ j(not_equal, &no_arguments_adaptor, Label::kNear);
1910
1911 // Drop arguments adaptor frame and load arguments count.
1912 __ mov(ebp, scratch2);
1913 __ mov(scratch1, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1914 __ SmiUntag(scratch1);
1915 __ jmp(&formal_parameter_count_loaded, Label::kNear);
1916
1917 __ bind(&no_arguments_adaptor);
1918 // Load caller's formal parameter count
1919 __ mov(scratch1, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1920 __ mov(scratch1,
1921 FieldOperand(scratch1, JSFunction::kSharedFunctionInfoOffset));
1922 __ mov(
1923 scratch1,
1924 FieldOperand(scratch1, SharedFunctionInfo::kFormalParameterCountOffset));
1925 __ SmiUntag(scratch1);
1926
1927 __ bind(&formal_parameter_count_loaded);
1928
1929 // Calculate the destination address where we will put the return address
1930 // after we drop current frame.
1931 Register new_sp_reg = scratch2;
1932 __ sub(scratch1, args_reg);
1933 __ lea(new_sp_reg, Operand(ebp, scratch1, times_pointer_size,
1934 StandardFrameConstants::kCallerPCOffset));
1935
1936 if (FLAG_debug_code) {
1937 __ cmp(esp, new_sp_reg);
1938 __ Check(below, kStackAccessBelowStackPointer);
1939 }
1940
1941 // Copy receiver and return address as well.
1942 Register count_reg = scratch1;
1943 __ lea(count_reg, Operand(args_reg, 2));
1944
1945 // Copy return address from caller's frame to current frame's return address
1946 // to avoid its trashing and let the following loop copy it to the right
1947 // place.
1948 Register tmp_reg = scratch3;
1949 __ mov(tmp_reg, Operand(ebp, StandardFrameConstants::kCallerPCOffset));
1950 __ mov(Operand(esp, 0), tmp_reg);
1951
1952 // Restore caller's frame pointer now as it could be overwritten by
1953 // the copying loop.
1954 __ mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
1955
1956 Operand src(esp, count_reg, times_pointer_size, 0);
1957 Operand dst(new_sp_reg, count_reg, times_pointer_size, 0);
1958
1959 // Now copy callee arguments to the caller frame going backwards to avoid
1960 // callee arguments corruption (source and destination areas could overlap).
1961 Label loop, entry;
1962 __ jmp(&entry, Label::kNear);
1963 __ bind(&loop);
1964 __ dec(count_reg);
1965 __ mov(tmp_reg, src);
1966 __ mov(dst, tmp_reg);
1967 __ bind(&entry);
1968 __ cmp(count_reg, Immediate(0));
1969 __ j(not_equal, &loop, Label::kNear);
1970
1971 // Leave current frame.
1972 __ mov(esp, new_sp_reg);
1973
1974 __ bind(&done);
1975 }
1976 } // namespace
1860 1977
1861 // static 1978 // static
1862 void Builtins::Generate_CallFunction(MacroAssembler* masm, 1979 void Builtins::Generate_CallFunction(MacroAssembler* masm,
1863 ConvertReceiverMode mode) { 1980 ConvertReceiverMode mode,
1981 TailCallMode tail_call_mode) {
1864 // ----------- S t a t e ------------- 1982 // ----------- S t a t e -------------
1865 // -- eax : the number of arguments (not including the receiver) 1983 // -- eax : the number of arguments (not including the receiver)
1866 // -- edi : the function to call (checked to be a JSFunction) 1984 // -- edi : the function to call (checked to be a JSFunction)
1867 // ----------------------------------- 1985 // -----------------------------------
1868 __ AssertFunction(edi); 1986 __ AssertFunction(edi);
1869 1987
1870 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList) 1988 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
1871 // Check that the function is not a "classConstructor". 1989 // Check that the function is not a "classConstructor".
1872 Label class_constructor; 1990 Label class_constructor;
1873 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 1991 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
1942 } 2060 }
1943 __ bind(&done_convert); 2061 __ bind(&done_convert);
1944 2062
1945 // ----------- S t a t e ------------- 2063 // ----------- S t a t e -------------
1946 // -- eax : the number of arguments (not including the receiver) 2064 // -- eax : the number of arguments (not including the receiver)
1947 // -- edx : the shared function info. 2065 // -- edx : the shared function info.
1948 // -- edi : the function to call (checked to be a JSFunction) 2066 // -- edi : the function to call (checked to be a JSFunction)
1949 // -- esi : the function context. 2067 // -- esi : the function context.
1950 // ----------------------------------- 2068 // -----------------------------------
1951 2069
2070 if (tail_call_mode == TailCallMode::kAllow) {
2071 PrepareForTailCall(masm, eax, ebx, ecx, edx);
2072 // Reload shared function info.
2073 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2074 }
2075
1952 __ mov(ebx, 2076 __ mov(ebx,
1953 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); 2077 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
1954 __ SmiUntag(ebx); 2078 __ SmiUntag(ebx);
1955 ParameterCount actual(eax); 2079 ParameterCount actual(eax);
1956 ParameterCount expected(ebx); 2080 ParameterCount expected(ebx);
1957 __ InvokeFunctionCode(edi, no_reg, expected, actual, JUMP_FUNCTION, 2081 __ InvokeFunctionCode(edi, no_reg, expected, actual, JUMP_FUNCTION,
1958 CheckDebugStepCallWrapper()); 2082 CheckDebugStepCallWrapper());
1959 // The function is a "classConstructor", need to raise an exception. 2083 // The function is a "classConstructor", need to raise an exception.
1960 __ bind(&class_constructor); 2084 __ bind(&class_constructor);
1961 { 2085 {
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
2047 // [[BoundArguments]]), so we need to subtract one for the return address. 2171 // [[BoundArguments]]), so we need to subtract one for the return address.
2048 __ dec(eax); 2172 __ dec(eax);
2049 } 2173 }
2050 __ bind(&no_bound_arguments); 2174 __ bind(&no_bound_arguments);
2051 } 2175 }
2052 2176
2053 } // namespace 2177 } // namespace
2054 2178
2055 2179
2056 // static 2180 // static
2057 void Builtins::Generate_CallBoundFunction(MacroAssembler* masm) { 2181 void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
2182 TailCallMode tail_call_mode) {
2058 // ----------- S t a t e ------------- 2183 // ----------- S t a t e -------------
2059 // -- eax : the number of arguments (not including the receiver) 2184 // -- eax : the number of arguments (not including the receiver)
2060 // -- edi : the function to call (checked to be a JSBoundFunction) 2185 // -- edi : the function to call (checked to be a JSBoundFunction)
2061 // ----------------------------------- 2186 // -----------------------------------
2062 __ AssertBoundFunction(edi); 2187 __ AssertBoundFunction(edi);
2063 2188
2189 if (tail_call_mode == TailCallMode::kAllow) {
2190 PrepareForTailCall(masm, eax, ebx, ecx, edx);
2191 }
2192
2064 // Patch the receiver to [[BoundThis]]. 2193 // Patch the receiver to [[BoundThis]].
2065 __ mov(ebx, FieldOperand(edi, JSBoundFunction::kBoundThisOffset)); 2194 __ mov(ebx, FieldOperand(edi, JSBoundFunction::kBoundThisOffset));
2066 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ebx); 2195 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ebx);
2067 2196
2068 // Push the [[BoundArguments]] onto the stack. 2197 // Push the [[BoundArguments]] onto the stack.
2069 Generate_PushBoundArguments(masm); 2198 Generate_PushBoundArguments(masm);
2070 2199
2071 // Call the [[BoundTargetFunction]] via the Call builtin. 2200 // Call the [[BoundTargetFunction]] via the Call builtin.
2072 __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset)); 2201 __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2073 __ mov(ecx, Operand::StaticVariable(ExternalReference( 2202 __ mov(ecx, Operand::StaticVariable(ExternalReference(
2074 Builtins::kCall_ReceiverIsAny, masm->isolate()))); 2203 Builtins::kCall_ReceiverIsAny, masm->isolate())));
2075 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); 2204 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2076 __ jmp(ecx); 2205 __ jmp(ecx);
2077 } 2206 }
2078 2207
2079 2208
2080 // static 2209 // static
2081 void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { 2210 void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode,
2211 TailCallMode tail_call_mode) {
2082 // ----------- S t a t e ------------- 2212 // ----------- S t a t e -------------
2083 // -- eax : the number of arguments (not including the receiver) 2213 // -- eax : the number of arguments (not including the receiver)
2084 // -- edi : the target to call (can be any Object). 2214 // -- edi : the target to call (can be any Object).
2085 // ----------------------------------- 2215 // -----------------------------------
2086 2216
2087 Label non_callable, non_function, non_smi; 2217 Label non_callable, non_function, non_smi;
2088 __ JumpIfSmi(edi, &non_callable); 2218 __ JumpIfSmi(edi, &non_callable);
2089 __ bind(&non_smi); 2219 __ bind(&non_smi);
2090 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); 2220 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
2091 __ j(equal, masm->isolate()->builtins()->CallFunction(mode), 2221 __ j(equal, masm->isolate()->builtins()->CallFunction(mode, tail_call_mode),
2092 RelocInfo::CODE_TARGET); 2222 RelocInfo::CODE_TARGET);
2093 __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE); 2223 __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
2094 __ j(equal, masm->isolate()->builtins()->CallBoundFunction(), 2224 __ j(equal, masm->isolate()->builtins()->CallBoundFunction(tail_call_mode),
2095 RelocInfo::CODE_TARGET); 2225 RelocInfo::CODE_TARGET);
2096 __ CmpInstanceType(ecx, JS_PROXY_TYPE); 2226 __ CmpInstanceType(ecx, JS_PROXY_TYPE);
2097 __ j(not_equal, &non_function); 2227 __ j(not_equal, &non_function);
2098 2228
2229 // 0. Prepare for tail call if necessary.
2230 if (tail_call_mode == TailCallMode::kAllow) {
2231 PrepareForTailCall(masm, eax, ebx, ecx, edx);
2232 }
2233
2099 // 1. Runtime fallback for Proxy [[Call]]. 2234 // 1. Runtime fallback for Proxy [[Call]].
2100 __ PopReturnAddressTo(ecx); 2235 __ PopReturnAddressTo(ecx);
2101 __ Push(edi); 2236 __ Push(edi);
2102 __ PushReturnAddressFrom(ecx); 2237 __ PushReturnAddressFrom(ecx);
2103 // Increase the arguments size to include the pushed function and the 2238 // Increase the arguments size to include the pushed function and the
2104 // existing receiver on the stack. 2239 // existing receiver on the stack.
2105 __ add(eax, Immediate(2)); 2240 __ add(eax, Immediate(2));
2106 // Tail-call to the runtime. 2241 // Tail-call to the runtime.
2107 __ JumpToExternalReference( 2242 __ JumpToExternalReference(
2108 ExternalReference(Runtime::kJSProxyCall, masm->isolate())); 2243 ExternalReference(Runtime::kJSProxyCall, masm->isolate()));
2109 2244
2110 // 2. Call to something else, which might have a [[Call]] internal method (if 2245 // 2. Call to something else, which might have a [[Call]] internal method (if
2111 // not we raise an exception). 2246 // not we raise an exception).
2112 __ bind(&non_function); 2247 __ bind(&non_function);
2113 // Check if target has a [[Call]] internal method. 2248 // Check if target has a [[Call]] internal method.
2114 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable); 2249 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable);
2115 __ j(zero, &non_callable, Label::kNear); 2250 __ j(zero, &non_callable, Label::kNear);
2116 // Overwrite the original receiver with the (original) target. 2251 // Overwrite the original receiver with the (original) target.
2117 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi); 2252 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
2118 // Let the "call_as_function_delegate" take care of the rest. 2253 // Let the "call_as_function_delegate" take care of the rest.
2119 __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, edi); 2254 __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, edi);
2120 __ Jump(masm->isolate()->builtins()->CallFunction( 2255 __ Jump(masm->isolate()->builtins()->CallFunction(
2121 ConvertReceiverMode::kNotNullOrUndefined), 2256 ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode),
2122 RelocInfo::CODE_TARGET); 2257 RelocInfo::CODE_TARGET);
2123 2258
2124 // 3. Call to something that is not callable. 2259 // 3. Call to something that is not callable.
2125 __ bind(&non_callable); 2260 __ bind(&non_callable);
2126 { 2261 {
2127 FrameScope scope(masm, StackFrame::INTERNAL); 2262 FrameScope scope(masm, StackFrame::INTERNAL);
2128 __ Push(edi); 2263 __ Push(edi);
2129 __ CallRuntime(Runtime::kThrowCalledNonCallable); 2264 __ CallRuntime(Runtime::kThrowCalledNonCallable);
2130 } 2265 }
2131 } 2266 }
(...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after
2548 2683
2549 __ bind(&ok); 2684 __ bind(&ok);
2550 __ ret(0); 2685 __ ret(0);
2551 } 2686 }
2552 2687
2553 #undef __ 2688 #undef __
2554 } // namespace internal 2689 } // namespace internal
2555 } // namespace v8 2690 } // namespace v8
2556 2691
2557 #endif // V8_TARGET_ARCH_X87 2692 #endif // V8_TARGET_ARCH_X87
OLDNEW
« no previous file with comments | « src/full-codegen/x87/full-codegen-x87.cc ('k') | src/x87/code-stubs-x87.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698