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_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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |