OLD | NEW |
| (Empty) |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | |
2 // Redistribution and use in source and binary forms, with or without | |
3 // modification, are permitted provided that the following conditions are | |
4 // met: | |
5 // | |
6 // * Redistributions of source code must retain the above copyright | |
7 // notice, this list of conditions and the following disclaimer. | |
8 // * Redistributions in binary form must reproduce the above | |
9 // copyright notice, this list of conditions and the following | |
10 // disclaimer in the documentation and/or other materials provided | |
11 // with the distribution. | |
12 // * Neither the name of Google Inc. nor the names of its | |
13 // contributors may be used to endorse or promote products derived | |
14 // from this software without specific prior written permission. | |
15 // | |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | |
28 #include "v8.h" | |
29 | |
30 #include "codegen-inl.h" | |
31 #include "debug.h" | |
32 #include "runtime.h" | |
33 | |
34 namespace v8 { namespace internal { | |
35 | |
36 | |
37 #define __ ACCESS_MASM(masm) | |
38 | |
39 | |
40 void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) { | |
41 // TODO(1238487): Don't pass the function in a static variable. | |
42 __ mov(ip, Operand(ExternalReference::builtin_passed_function())); | |
43 __ str(r1, MemOperand(ip, 0)); | |
44 | |
45 // The actual argument count has already been loaded into register | |
46 // r0, but JumpToBuiltin expects r0 to contain the number of | |
47 // arguments including the receiver. | |
48 __ add(r0, r0, Operand(1)); | |
49 __ JumpToBuiltin(ExternalReference(id)); | |
50 } | |
51 | |
52 | |
53 void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { | |
54 // ----------- S t a t e ------------- | |
55 // -- r0 : number of arguments | |
56 // -- r1 : constructor function | |
57 // -- lr : return address | |
58 // -- sp[...]: constructor arguments | |
59 // ----------------------------------- | |
60 | |
61 // Enter a construct frame. | |
62 __ EnterConstructFrame(); | |
63 | |
64 // Preserve the two incoming parameters | |
65 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); | |
66 __ push(r0); // smi-tagged arguments count | |
67 __ push(r1); // constructor function | |
68 | |
69 // Allocate the new receiver object. | |
70 __ push(r1); // argument for Runtime_NewObject | |
71 __ CallRuntime(Runtime::kNewObject, 1); | |
72 __ push(r0); // save the receiver | |
73 | |
74 // Push the function and the allocated receiver from the stack. | |
75 // sp[0]: receiver (newly allocated object) | |
76 // sp[1]: constructor function | |
77 // sp[2]: number of arguments (smi-tagged) | |
78 __ ldr(r1, MemOperand(sp, kPointerSize)); | |
79 __ push(r1); // function | |
80 __ push(r0); // receiver | |
81 | |
82 // Reload the number of arguments from the stack. | |
83 // r1: constructor function | |
84 // sp[0]: receiver | |
85 // sp[1]: constructor function | |
86 // sp[2]: receiver | |
87 // sp[3]: constructor function | |
88 // sp[4]: number of arguments (smi-tagged) | |
89 __ ldr(r3, MemOperand(sp, 4 * kPointerSize)); | |
90 | |
91 // Setup pointer to last argument. | |
92 __ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset)); | |
93 | |
94 // Setup number of arguments for function call below | |
95 __ mov(r0, Operand(r3, LSR, kSmiTagSize)); | |
96 | |
97 // Copy arguments and receiver to the expression stack. | |
98 // r0: number of arguments | |
99 // r2: address of last argument (caller sp) | |
100 // r1: constructor function | |
101 // r3: number of arguments (smi-tagged) | |
102 // sp[0]: receiver | |
103 // sp[1]: constructor function | |
104 // sp[2]: receiver | |
105 // sp[3]: constructor function | |
106 // sp[4]: number of arguments (smi-tagged) | |
107 Label loop, entry; | |
108 __ b(&entry); | |
109 __ bind(&loop); | |
110 __ ldr(ip, MemOperand(r2, r3, LSL, kPointerSizeLog2 - 1)); | |
111 __ push(ip); | |
112 __ bind(&entry); | |
113 __ sub(r3, r3, Operand(2), SetCC); | |
114 __ b(ge, &loop); | |
115 | |
116 // Call the function. | |
117 // r0: number of arguments | |
118 // r1: constructor function | |
119 ParameterCount actual(r0); | |
120 __ InvokeFunction(r1, actual, CALL_FUNCTION); | |
121 | |
122 // Pop the function from the stack. | |
123 // sp[0]: constructor function | |
124 // sp[2]: receiver | |
125 // sp[3]: constructor function | |
126 // sp[4]: number of arguments (smi-tagged) | |
127 __ pop(); | |
128 | |
129 // Restore context from the frame. | |
130 // r0: result | |
131 // sp[0]: receiver | |
132 // sp[1]: constructor function | |
133 // sp[2]: number of arguments (smi-tagged) | |
134 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | |
135 | |
136 // If the result is an object (in the ECMA sense), we should get rid | |
137 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 | |
138 // on page 74. | |
139 Label use_receiver, exit; | |
140 | |
141 // If the result is a smi, it is *not* an object in the ECMA sense. | |
142 // r0: result | |
143 // sp[0]: receiver (newly allocated object) | |
144 // sp[1]: constructor function | |
145 // sp[2]: number of arguments (smi-tagged) | |
146 __ tst(r0, Operand(kSmiTagMask)); | |
147 __ b(eq, &use_receiver); | |
148 | |
149 // If the type of the result (stored in its map) is less than | |
150 // FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense. | |
151 __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset)); | |
152 __ ldrb(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset)); | |
153 __ cmp(r3, Operand(FIRST_JS_OBJECT_TYPE)); | |
154 __ b(ge, &exit); | |
155 | |
156 // Throw away the result of the constructor invocation and use the | |
157 // on-stack receiver as the result. | |
158 __ bind(&use_receiver); | |
159 __ ldr(r0, MemOperand(sp)); | |
160 | |
161 // Remove receiver from the stack, remove caller arguments, and | |
162 // return. | |
163 __ bind(&exit); | |
164 // r0: result | |
165 // sp[0]: receiver (newly allocated object) | |
166 // sp[1]: constructor function | |
167 // sp[2]: number of arguments (smi-tagged) | |
168 __ ldr(r1, MemOperand(sp, 2 * kPointerSize)); | |
169 __ LeaveConstructFrame(); | |
170 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1)); | |
171 __ add(sp, sp, Operand(kPointerSize)); | |
172 __ mov(pc, Operand(lr)); | |
173 } | |
174 | |
175 | |
176 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, | |
177 bool is_construct) { | |
178 // Called from Generate_JS_Entry | |
179 // r0: code entry | |
180 // r1: function | |
181 // r2: receiver | |
182 // r3: argc | |
183 // r4: argv | |
184 // r5-r7, cp may be clobbered | |
185 | |
186 // Clear the context before we push it when entering the JS frame. | |
187 __ mov(cp, Operand(0)); | |
188 | |
189 // Enter an internal frame. | |
190 __ EnterInternalFrame(); | |
191 | |
192 // Setup the context from the function argument. | |
193 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); | |
194 | |
195 // Push the function and the receiver onto the stack. | |
196 __ push(r1); | |
197 __ push(r2); | |
198 | |
199 // Copy arguments to the stack in a loop. | |
200 // r1: function | |
201 // r3: argc | |
202 // r4: argv, i.e. points to first arg | |
203 Label loop, entry; | |
204 __ add(r2, r4, Operand(r3, LSL, kPointerSizeLog2)); | |
205 // r2 points past last arg. | |
206 __ b(&entry); | |
207 __ bind(&loop); | |
208 __ ldr(r0, MemOperand(r4, kPointerSize, PostIndex)); // read next parameter | |
209 __ ldr(r0, MemOperand(r0)); // dereference handle | |
210 __ push(r0); // push parameter | |
211 __ bind(&entry); | |
212 __ cmp(r4, Operand(r2)); | |
213 __ b(ne, &loop); | |
214 | |
215 // Initialize all JavaScript callee-saved registers, since they will be seen | |
216 // by the garbage collector as part of handlers. | |
217 __ mov(r4, Operand(Factory::undefined_value())); | |
218 __ mov(r5, Operand(r4)); | |
219 __ mov(r6, Operand(r4)); | |
220 __ mov(r7, Operand(r4)); | |
221 if (kR9Available == 1) { | |
222 __ mov(r9, Operand(r4)); | |
223 } | |
224 | |
225 // Invoke the code and pass argc as r0. | |
226 __ mov(r0, Operand(r3)); | |
227 if (is_construct) { | |
228 __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), | |
229 RelocInfo::CODE_TARGET); | |
230 } else { | |
231 ParameterCount actual(r0); | |
232 __ InvokeFunction(r1, actual, CALL_FUNCTION); | |
233 } | |
234 | |
235 // Exit the JS frame and remove the parameters (except function), and return. | |
236 // Respect ABI stack constraint. | |
237 __ LeaveInternalFrame(); | |
238 __ mov(pc, lr); | |
239 | |
240 // r0: result | |
241 } | |
242 | |
243 | |
244 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { | |
245 Generate_JSEntryTrampolineHelper(masm, false); | |
246 } | |
247 | |
248 | |
249 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { | |
250 Generate_JSEntryTrampolineHelper(masm, true); | |
251 } | |
252 | |
253 | |
254 void Builtins::Generate_FunctionCall(MacroAssembler* masm) { | |
255 // 1. Make sure we have at least one argument. | |
256 // r0: actual number of argument | |
257 { Label done; | |
258 __ tst(r0, Operand(r0)); | |
259 __ b(ne, &done); | |
260 __ mov(r2, Operand(Factory::undefined_value())); | |
261 __ push(r2); | |
262 __ add(r0, r0, Operand(1)); | |
263 __ bind(&done); | |
264 } | |
265 | |
266 // 2. Get the function to call from the stack. | |
267 // r0: actual number of argument | |
268 { Label done, non_function, function; | |
269 __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); | |
270 __ tst(r1, Operand(kSmiTagMask)); | |
271 __ b(eq, &non_function); | |
272 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); | |
273 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); | |
274 __ cmp(r2, Operand(JS_FUNCTION_TYPE)); | |
275 __ b(eq, &function); | |
276 | |
277 // Non-function called: Clear the function to force exception. | |
278 __ bind(&non_function); | |
279 __ mov(r1, Operand(0)); | |
280 __ b(&done); | |
281 | |
282 // Change the context eagerly because it will be used below to get the | |
283 // right global object. | |
284 __ bind(&function); | |
285 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); | |
286 | |
287 __ bind(&done); | |
288 } | |
289 | |
290 // 3. Make sure first argument is an object; convert if necessary. | |
291 // r0: actual number of arguments | |
292 // r1: function | |
293 { Label call_to_object, use_global_receiver, patch_receiver, done; | |
294 __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2)); | |
295 __ ldr(r2, MemOperand(r2, -kPointerSize)); | |
296 | |
297 // r0: actual number of arguments | |
298 // r1: function | |
299 // r2: first argument | |
300 __ tst(r2, Operand(kSmiTagMask)); | |
301 __ b(eq, &call_to_object); | |
302 | |
303 __ mov(r3, Operand(Factory::null_value())); | |
304 __ cmp(r2, r3); | |
305 __ b(eq, &use_global_receiver); | |
306 __ mov(r3, Operand(Factory::undefined_value())); | |
307 __ cmp(r2, r3); | |
308 __ b(eq, &use_global_receiver); | |
309 | |
310 __ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset)); | |
311 __ ldrb(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset)); | |
312 __ cmp(r3, Operand(FIRST_JS_OBJECT_TYPE)); | |
313 __ b(lt, &call_to_object); | |
314 __ cmp(r3, Operand(LAST_JS_OBJECT_TYPE)); | |
315 __ b(le, &done); | |
316 | |
317 __ bind(&call_to_object); | |
318 __ EnterInternalFrame(); | |
319 | |
320 // Store number of arguments and function across the call into the runtime. | |
321 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); | |
322 __ push(r0); | |
323 __ push(r1); | |
324 | |
325 __ push(r2); | |
326 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS); | |
327 __ mov(r2, r0); | |
328 | |
329 // Restore number of arguments and function. | |
330 __ pop(r1); | |
331 __ pop(r0); | |
332 __ mov(r0, Operand(r0, ASR, kSmiTagSize)); | |
333 | |
334 __ LeaveInternalFrame(); | |
335 __ b(&patch_receiver); | |
336 | |
337 // Use the global receiver object from the called function as the receiver. | |
338 __ bind(&use_global_receiver); | |
339 const int kGlobalIndex = | |
340 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; | |
341 __ ldr(r2, FieldMemOperand(cp, kGlobalIndex)); | |
342 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset)); | |
343 | |
344 __ bind(&patch_receiver); | |
345 __ add(r3, sp, Operand(r0, LSL, kPointerSizeLog2)); | |
346 __ str(r2, MemOperand(r3, -kPointerSize)); | |
347 | |
348 __ bind(&done); | |
349 } | |
350 | |
351 // 4. Shift stuff one slot down the stack | |
352 // r0: actual number of arguments (including call() receiver) | |
353 // r1: function | |
354 { Label loop; | |
355 // Calculate the copy start address (destination). Copy end address is sp. | |
356 __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2)); | |
357 __ add(r2, r2, Operand(kPointerSize)); // copy receiver too | |
358 | |
359 __ bind(&loop); | |
360 __ ldr(ip, MemOperand(r2, -kPointerSize)); | |
361 __ str(ip, MemOperand(r2)); | |
362 __ sub(r2, r2, Operand(kPointerSize)); | |
363 __ cmp(r2, sp); | |
364 __ b(ne, &loop); | |
365 } | |
366 | |
367 // 5. Adjust the actual number of arguments and remove the top element. | |
368 // r0: actual number of arguments (including call() receiver) | |
369 // r1: function | |
370 __ sub(r0, r0, Operand(1)); | |
371 __ add(sp, sp, Operand(kPointerSize)); | |
372 | |
373 // 6. Get the code for the function or the non-function builtin. | |
374 // If number of expected arguments matches, then call. Otherwise restart | |
375 // the arguments adaptor stub. | |
376 // r0: actual number of arguments | |
377 // r1: function | |
378 { Label invoke; | |
379 __ tst(r1, r1); | |
380 __ b(ne, &invoke); | |
381 __ mov(r2, Operand(0)); // expected arguments is 0 for CALL_NON_FUNCTION | |
382 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); | |
383 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), | |
384 RelocInfo::CODE_TARGET); | |
385 | |
386 __ bind(&invoke); | |
387 __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); | |
388 __ ldr(r2, | |
389 FieldMemOperand(r3, | |
390 SharedFunctionInfo::kFormalParameterCountOffset)); | |
391 __ ldr(r3, | |
392 MemOperand(r3, SharedFunctionInfo::kCodeOffset - kHeapObjectTag)); | |
393 __ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag)); | |
394 __ cmp(r2, r0); // Check formal and actual parameter counts. | |
395 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), | |
396 RelocInfo::CODE_TARGET, ne); | |
397 | |
398 // 7. Jump to the code in r3 without checking arguments. | |
399 ParameterCount expected(0); | |
400 __ InvokeCode(r3, expected, expected, JUMP_FUNCTION); | |
401 } | |
402 } | |
403 | |
404 | |
405 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { | |
406 const int kIndexOffset = -5 * kPointerSize; | |
407 const int kLimitOffset = -4 * kPointerSize; | |
408 const int kArgsOffset = 2 * kPointerSize; | |
409 const int kRecvOffset = 3 * kPointerSize; | |
410 const int kFunctionOffset = 4 * kPointerSize; | |
411 | |
412 __ EnterInternalFrame(); | |
413 | |
414 __ ldr(r0, MemOperand(fp, kFunctionOffset)); // get the function | |
415 __ push(r0); | |
416 __ ldr(r0, MemOperand(fp, kArgsOffset)); // get the args array | |
417 __ push(r0); | |
418 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_JS); | |
419 | |
420 // Eagerly check for stack-overflow before starting to push the arguments. | |
421 // r0: number of arguments | |
422 Label okay; | |
423 ExternalReference stack_guard_limit_address = | |
424 ExternalReference::address_of_stack_guard_limit(); | |
425 __ mov(r2, Operand(stack_guard_limit_address)); | |
426 __ ldr(r2, MemOperand(r2)); | |
427 __ sub(r2, sp, r2); | |
428 __ sub(r2, r2, Operand(3 * kPointerSize)); // limit, index, receiver | |
429 | |
430 __ cmp(r2, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); | |
431 __ b(hi, &okay); | |
432 | |
433 // Out of stack space. | |
434 __ ldr(r1, MemOperand(fp, kFunctionOffset)); | |
435 __ push(r1); | |
436 __ push(r0); | |
437 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_JS); | |
438 | |
439 // Push current limit and index. | |
440 __ bind(&okay); | |
441 __ push(r0); // limit | |
442 __ mov(r1, Operand(0)); // initial index | |
443 __ push(r1); | |
444 | |
445 // Change context eagerly to get the right global object if necessary. | |
446 __ ldr(r0, MemOperand(fp, kFunctionOffset)); | |
447 __ ldr(cp, FieldMemOperand(r0, JSFunction::kContextOffset)); | |
448 | |
449 // Compute the receiver. | |
450 Label call_to_object, use_global_receiver, push_receiver; | |
451 __ ldr(r0, MemOperand(fp, kRecvOffset)); | |
452 __ tst(r0, Operand(kSmiTagMask)); | |
453 __ b(eq, &call_to_object); | |
454 __ mov(r1, Operand(Factory::null_value())); | |
455 __ cmp(r0, r1); | |
456 __ b(eq, &use_global_receiver); | |
457 __ mov(r1, Operand(Factory::undefined_value())); | |
458 __ cmp(r0, r1); | |
459 __ b(eq, &use_global_receiver); | |
460 | |
461 // Check if the receiver is already a JavaScript object. | |
462 // r0: receiver | |
463 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); | |
464 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); | |
465 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE)); | |
466 __ b(lt, &call_to_object); | |
467 __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE)); | |
468 __ b(le, &push_receiver); | |
469 | |
470 // Convert the receiver to a regular object. | |
471 // r0: receiver | |
472 __ bind(&call_to_object); | |
473 __ push(r0); | |
474 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS); | |
475 __ b(&push_receiver); | |
476 | |
477 // Use the current global receiver object as the receiver. | |
478 __ bind(&use_global_receiver); | |
479 const int kGlobalOffset = | |
480 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; | |
481 __ ldr(r0, FieldMemOperand(cp, kGlobalOffset)); | |
482 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset)); | |
483 | |
484 // Push the receiver. | |
485 // r0: receiver | |
486 __ bind(&push_receiver); | |
487 __ push(r0); | |
488 | |
489 // Copy all arguments from the array to the stack. | |
490 Label entry, loop; | |
491 __ ldr(r0, MemOperand(fp, kIndexOffset)); | |
492 __ b(&entry); | |
493 | |
494 // Load the current argument from the arguments array and push it to the | |
495 // stack. | |
496 // r0: current argument index | |
497 __ bind(&loop); | |
498 __ ldr(r1, MemOperand(fp, kArgsOffset)); | |
499 __ push(r1); | |
500 __ push(r0); | |
501 | |
502 // Call the runtime to access the property in the arguments array. | |
503 __ CallRuntime(Runtime::kGetProperty, 2); | |
504 __ push(r0); | |
505 | |
506 // Use inline caching to access the arguments. | |
507 __ ldr(r0, MemOperand(fp, kIndexOffset)); | |
508 __ add(r0, r0, Operand(1 << kSmiTagSize)); | |
509 __ str(r0, MemOperand(fp, kIndexOffset)); | |
510 | |
511 // Test if the copy loop has finished copying all the elements from the | |
512 // arguments object. | |
513 __ bind(&entry); | |
514 __ ldr(r1, MemOperand(fp, kLimitOffset)); | |
515 __ cmp(r0, r1); | |
516 __ b(ne, &loop); | |
517 | |
518 // Invoke the function. | |
519 ParameterCount actual(r0); | |
520 __ mov(r0, Operand(r0, ASR, kSmiTagSize)); | |
521 __ ldr(r1, MemOperand(fp, kFunctionOffset)); | |
522 __ InvokeFunction(r1, actual, CALL_FUNCTION); | |
523 | |
524 // Tear down the internal frame and remove function, receiver and args. | |
525 __ LeaveInternalFrame(); | |
526 __ add(sp, sp, Operand(3 * kPointerSize)); | |
527 __ mov(pc, lr); | |
528 } | |
529 | |
530 | |
531 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { | |
532 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); | |
533 __ mov(r4, Operand(ArgumentsAdaptorFrame::SENTINEL)); | |
534 __ stm(db_w, sp, r0.bit() | r1.bit() | r4.bit() | fp.bit() | lr.bit()); | |
535 __ add(fp, sp, Operand(3 * kPointerSize)); | |
536 } | |
537 | |
538 | |
539 static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { | |
540 // ----------- S t a t e ------------- | |
541 // -- r0 : result being passed through | |
542 // ----------------------------------- | |
543 // Get the number of arguments passed (as a smi), tear down the frame and | |
544 // then tear down the parameters. | |
545 __ ldr(r1, MemOperand(fp, -3 * kPointerSize)); | |
546 __ mov(sp, fp); | |
547 __ ldm(ia_w, sp, fp.bit() | lr.bit()); | |
548 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); | |
549 __ add(sp, sp, Operand(kPointerSize)); // adjust for receiver | |
550 } | |
551 | |
552 | |
553 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { | |
554 // ----------- S t a t e ------------- | |
555 // -- r0 : actual number of arguments | |
556 // -- r1 : function (passed through to callee) | |
557 // -- r2 : expected number of arguments | |
558 // -- r3 : code entry to call | |
559 // ----------------------------------- | |
560 | |
561 Label invoke, dont_adapt_arguments; | |
562 | |
563 Label enough, too_few; | |
564 __ cmp(r0, Operand(r2)); | |
565 __ b(lt, &too_few); | |
566 __ cmp(r2, Operand(SharedFunctionInfo::kDontAdaptArgumentsSentinel)); | |
567 __ b(eq, &dont_adapt_arguments); | |
568 | |
569 { // Enough parameters: actual >= expected | |
570 __ bind(&enough); | |
571 EnterArgumentsAdaptorFrame(masm); | |
572 | |
573 // Calculate copy start address into r0 and copy end address into r2. | |
574 // r0: actual number of arguments as a smi | |
575 // r1: function | |
576 // r2: expected number of arguments | |
577 // r3: code entry to call | |
578 __ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); | |
579 // adjust for return address and receiver | |
580 __ add(r0, r0, Operand(2 * kPointerSize)); | |
581 __ sub(r2, r0, Operand(r2, LSL, kPointerSizeLog2)); | |
582 | |
583 // Copy the arguments (including the receiver) to the new stack frame. | |
584 // r0: copy start address | |
585 // r1: function | |
586 // r2: copy end address | |
587 // r3: code entry to call | |
588 | |
589 Label copy; | |
590 __ bind(©); | |
591 __ ldr(ip, MemOperand(r0, 0)); | |
592 __ push(ip); | |
593 __ cmp(r0, r2); // Compare before moving to next argument. | |
594 __ sub(r0, r0, Operand(kPointerSize)); | |
595 __ b(ne, ©); | |
596 | |
597 __ b(&invoke); | |
598 } | |
599 | |
600 { // Too few parameters: Actual < expected | |
601 __ bind(&too_few); | |
602 EnterArgumentsAdaptorFrame(masm); | |
603 | |
604 // Calculate copy start address into r0 and copy end address is fp. | |
605 // r0: actual number of arguments as a smi | |
606 // r1: function | |
607 // r2: expected number of arguments | |
608 // r3: code entry to call | |
609 __ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); | |
610 | |
611 // Copy the arguments (including the receiver) to the new stack frame. | |
612 // r0: copy start address | |
613 // r1: function | |
614 // r2: expected number of arguments | |
615 // r3: code entry to call | |
616 Label copy; | |
617 __ bind(©); | |
618 // Adjust load for return address and receiver. | |
619 __ ldr(ip, MemOperand(r0, 2 * kPointerSize)); | |
620 __ push(ip); | |
621 __ cmp(r0, fp); // Compare before moving to next argument. | |
622 __ sub(r0, r0, Operand(kPointerSize)); | |
623 __ b(ne, ©); | |
624 | |
625 // Fill the remaining expected arguments with undefined. | |
626 // r1: function | |
627 // r2: expected number of arguments | |
628 // r3: code entry to call | |
629 __ mov(ip, Operand(Factory::undefined_value())); | |
630 __ sub(r2, fp, Operand(r2, LSL, kPointerSizeLog2)); | |
631 __ sub(r2, r2, Operand(4 * kPointerSize)); // Adjust for frame. | |
632 | |
633 Label fill; | |
634 __ bind(&fill); | |
635 __ push(ip); | |
636 __ cmp(sp, r2); | |
637 __ b(ne, &fill); | |
638 } | |
639 | |
640 // Call the entry point. | |
641 __ bind(&invoke); | |
642 __ Call(r3); | |
643 | |
644 // Exit frame and return. | |
645 LeaveArgumentsAdaptorFrame(masm); | |
646 __ mov(pc, lr); | |
647 | |
648 | |
649 // ------------------------------------------- | |
650 // Dont adapt arguments. | |
651 // ------------------------------------------- | |
652 __ bind(&dont_adapt_arguments); | |
653 __ mov(pc, r3); | |
654 } | |
655 | |
656 | |
657 #undef __ | |
658 | |
659 } } // namespace v8::internal | |
OLD | NEW |