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