blob: 519c04a2cf0a8e5256f29d09f3055b09b0235abf [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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
34namespace v8 { namespace internal {
35
36
ager@chromium.org65dad4b2009-04-23 08:48:43 +000037#define __ ACCESS_MASM(masm)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038
39
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000040void 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.
mads.s.ager31e71382008-08-13 09:32:07 +000048 __ add(r0, r0, Operand(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049 __ JumpToBuiltin(ExternalReference(id));
50}
51
52
53void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000054 // ----------- S t a t e -------------
55 // -- r0 : number of arguments
56 // -- r1 : constructor function
57 // -- lr : return address
58 // -- sp[...]: constructor arguments
59 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060
ager@chromium.org7c537e22008-10-16 08:43:32 +000061 // Enter a construct frame.
62 __ EnterConstructFrame();
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000063
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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
69 // Allocate the new receiver object.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000070 __ push(r1); // argument for Runtime_NewObject
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000071 __ CallRuntime(Runtime::kNewObject, 1);
mads.s.ager31e71382008-08-13 09:32:07 +000072 __ push(r0); // save the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073
74 // Push the function and the allocated receiver from the stack.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000075 // 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));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000079 __ push(r1); // function
80 __ push(r0); // receiver
81
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000082 // 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));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000090
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000091 // 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));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096
97 // Copy arguments and receiver to the expression stack.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000098 // 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)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000107 Label loop, entry;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108 __ b(&entry);
109 __ bind(&loop);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000110 __ ldr(ip, MemOperand(r2, r3, LSL, kPointerSizeLog2 - 1));
111 __ push(ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000112 __ bind(&entry);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000113 __ sub(r3, r3, Operand(2), SetCC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000114 __ b(ge, &loop);
115
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000116 // Call the function.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000117 // r0: number of arguments
118 // r1: constructor function
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000119 ParameterCount actual(r0);
120 __ InvokeFunction(r1, actual, CALL_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000121
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000122 // 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)
mads.s.ager31e71382008-08-13 09:32:07 +0000127 __ pop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000128
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000129 // 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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000136 // 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.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000142 // r0: result
143 // sp[0]: receiver (newly allocated object)
144 // sp[1]: constructor function
145 // sp[2]: number of arguments (smi-tagged)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000146 __ tst(r0, Operand(kSmiTagMask));
147 __ b(eq, &use_receiver);
148
149 // If the type of the result (stored in its map) is less than
ager@chromium.orgc27e4e72008-09-04 13:52:27 +0000150 // FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000151 __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
152 __ ldrb(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset));
153 __ cmp(r3, Operand(FIRST_JS_OBJECT_TYPE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000154 __ 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);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000164 // 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));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000169 __ LeaveConstructFrame();
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000170 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1));
171 __ add(sp, sp, Operand(kPointerSize));
172 __ mov(pc, Operand(lr));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000173}
174
175
176static 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
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000186 // Clear the context before we push it when entering the JS frame.
187 __ mov(cp, Operand(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000188
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000189 // Enter an internal frame.
190 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000191
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.
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000196 __ push(r1);
197 __ push(r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000198
199 // Copy arguments to the stack in a loop.
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000200 // r1: function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000201 // 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);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000208 __ ldr(r0, MemOperand(r4, kPointerSize, PostIndex)); // read next parameter
209 __ ldr(r0, MemOperand(r0)); // dereference handle
210 __ push(r0); // push parameter
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000211 __ 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));
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000221 if (kR9Available == 1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222 __ mov(r9, Operand(r4));
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000223 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000224
225 // Invoke the code and pass argc as r0.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000226 __ mov(r0, Operand(r3));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000227 if (is_construct) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000228 __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
ager@chromium.org236ad962008-09-25 09:45:57 +0000229 RelocInfo::CODE_TARGET);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000230 } else {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000231 ParameterCount actual(r0);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000232 __ InvokeFunction(r1, actual, CALL_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000233 }
234
235 // Exit the JS frame and remove the parameters (except function), and return.
236 // Respect ABI stack constraint.
ager@chromium.org236ad962008-09-25 09:45:57 +0000237 __ LeaveInternalFrame();
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000238 __ mov(pc, lr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000239
240 // r0: result
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000241}
242
243
244void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
245 Generate_JSEntryTrampolineHelper(masm, false);
246}
247
248
249void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
250 Generate_JSEntryTrampolineHelper(masm, true);
251}
252
253
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000254void 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
ager@chromium.org236ad962008-09-25 09:45:57 +0000334 __ LeaveInternalFrame();
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000335 __ b(&patch_receiver);
336
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000337 // Use the global receiver object from the called function as the receiver.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000338 __ bind(&use_global_receiver);
339 const int kGlobalIndex =
340 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
341 __ ldr(r2, FieldMemOperand(cp, kGlobalIndex));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000342 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000343
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);
ager@chromium.org236ad962008-09-25 09:45:57 +0000383 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
384 RelocInfo::CODE_TARGET);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000385
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.
ager@chromium.org236ad962008-09-25 09:45:57 +0000395 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
396 RelocInfo::CODE_TARGET, ne);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000397
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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000405void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000406 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
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000420 Label no_preemption, retry_preemption;
421 __ bind(&retry_preemption);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000422 ExternalReference stack_guard_limit_address =
423 ExternalReference::address_of_stack_guard_limit();
424 __ mov(r2, Operand(stack_guard_limit_address));
425 __ ldr(r2, MemOperand(r2));
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000426 __ cmp(sp, r2);
427 __ b(hi, &no_preemption);
428
429 // We have encountered a preemption or stack overflow already before we push
430 // the array contents. Save r0 which is the Smi-tagged length of the array.
431 __ push(r0);
432
433 // Runtime routines expect at least one argument, so give it a Smi.
434 __ mov(r0, Operand(Smi::FromInt(0)));
435 __ push(r0);
436 __ CallRuntime(Runtime::kStackGuard, 1);
437
438 // Since we returned, it wasn't a stack overflow. Restore r0 and try again.
439 __ pop(r0);
440 __ b(&retry_preemption);
441
442 __ bind(&no_preemption);
443
444 // Eagerly check for stack-overflow before starting to push the arguments.
445 // r0: number of arguments.
446 // r2: stack limit.
447 Label okay;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000448 __ sub(r2, sp, r2);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000449
450 __ cmp(r2, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
451 __ b(hi, &okay);
452
453 // Out of stack space.
454 __ ldr(r1, MemOperand(fp, kFunctionOffset));
455 __ push(r1);
456 __ push(r0);
457 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_JS);
458
459 // Push current limit and index.
460 __ bind(&okay);
461 __ push(r0); // limit
462 __ mov(r1, Operand(0)); // initial index
463 __ push(r1);
464
465 // Change context eagerly to get the right global object if necessary.
466 __ ldr(r0, MemOperand(fp, kFunctionOffset));
467 __ ldr(cp, FieldMemOperand(r0, JSFunction::kContextOffset));
468
469 // Compute the receiver.
470 Label call_to_object, use_global_receiver, push_receiver;
471 __ ldr(r0, MemOperand(fp, kRecvOffset));
472 __ tst(r0, Operand(kSmiTagMask));
473 __ b(eq, &call_to_object);
474 __ mov(r1, Operand(Factory::null_value()));
475 __ cmp(r0, r1);
476 __ b(eq, &use_global_receiver);
477 __ mov(r1, Operand(Factory::undefined_value()));
478 __ cmp(r0, r1);
479 __ b(eq, &use_global_receiver);
480
481 // Check if the receiver is already a JavaScript object.
482 // r0: receiver
483 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
484 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
485 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE));
486 __ b(lt, &call_to_object);
487 __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE));
488 __ b(le, &push_receiver);
489
490 // Convert the receiver to a regular object.
491 // r0: receiver
492 __ bind(&call_to_object);
493 __ push(r0);
494 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
495 __ b(&push_receiver);
496
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000497 // Use the current global receiver object as the receiver.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000498 __ bind(&use_global_receiver);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000499 const int kGlobalOffset =
500 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
501 __ ldr(r0, FieldMemOperand(cp, kGlobalOffset));
502 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000503
504 // Push the receiver.
505 // r0: receiver
506 __ bind(&push_receiver);
507 __ push(r0);
508
509 // Copy all arguments from the array to the stack.
510 Label entry, loop;
511 __ ldr(r0, MemOperand(fp, kIndexOffset));
512 __ b(&entry);
513
514 // Load the current argument from the arguments array and push it to the
515 // stack.
516 // r0: current argument index
517 __ bind(&loop);
518 __ ldr(r1, MemOperand(fp, kArgsOffset));
519 __ push(r1);
520 __ push(r0);
521
522 // Call the runtime to access the property in the arguments array.
523 __ CallRuntime(Runtime::kGetProperty, 2);
524 __ push(r0);
525
526 // Use inline caching to access the arguments.
527 __ ldr(r0, MemOperand(fp, kIndexOffset));
528 __ add(r0, r0, Operand(1 << kSmiTagSize));
529 __ str(r0, MemOperand(fp, kIndexOffset));
530
531 // Test if the copy loop has finished copying all the elements from the
532 // arguments object.
533 __ bind(&entry);
534 __ ldr(r1, MemOperand(fp, kLimitOffset));
535 __ cmp(r0, r1);
536 __ b(ne, &loop);
537
538 // Invoke the function.
539 ParameterCount actual(r0);
540 __ mov(r0, Operand(r0, ASR, kSmiTagSize));
541 __ ldr(r1, MemOperand(fp, kFunctionOffset));
542 __ InvokeFunction(r1, actual, CALL_FUNCTION);
543
544 // Tear down the internal frame and remove function, receiver and args.
ager@chromium.org236ad962008-09-25 09:45:57 +0000545 __ LeaveInternalFrame();
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000546 __ add(sp, sp, Operand(3 * kPointerSize));
547 __ mov(pc, lr);
548}
549
550
551static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
552 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
553 __ mov(r4, Operand(ArgumentsAdaptorFrame::SENTINEL));
554 __ stm(db_w, sp, r0.bit() | r1.bit() | r4.bit() | fp.bit() | lr.bit());
555 __ add(fp, sp, Operand(3 * kPointerSize));
556}
557
558
ager@chromium.org7c537e22008-10-16 08:43:32 +0000559static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000560 // ----------- S t a t e -------------
561 // -- r0 : result being passed through
562 // -----------------------------------
563 // Get the number of arguments passed (as a smi), tear down the frame and
564 // then tear down the parameters.
565 __ ldr(r1, MemOperand(fp, -3 * kPointerSize));
566 __ mov(sp, fp);
567 __ ldm(ia_w, sp, fp.bit() | lr.bit());
568 __ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
569 __ add(sp, sp, Operand(kPointerSize)); // adjust for receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000570}
571
572
573void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000574 // ----------- S t a t e -------------
575 // -- r0 : actual number of arguments
576 // -- r1 : function (passed through to callee)
577 // -- r2 : expected number of arguments
578 // -- r3 : code entry to call
579 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000580
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000581 Label invoke, dont_adapt_arguments;
582
583 Label enough, too_few;
584 __ cmp(r0, Operand(r2));
585 __ b(lt, &too_few);
586 __ cmp(r2, Operand(SharedFunctionInfo::kDontAdaptArgumentsSentinel));
587 __ b(eq, &dont_adapt_arguments);
588
ager@chromium.org32912102009-01-16 10:38:43 +0000589 { // Enough parameters: actual >= expected
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000590 __ bind(&enough);
591 EnterArgumentsAdaptorFrame(masm);
592
593 // Calculate copy start address into r0 and copy end address into r2.
594 // r0: actual number of arguments as a smi
595 // r1: function
596 // r2: expected number of arguments
597 // r3: code entry to call
598 __ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
599 // adjust for return address and receiver
600 __ add(r0, r0, Operand(2 * kPointerSize));
601 __ sub(r2, r0, Operand(r2, LSL, kPointerSizeLog2));
602
603 // Copy the arguments (including the receiver) to the new stack frame.
604 // r0: copy start address
605 // r1: function
606 // r2: copy end address
607 // r3: code entry to call
608
609 Label copy;
610 __ bind(&copy);
611 __ ldr(ip, MemOperand(r0, 0));
612 __ push(ip);
613 __ cmp(r0, r2); // Compare before moving to next argument.
614 __ sub(r0, r0, Operand(kPointerSize));
615 __ b(ne, &copy);
616
617 __ b(&invoke);
618 }
619
620 { // Too few parameters: Actual < expected
621 __ bind(&too_few);
622 EnterArgumentsAdaptorFrame(masm);
623
624 // Calculate copy start address into r0 and copy end address is fp.
625 // r0: actual number of arguments as a smi
626 // r1: function
627 // r2: expected number of arguments
628 // r3: code entry to call
629 __ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
630
631 // Copy the arguments (including the receiver) to the new stack frame.
632 // r0: copy start address
633 // r1: function
634 // r2: expected number of arguments
635 // r3: code entry to call
636 Label copy;
637 __ bind(&copy);
638 // Adjust load for return address and receiver.
639 __ ldr(ip, MemOperand(r0, 2 * kPointerSize));
640 __ push(ip);
641 __ cmp(r0, fp); // Compare before moving to next argument.
642 __ sub(r0, r0, Operand(kPointerSize));
643 __ b(ne, &copy);
644
645 // Fill the remaining expected arguments with undefined.
646 // r1: function
647 // r2: expected number of arguments
648 // r3: code entry to call
649 __ mov(ip, Operand(Factory::undefined_value()));
650 __ sub(r2, fp, Operand(r2, LSL, kPointerSizeLog2));
651 __ sub(r2, r2, Operand(4 * kPointerSize)); // Adjust for frame.
652
653 Label fill;
654 __ bind(&fill);
655 __ push(ip);
656 __ cmp(sp, r2);
657 __ b(ne, &fill);
658 }
659
660 // Call the entry point.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000661 __ bind(&invoke);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000662 __ Call(r3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000663
ager@chromium.org7c537e22008-10-16 08:43:32 +0000664 // Exit frame and return.
665 LeaveArgumentsAdaptorFrame(masm);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000666 __ mov(pc, lr);
667
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000668
669 // -------------------------------------------
670 // Dont adapt arguments.
671 // -------------------------------------------
672 __ bind(&dont_adapt_arguments);
673 __ mov(pc, r3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000674}
675
676
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000677#undef __
678
679} } // namespace v8::internal