OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
178 // ------------------------------------------- | 178 // ------------------------------------------- |
179 // Dont adapt arguments. | 179 // Dont adapt arguments. |
180 // ------------------------------------------- | 180 // ------------------------------------------- |
181 __ bind(&dont_adapt_arguments); | 181 __ bind(&dont_adapt_arguments); |
182 __ jmp(rdx); | 182 __ jmp(rdx); |
183 } | 183 } |
184 | 184 |
185 | 185 |
186 void Builtins::Generate_FunctionCall(MacroAssembler* masm) { | 186 void Builtins::Generate_FunctionCall(MacroAssembler* masm) { |
187 // Stack Layout: | 187 // Stack Layout: |
188 // rsp: return address | 188 // rsp[0]: Return address |
189 // +1: Argument n | 189 // rsp[1]: Argument n |
190 // +2: Argument n-1 | 190 // rsp[2]: Argument n-1 |
191 // ... | 191 // ... |
192 // +n: Argument 1 = receiver | 192 // rsp[n]: Argument 1 |
193 // +n+1: Argument 0 = function to call | 193 // rsp[n+1]: Receiver (function to call) |
194 // | 194 // |
195 // rax contains the number of arguments, n, not counting the function. | 195 // rax contains the number of arguments, n, not counting the receiver. |
196 // | 196 // |
197 // 1. Make sure we have at least one argument. | 197 // 1. Make sure we have at least one argument. |
198 { Label done; | 198 { Label done; |
199 __ testq(rax, rax); | 199 __ testq(rax, rax); |
200 __ j(not_zero, &done); | 200 __ j(not_zero, &done); |
201 __ pop(rbx); | 201 __ pop(rbx); |
202 __ Push(Factory::undefined_value()); | 202 __ Push(Factory::undefined_value()); |
203 __ push(rbx); | 203 __ push(rbx); |
204 __ incq(rax); | 204 __ incq(rax); |
205 __ bind(&done); | 205 __ bind(&done); |
206 } | 206 } |
207 | 207 |
208 // 2. Get the function to call from the stack. | 208 // 2. Get the function to call (passed as receiver) from the stack, check |
209 { Label done, non_function, function; | 209 // if it is a function. |
| 210 Label non_function; |
| 211 { Label function; |
210 // The function to call is at position n+1 on the stack. | 212 // The function to call is at position n+1 on the stack. |
211 __ movq(rdi, Operand(rsp, rax, times_pointer_size, +1 * kPointerSize)); | 213 __ movq(rdi, Operand(rsp, rax, times_pointer_size, 1 * kPointerSize)); |
212 __ JumpIfSmi(rdi, &non_function); | 214 __ JumpIfSmi(rdi, &non_function); |
213 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); | 215 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); |
214 __ j(equal, &function); | 216 __ j(not_equal, &non_function); |
| 217 __ bind(&function); |
| 218 } |
215 | 219 |
216 // Non-function called: Clear the function to force exception. | 220 // 3a. Patch the first argument if necessary when calling a function. |
217 __ bind(&non_function); | 221 Label shift_arguments; |
218 __ xor_(rdi, rdi); | 222 { Label convert_to_object, use_global_receiver, patch_receiver; |
219 __ jmp(&done); | 223 // Change context eagerly in case we need the global receiver. |
220 | |
221 // Function called: Change context eagerly to get the right global object. | |
222 __ bind(&function); | |
223 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); | 224 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); |
224 | 225 |
225 __ bind(&done); | |
226 } | |
227 | |
228 // 3. Make sure first argument is an object; convert if necessary. | |
229 { Label call_to_object, use_global_receiver, patch_receiver, done; | |
230 __ movq(rbx, Operand(rsp, rax, times_pointer_size, 0)); | 226 __ movq(rbx, Operand(rsp, rax, times_pointer_size, 0)); |
231 | 227 __ JumpIfSmi(rbx, &convert_to_object); |
232 __ JumpIfSmi(rbx, &call_to_object); | |
233 | 228 |
234 __ CompareRoot(rbx, Heap::kNullValueRootIndex); | 229 __ CompareRoot(rbx, Heap::kNullValueRootIndex); |
235 __ j(equal, &use_global_receiver); | 230 __ j(equal, &use_global_receiver); |
236 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex); | 231 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex); |
237 __ j(equal, &use_global_receiver); | 232 __ j(equal, &use_global_receiver); |
238 | 233 |
239 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, rcx); | 234 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, rcx); |
240 __ j(below, &call_to_object); | 235 __ j(below, &convert_to_object); |
241 __ CmpInstanceType(rcx, LAST_JS_OBJECT_TYPE); | 236 __ CmpInstanceType(rcx, LAST_JS_OBJECT_TYPE); |
242 __ j(below_equal, &done); | 237 __ j(below_equal, &shift_arguments); |
243 | 238 |
244 __ bind(&call_to_object); | 239 __ bind(&convert_to_object); |
245 __ EnterInternalFrame(); // preserves rax, rbx, rdi | 240 __ EnterInternalFrame(); // In order to preserve argument count. |
246 | |
247 // Store the arguments count on the stack (smi tagged). | |
248 __ Integer32ToSmi(rax, rax); | 241 __ Integer32ToSmi(rax, rax); |
249 __ push(rax); | 242 __ push(rax); |
250 | 243 |
251 __ push(rdi); // save edi across the call | |
252 __ push(rbx); | 244 __ push(rbx); |
253 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | 245 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
254 __ movq(rbx, rax); | 246 __ movq(rbx, rax); |
255 __ pop(rdi); // restore edi after the call | |
256 | 247 |
257 // Get the arguments count and untag it. | |
258 __ pop(rax); | 248 __ pop(rax); |
259 __ SmiToInteger32(rax, rax); | 249 __ SmiToInteger32(rax, rax); |
260 | |
261 __ LeaveInternalFrame(); | 250 __ LeaveInternalFrame(); |
| 251 // Restore the function to rdi. |
| 252 __ movq(rdi, Operand(rsp, rax, times_pointer_size, 1 * kPointerSize)); |
262 __ jmp(&patch_receiver); | 253 __ jmp(&patch_receiver); |
263 | 254 |
264 // Use the global receiver object from the called function as the receiver. | 255 // Use the global receiver object from the called function as the |
| 256 // receiver. |
265 __ bind(&use_global_receiver); | 257 __ bind(&use_global_receiver); |
266 const int kGlobalIndex = | 258 const int kGlobalIndex = |
267 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; | 259 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; |
268 __ movq(rbx, FieldOperand(rsi, kGlobalIndex)); | 260 __ movq(rbx, FieldOperand(rsi, kGlobalIndex)); |
269 __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalContextOffset)); | 261 __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalContextOffset)); |
270 __ movq(rbx, FieldOperand(rbx, kGlobalIndex)); | 262 __ movq(rbx, FieldOperand(rbx, kGlobalIndex)); |
271 __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); | 263 __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); |
272 | 264 |
273 __ bind(&patch_receiver); | 265 __ bind(&patch_receiver); |
274 __ movq(Operand(rsp, rax, times_pointer_size, 0), rbx); | 266 __ movq(Operand(rsp, rax, times_pointer_size, 0), rbx); |
275 | 267 |
276 __ bind(&done); | 268 __ jmp(&shift_arguments); |
277 } | 269 } |
278 | 270 |
279 // 4. Check that the function really is a function. | |
280 { Label real_function; | |
281 __ testq(rdi, rdi); | |
282 __ j(not_zero, &real_function); | |
283 __ xor_(rbx, rbx); | |
284 // CALL_NON_FUNCTION will expect to find the non-function callee on the | |
285 // expression stack of the caller. Transfer it from receiver to the | |
286 // caller's expression stack (and make the first argument the receiver | |
287 // for CALL_NON_FUNCTION) by decrementing the argument count. | |
288 __ decq(rax); | |
289 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION); | |
290 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), | |
291 RelocInfo::CODE_TARGET); | |
292 | 271 |
293 __ bind(&real_function); | 272 // 3b. Patch the first argument when calling a non-function. The |
294 } | 273 // CALL_NON_FUNCTION builtin expects the non-function callee as |
| 274 // receiver, so overwrite the first argument which will ultimately |
| 275 // become the receiver. |
| 276 __ bind(&non_function); |
| 277 __ movq(Operand(rsp, rax, times_pointer_size, 0), rdi); |
| 278 __ xor_(rdi, rdi); |
295 | 279 |
296 // 5. Shift arguments and return address one slot down on the stack | 280 // 4. Shift arguments and return address one slot down on the stack |
297 // (overwriting the receiver). | 281 // (overwriting the original receiver). Adjust argument count to make |
| 282 // the original first argument the new receiver. |
| 283 __ bind(&shift_arguments); |
298 { Label loop; | 284 { Label loop; |
299 __ movq(rcx, rax); | 285 __ movq(rcx, rax); |
300 __ bind(&loop); | 286 __ bind(&loop); |
301 __ movq(rbx, Operand(rsp, rcx, times_pointer_size, 0)); | 287 __ movq(rbx, Operand(rsp, rcx, times_pointer_size, 0)); |
302 __ movq(Operand(rsp, rcx, times_pointer_size, 1 * kPointerSize), rbx); | 288 __ movq(Operand(rsp, rcx, times_pointer_size, 1 * kPointerSize), rbx); |
303 __ decq(rcx); | 289 __ decq(rcx); |
304 __ j(not_sign, &loop); | 290 __ j(not_sign, &loop); // While non-negative (to copy return address). |
305 __ pop(rbx); // Discard copy of return address. | 291 __ pop(rbx); // Discard copy of return address. |
306 __ decq(rax); // One fewer argument (first argument is new receiver). | 292 __ decq(rax); // One fewer argument (first argument is new receiver). |
307 } | 293 } |
308 | 294 |
309 // 6. Get the code to call from the function and check that the number of | 295 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin. |
310 // expected arguments matches what we're providing. | 296 { Label function; |
| 297 __ testq(rdi, rdi); |
| 298 __ j(not_zero, &function); |
| 299 __ xor_(rbx, rbx); |
| 300 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION); |
| 301 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), |
| 302 RelocInfo::CODE_TARGET); |
| 303 __ bind(&function); |
| 304 } |
| 305 |
| 306 // 5b. Get the code to call from the function and check that the number of |
| 307 // expected arguments matches what we're providing. If so, jump |
| 308 // (tail-call) to the code in register edx without checking arguments. |
311 __ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); | 309 __ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); |
312 __ movsxlq(rbx, | 310 __ movsxlq(rbx, |
313 FieldOperand(rdx, SharedFunctionInfo::kFormalParameterCountOffset)); | 311 FieldOperand(rdx, SharedFunctionInfo::kFormalParameterCountOffset)); |
314 __ movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kCodeOffset)); | 312 __ movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kCodeOffset)); |
315 __ lea(rdx, FieldOperand(rdx, Code::kHeaderSize)); | 313 __ lea(rdx, FieldOperand(rdx, Code::kHeaderSize)); |
316 __ cmpq(rax, rbx); | 314 __ cmpq(rax, rbx); |
317 __ j(not_equal, | 315 __ j(not_equal, |
318 Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), | 316 Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), |
319 RelocInfo::CODE_TARGET); | 317 RelocInfo::CODE_TARGET); |
320 | 318 |
321 // 7. Jump (tail-call) to the code in register edx without checking arguments. | |
322 ParameterCount expected(0); | 319 ParameterCount expected(0); |
323 __ InvokeCode(rdx, expected, expected, JUMP_FUNCTION); | 320 __ InvokeCode(rdx, expected, expected, JUMP_FUNCTION); |
324 } | 321 } |
325 | 322 |
326 | 323 |
327 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { | 324 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { |
328 // Stack at entry: | 325 // Stack at entry: |
329 // rsp: return address | 326 // rsp: return address |
330 // rsp+8: arguments | 327 // rsp+8: arguments |
331 // rsp+16: receiver ("this") | 328 // rsp+16: receiver ("this") |
(...skipping 566 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
898 | 895 |
899 // Jump to the function-specific construct stub. | 896 // Jump to the function-specific construct stub. |
900 __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); | 897 __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); |
901 __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kConstructStubOffset)); | 898 __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kConstructStubOffset)); |
902 __ lea(rbx, FieldOperand(rbx, Code::kHeaderSize)); | 899 __ lea(rbx, FieldOperand(rbx, Code::kHeaderSize)); |
903 __ jmp(rbx); | 900 __ jmp(rbx); |
904 | 901 |
905 // edi: called object | 902 // edi: called object |
906 // eax: number of arguments | 903 // eax: number of arguments |
907 __ bind(&non_function_call); | 904 __ bind(&non_function_call); |
908 // Set expected number of arguments to zero (not changing eax). | 905 // CALL_NON_FUNCTION expects the non-function constructor as receiver |
| 906 // (instead of the original receiver from the call site). The receiver is |
| 907 // stack element argc+1. |
| 908 __ movq(Operand(rsp, rax, times_pointer_size, kPointerSize), rdi); |
| 909 // Set expected number of arguments to zero (not changing rax). |
909 __ movq(rbx, Immediate(0)); | 910 __ movq(rbx, Immediate(0)); |
910 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); | 911 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); |
911 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), | 912 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), |
912 RelocInfo::CODE_TARGET); | 913 RelocInfo::CODE_TARGET); |
913 } | 914 } |
914 | 915 |
915 | 916 |
916 static void Generate_JSConstructStubHelper(MacroAssembler* masm, | 917 static void Generate_JSConstructStubHelper(MacroAssembler* masm, |
917 bool is_api_function) { | 918 bool is_api_function) { |
918 // Enter a construct frame. | 919 // Enter a construct frame. |
(...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1291 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { | 1292 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { |
1292 Generate_JSEntryTrampolineHelper(masm, false); | 1293 Generate_JSEntryTrampolineHelper(masm, false); |
1293 } | 1294 } |
1294 | 1295 |
1295 | 1296 |
1296 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { | 1297 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { |
1297 Generate_JSEntryTrampolineHelper(masm, true); | 1298 Generate_JSEntryTrampolineHelper(masm, true); |
1298 } | 1299 } |
1299 | 1300 |
1300 } } // namespace v8::internal | 1301 } } // namespace v8::internal |
OLD | NEW |