| 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/base/bits.h" | 7 #include "src/base/bits.h" |
| 8 #include "src/bootstrapper.h" | 8 #include "src/bootstrapper.h" |
| 9 #include "src/code-stubs.h" | 9 #include "src/code-stubs.h" |
| 10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
| (...skipping 2011 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2022 CallStubInRecordCallTarget(masm, &create_stub, is_super); | 2022 CallStubInRecordCallTarget(masm, &create_stub, is_super); |
| 2023 __ jmp(&done); | 2023 __ jmp(&done); |
| 2024 | 2024 |
| 2025 __ bind(¬_array_function); | 2025 __ bind(¬_array_function); |
| 2026 CreateWeakCellStub weak_cell_stub(isolate); | 2026 CreateWeakCellStub weak_cell_stub(isolate); |
| 2027 CallStubInRecordCallTarget(masm, &weak_cell_stub, is_super); | 2027 CallStubInRecordCallTarget(masm, &weak_cell_stub, is_super); |
| 2028 __ bind(&done); | 2028 __ bind(&done); |
| 2029 } | 2029 } |
| 2030 | 2030 |
| 2031 | 2031 |
| 2032 static void EmitContinueIfStrictOrNative(MacroAssembler* masm, Label* cont) { | |
| 2033 // ----------- S t a t e ------------- | |
| 2034 // -- edi : the function to call | |
| 2035 // -- edx : the function's shared function info | |
| 2036 // ----------------------------------- | |
| 2037 // Do not transform the receiver for strict mode functions. | |
| 2038 __ test_b(FieldOperand(edx, SharedFunctionInfo::kStrictModeByteOffset), | |
| 2039 1 << SharedFunctionInfo::kStrictModeBitWithinByte); | |
| 2040 __ j(not_equal, cont); | |
| 2041 | |
| 2042 // Do not transform the receiver for natives (shared already in ecx). | |
| 2043 __ test_b(FieldOperand(edx, SharedFunctionInfo::kNativeByteOffset), | |
| 2044 1 << SharedFunctionInfo::kNativeBitWithinByte); | |
| 2045 __ j(not_equal, cont); | |
| 2046 } | |
| 2047 | |
| 2048 | |
| 2049 static void EmitSlowCase(Isolate* isolate, MacroAssembler* masm, int argc) { | |
| 2050 __ Set(eax, argc); | |
| 2051 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); | |
| 2052 } | |
| 2053 | |
| 2054 | |
| 2055 static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) { | |
| 2056 // Wrap the receiver and patch it back onto the stack. | |
| 2057 { FrameScope frame_scope(masm, StackFrame::INTERNAL); | |
| 2058 __ push(edi); | |
| 2059 ToObjectStub stub(masm->isolate()); | |
| 2060 __ CallStub(&stub); | |
| 2061 __ pop(edi); | |
| 2062 } | |
| 2063 __ mov(Operand(esp, (argc + 1) * kPointerSize), eax); | |
| 2064 __ jmp(cont); | |
| 2065 } | |
| 2066 | |
| 2067 | |
| 2068 static void EmitClassConstructorCallCheck(MacroAssembler* masm) { | |
| 2069 // ----------- S t a t e ------------- | |
| 2070 // -- edi : the function to call | |
| 2071 // -- edx : the function's shared function info | |
| 2072 // ----------------------------------- | |
| 2073 // ClassConstructor Check: ES6 section 9.2.1 [[Call]] | |
| 2074 Label non_class_constructor; | |
| 2075 // Check whether the current function is a classConstructor. | |
| 2076 __ test_b(FieldOperand(edx, SharedFunctionInfo::kFunctionKindByteOffset), | |
| 2077 SharedFunctionInfo::kClassConstructorBitsWithinByte); | |
| 2078 __ j(zero, &non_class_constructor, Label::kNear); | |
| 2079 // If we call a classConstructor Function throw a TypeError | |
| 2080 // indirectly via the CallFunction builtin. | |
| 2081 __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET); | |
| 2082 __ bind(&non_class_constructor); | |
| 2083 } | |
| 2084 | |
| 2085 | |
| 2086 static void CallFunctionNoFeedback(MacroAssembler* masm, | |
| 2087 int argc, bool needs_checks, | |
| 2088 bool call_as_method) { | |
| 2089 // edi : the function to call | |
| 2090 Label slow, wrap, cont; | |
| 2091 | |
| 2092 if (needs_checks) { | |
| 2093 // Check that the function really is a JavaScript function. | |
| 2094 __ JumpIfSmi(edi, &slow); | |
| 2095 | |
| 2096 // Goto slow case if we do not have a function. | |
| 2097 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | |
| 2098 __ j(not_equal, &slow); | |
| 2099 } | |
| 2100 | |
| 2101 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | |
| 2102 EmitClassConstructorCallCheck(masm); | |
| 2103 | |
| 2104 // Fast-case: Just invoke the function. | |
| 2105 ParameterCount actual(argc); | |
| 2106 | |
| 2107 if (call_as_method) { | |
| 2108 if (needs_checks) { | |
| 2109 EmitContinueIfStrictOrNative(masm, &cont); | |
| 2110 } | |
| 2111 | |
| 2112 // Load the receiver from the stack. | |
| 2113 __ mov(eax, Operand(esp, (argc + 1) * kPointerSize)); | |
| 2114 | |
| 2115 if (needs_checks) { | |
| 2116 __ JumpIfSmi(eax, &wrap); | |
| 2117 | |
| 2118 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); | |
| 2119 __ j(below, &wrap); | |
| 2120 } else { | |
| 2121 __ jmp(&wrap); | |
| 2122 } | |
| 2123 | |
| 2124 __ bind(&cont); | |
| 2125 } | |
| 2126 | |
| 2127 __ InvokeFunction(edi, actual, JUMP_FUNCTION, NullCallWrapper()); | |
| 2128 | |
| 2129 if (needs_checks) { | |
| 2130 // Slow-case: Non-function called. | |
| 2131 __ bind(&slow); | |
| 2132 EmitSlowCase(masm->isolate(), masm, argc); | |
| 2133 } | |
| 2134 | |
| 2135 if (call_as_method) { | |
| 2136 __ bind(&wrap); | |
| 2137 EmitWrapCase(masm, argc, &cont); | |
| 2138 } | |
| 2139 } | |
| 2140 | |
| 2141 | |
| 2142 void CallFunctionStub::Generate(MacroAssembler* masm) { | |
| 2143 CallFunctionNoFeedback(masm, argc(), NeedsChecks(), CallAsMethod()); | |
| 2144 } | |
| 2145 | |
| 2146 | |
| 2147 void CallConstructStub::Generate(MacroAssembler* masm) { | 2032 void CallConstructStub::Generate(MacroAssembler* masm) { |
| 2148 // eax : number of arguments | 2033 // eax : number of arguments |
| 2149 // ebx : feedback vector | 2034 // ebx : feedback vector |
| 2150 // ecx : original constructor (for IsSuperConstructorCall) | 2035 // ecx : original constructor (for IsSuperConstructorCall) |
| 2151 // edx : slot in feedback vector (Smi, for RecordCallTarget) | 2036 // edx : slot in feedback vector (Smi, for RecordCallTarget) |
| 2152 // edi : constructor function | 2037 // edi : constructor function |
| 2153 | 2038 |
| 2154 if (IsSuperConstructorCall()) { | 2039 if (IsSuperConstructorCall()) { |
| 2155 __ push(ecx); | 2040 __ push(ecx); |
| 2156 } | 2041 } |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2229 | 2114 |
| 2230 void CallICStub::Generate(MacroAssembler* masm) { | 2115 void CallICStub::Generate(MacroAssembler* masm) { |
| 2231 // edi - function | 2116 // edi - function |
| 2232 // edx - slot id | 2117 // edx - slot id |
| 2233 // ebx - vector | 2118 // ebx - vector |
| 2234 Isolate* isolate = masm->isolate(); | 2119 Isolate* isolate = masm->isolate(); |
| 2235 const int with_types_offset = | 2120 const int with_types_offset = |
| 2236 FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex); | 2121 FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex); |
| 2237 const int generic_offset = | 2122 const int generic_offset = |
| 2238 FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex); | 2123 FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex); |
| 2239 Label extra_checks_or_miss, slow_start; | 2124 Label extra_checks_or_miss, call; |
| 2240 Label slow, wrap, cont; | |
| 2241 Label have_js_function; | |
| 2242 int argc = arg_count(); | 2125 int argc = arg_count(); |
| 2243 ParameterCount actual(argc); | 2126 ParameterCount actual(argc); |
| 2244 | 2127 |
| 2245 // The checks. First, does edi match the recorded monomorphic target? | 2128 // The checks. First, does edi match the recorded monomorphic target? |
| 2246 __ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size, | 2129 __ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size, |
| 2247 FixedArray::kHeaderSize)); | 2130 FixedArray::kHeaderSize)); |
| 2248 | 2131 |
| 2249 // We don't know that we have a weak cell. We might have a private symbol | 2132 // We don't know that we have a weak cell. We might have a private symbol |
| 2250 // or an AllocationSite, but the memory is safe to examine. | 2133 // or an AllocationSite, but the memory is safe to examine. |
| 2251 // AllocationSite::kTransitionInfoOffset - contains a Smi or pointer to | 2134 // AllocationSite::kTransitionInfoOffset - contains a Smi or pointer to |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2265 | 2148 |
| 2266 // The compare above could have been a SMI/SMI comparison. Guard against this | 2149 // The compare above could have been a SMI/SMI comparison. Guard against this |
| 2267 // convincing us that we have a monomorphic JSFunction. | 2150 // convincing us that we have a monomorphic JSFunction. |
| 2268 __ JumpIfSmi(edi, &extra_checks_or_miss); | 2151 __ JumpIfSmi(edi, &extra_checks_or_miss); |
| 2269 | 2152 |
| 2270 // Increment the call count for monomorphic function calls. | 2153 // Increment the call count for monomorphic function calls. |
| 2271 __ add(FieldOperand(ebx, edx, times_half_pointer_size, | 2154 __ add(FieldOperand(ebx, edx, times_half_pointer_size, |
| 2272 FixedArray::kHeaderSize + kPointerSize), | 2155 FixedArray::kHeaderSize + kPointerSize), |
| 2273 Immediate(Smi::FromInt(CallICNexus::kCallCountIncrement))); | 2156 Immediate(Smi::FromInt(CallICNexus::kCallCountIncrement))); |
| 2274 | 2157 |
| 2275 __ bind(&have_js_function); | 2158 __ bind(&call); |
| 2276 | 2159 __ Set(eax, argc); |
| 2277 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 2160 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); |
| 2278 EmitClassConstructorCallCheck(masm); | |
| 2279 | |
| 2280 if (CallAsMethod()) { | |
| 2281 EmitContinueIfStrictOrNative(masm, &cont); | |
| 2282 | |
| 2283 // Load the receiver from the stack. | |
| 2284 __ mov(eax, Operand(esp, (argc + 1) * kPointerSize)); | |
| 2285 | |
| 2286 __ JumpIfSmi(eax, &wrap); | |
| 2287 | |
| 2288 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); | |
| 2289 __ j(below, &wrap); | |
| 2290 | |
| 2291 __ bind(&cont); | |
| 2292 } | |
| 2293 | |
| 2294 __ InvokeFunction(edi, actual, JUMP_FUNCTION, NullCallWrapper()); | |
| 2295 | |
| 2296 __ bind(&slow); | |
| 2297 EmitSlowCase(isolate, masm, argc); | |
| 2298 | |
| 2299 if (CallAsMethod()) { | |
| 2300 __ bind(&wrap); | |
| 2301 EmitWrapCase(masm, argc, &cont); | |
| 2302 } | |
| 2303 | 2161 |
| 2304 __ bind(&extra_checks_or_miss); | 2162 __ bind(&extra_checks_or_miss); |
| 2305 Label uninitialized, miss, not_allocation_site; | 2163 Label uninitialized, miss, not_allocation_site; |
| 2306 | 2164 |
| 2307 __ cmp(ecx, Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate))); | 2165 __ cmp(ecx, Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate))); |
| 2308 __ j(equal, &slow_start); | 2166 __ j(equal, &call); |
| 2309 | 2167 |
| 2310 // Check if we have an allocation site. | 2168 // Check if we have an allocation site. |
| 2311 __ CompareRoot(FieldOperand(ecx, HeapObject::kMapOffset), | 2169 __ CompareRoot(FieldOperand(ecx, HeapObject::kMapOffset), |
| 2312 Heap::kAllocationSiteMapRootIndex); | 2170 Heap::kAllocationSiteMapRootIndex); |
| 2313 __ j(not_equal, ¬_allocation_site); | 2171 __ j(not_equal, ¬_allocation_site); |
| 2314 | 2172 |
| 2315 // We have an allocation site. | 2173 // We have an allocation site. |
| 2316 HandleArrayCase(masm, &miss); | 2174 HandleArrayCase(masm, &miss); |
| 2317 | 2175 |
| 2318 __ bind(¬_allocation_site); | 2176 __ bind(¬_allocation_site); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2330 // to handle it here. More complex cases are dealt with in the runtime. | 2188 // to handle it here. More complex cases are dealt with in the runtime. |
| 2331 __ AssertNotSmi(ecx); | 2189 __ AssertNotSmi(ecx); |
| 2332 __ CmpObjectType(ecx, JS_FUNCTION_TYPE, ecx); | 2190 __ CmpObjectType(ecx, JS_FUNCTION_TYPE, ecx); |
| 2333 __ j(not_equal, &miss); | 2191 __ j(not_equal, &miss); |
| 2334 __ mov( | 2192 __ mov( |
| 2335 FieldOperand(ebx, edx, times_half_pointer_size, FixedArray::kHeaderSize), | 2193 FieldOperand(ebx, edx, times_half_pointer_size, FixedArray::kHeaderSize), |
| 2336 Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate))); | 2194 Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate))); |
| 2337 // We have to update statistics for runtime profiling. | 2195 // We have to update statistics for runtime profiling. |
| 2338 __ sub(FieldOperand(ebx, with_types_offset), Immediate(Smi::FromInt(1))); | 2196 __ sub(FieldOperand(ebx, with_types_offset), Immediate(Smi::FromInt(1))); |
| 2339 __ add(FieldOperand(ebx, generic_offset), Immediate(Smi::FromInt(1))); | 2197 __ add(FieldOperand(ebx, generic_offset), Immediate(Smi::FromInt(1))); |
| 2340 __ jmp(&slow_start); | 2198 __ jmp(&call); |
| 2341 | 2199 |
| 2342 __ bind(&uninitialized); | 2200 __ bind(&uninitialized); |
| 2343 | 2201 |
| 2344 // We are going monomorphic, provided we actually have a JSFunction. | 2202 // We are going monomorphic, provided we actually have a JSFunction. |
| 2345 __ JumpIfSmi(edi, &miss); | 2203 __ JumpIfSmi(edi, &miss); |
| 2346 | 2204 |
| 2347 // Goto miss case if we do not have a function. | 2205 // Goto miss case if we do not have a function. |
| 2348 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | 2206 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); |
| 2349 __ j(not_equal, &miss); | 2207 __ j(not_equal, &miss); |
| 2350 | 2208 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2367 // edx - slot | 2225 // edx - slot |
| 2368 // edi - function | 2226 // edi - function |
| 2369 { | 2227 { |
| 2370 FrameScope scope(masm, StackFrame::INTERNAL); | 2228 FrameScope scope(masm, StackFrame::INTERNAL); |
| 2371 CreateWeakCellStub create_stub(isolate); | 2229 CreateWeakCellStub create_stub(isolate); |
| 2372 __ push(edi); | 2230 __ push(edi); |
| 2373 __ CallStub(&create_stub); | 2231 __ CallStub(&create_stub); |
| 2374 __ pop(edi); | 2232 __ pop(edi); |
| 2375 } | 2233 } |
| 2376 | 2234 |
| 2377 __ jmp(&have_js_function); | 2235 __ jmp(&call); |
| 2378 | 2236 |
| 2379 // We are here because tracing is on or we encountered a MISS case we can't | 2237 // We are here because tracing is on or we encountered a MISS case we can't |
| 2380 // handle here. | 2238 // handle here. |
| 2381 __ bind(&miss); | 2239 __ bind(&miss); |
| 2382 GenerateMiss(masm); | 2240 GenerateMiss(masm); |
| 2383 | 2241 |
| 2384 // the slow case | 2242 __ jmp(&call); |
| 2385 __ bind(&slow_start); | |
| 2386 | |
| 2387 // Check that the function really is a JavaScript function. | |
| 2388 __ JumpIfSmi(edi, &slow); | |
| 2389 | |
| 2390 // Goto slow case if we do not have a function. | |
| 2391 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | |
| 2392 __ j(not_equal, &slow); | |
| 2393 __ jmp(&have_js_function); | |
| 2394 | 2243 |
| 2395 // Unreachable | 2244 // Unreachable |
| 2396 __ int3(); | 2245 __ int3(); |
| 2397 } | 2246 } |
| 2398 | 2247 |
| 2399 | 2248 |
| 2400 void CallICStub::GenerateMiss(MacroAssembler* masm) { | 2249 void CallICStub::GenerateMiss(MacroAssembler* masm) { |
| 2401 FrameScope scope(masm, StackFrame::INTERNAL); | 2250 FrameScope scope(masm, StackFrame::INTERNAL); |
| 2402 | 2251 |
| 2403 // Push the function and feedback info. | 2252 // Push the function and feedback info. |
| (...skipping 3492 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5896 Operand(ebp, 7 * kPointerSize), NULL); | 5745 Operand(ebp, 7 * kPointerSize), NULL); |
| 5897 } | 5746 } |
| 5898 | 5747 |
| 5899 | 5748 |
| 5900 #undef __ | 5749 #undef __ |
| 5901 | 5750 |
| 5902 } // namespace internal | 5751 } // namespace internal |
| 5903 } // namespace v8 | 5752 } // namespace v8 |
| 5904 | 5753 |
| 5905 #endif // V8_TARGET_ARCH_IA32 | 5754 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |