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

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

Powered by Google App Engine
This is Rietveld 408576698