blob: ad44026caf0bb1b9b74b0fe1752ae190e96b65e9 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-2009 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
32namespace v8 {
33namespace internal {
34
35
36#define __ ACCESS_MASM(masm)
37
38
39void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) {
40 // TODO(428): Don't pass the function in a static variable.
41 ExternalReference passed = ExternalReference::builtin_passed_function();
42 __ mov(Operand::StaticVariable(passed), edi);
43
44 // The actual argument count has already been loaded into register
45 // eax, but JumpToRuntime expects eax to contain the number of
46 // arguments including the receiver.
47 __ inc(eax);
48 __ JumpToRuntime(ExternalReference(id));
49}
50
51
52void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
53 // ----------- S t a t e -------------
54 // -- eax: number of arguments
55 // -- edi: constructor function
56 // -----------------------------------
57
58 Label non_function_call;
59 // Check that function is not a smi.
60 __ test(edi, Immediate(kSmiTagMask));
61 __ j(zero, &non_function_call);
62 // Check that function is a JSFunction.
63 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
64 __ j(not_equal, &non_function_call);
65
66 // Jump to the function-specific construct stub.
67 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
68 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kConstructStubOffset));
69 __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize));
70 __ jmp(Operand(ebx));
71
72 // edi: called object
73 // eax: number of arguments
74 __ bind(&non_function_call);
75
76 // Set expected number of arguments to zero (not changing eax).
77 __ Set(ebx, Immediate(0));
78 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
79 __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
80 RelocInfo::CODE_TARGET);
81}
82
83
84void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
85 // Enter a construct frame.
86 __ EnterConstructFrame();
87
88 // Store a smi-tagged arguments count on the stack.
89 __ shl(eax, kSmiTagSize);
90 __ push(eax);
91
92 // Push the function to invoke on the stack.
93 __ push(edi);
94
95 // Try to allocate the object without transitioning into C code. If any of the
96 // preconditions is not met, the code bails out to the runtime call.
97 Label rt_call, allocated;
98 if (FLAG_inline_new) {
99 Label undo_allocation;
100#ifdef ENABLE_DEBUGGER_SUPPORT
101 ExternalReference debug_step_in_fp =
102 ExternalReference::debug_step_in_fp_address();
103 __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
104 __ j(not_equal, &rt_call);
105#endif
106
107 // Verified that the constructor is a JSFunction.
108 // Load the initial map and verify that it is in fact a map.
109 // edi: constructor
110 __ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
111 // Will both indicate a NULL and a Smi
112 __ test(eax, Immediate(kSmiTagMask));
113 __ j(zero, &rt_call);
114 // edi: constructor
115 // eax: initial map (if proven valid below)
116 __ CmpObjectType(eax, MAP_TYPE, ebx);
117 __ j(not_equal, &rt_call);
118
119 // Check that the constructor is not constructing a JSFunction (see comments
120 // in Runtime_NewObject in runtime.cc). In which case the initial map's
121 // instance type would be JS_FUNCTION_TYPE.
122 // edi: constructor
123 // eax: initial map
124 __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
125 __ j(equal, &rt_call);
126
127 // Now allocate the JSObject on the heap.
128 // edi: constructor
129 // eax: initial map
130 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset));
131 __ shl(edi, kPointerSizeLog2);
132 __ AllocateInNewSpace(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS);
133 // Allocated the JSObject, now initialize the fields.
134 // eax: initial map
135 // ebx: JSObject
136 // edi: start of next object
137 __ mov(Operand(ebx, JSObject::kMapOffset), eax);
138 __ mov(ecx, Factory::empty_fixed_array());
139 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
140 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
141 // Set extra fields in the newly allocated object.
142 // eax: initial map
143 // ebx: JSObject
144 // edi: start of next object
145 { Label loop, entry;
146 __ mov(edx, Factory::undefined_value());
147 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
148 __ jmp(&entry);
149 __ bind(&loop);
150 __ mov(Operand(ecx, 0), edx);
151 __ add(Operand(ecx), Immediate(kPointerSize));
152 __ bind(&entry);
153 __ cmp(ecx, Operand(edi));
154 __ j(less, &loop);
155 }
156
157 // Add the object tag to make the JSObject real, so that we can continue and
158 // jump into the continuation code at any time from now on. Any failures
159 // need to undo the allocation, so that the heap is in a consistent state
160 // and verifiable.
161 // eax: initial map
162 // ebx: JSObject
163 // edi: start of next object
164 __ or_(Operand(ebx), Immediate(kHeapObjectTag));
165
166 // Check if a non-empty properties array is needed.
167 // Allocate and initialize a FixedArray if it is.
168 // eax: initial map
169 // ebx: JSObject
170 // edi: start of next object
171 // Calculate the total number of properties described by the map.
172 __ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
173 __ movzx_b(ecx, FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
174 __ add(edx, Operand(ecx));
175 // Calculate unused properties past the end of the in-object properties.
176 __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset));
177 __ sub(edx, Operand(ecx));
178 // Done if no extra properties are to be allocated.
179 __ j(zero, &allocated);
180 __ Assert(positive, "Property allocation count failed.");
181
182 // Scale the number of elements by pointer size and add the header for
183 // FixedArrays to the start of the next object calculation from above.
184 // ebx: JSObject
185 // edi: start of next object (will be start of FixedArray)
186 // edx: number of elements in properties array
187 __ AllocateInNewSpace(FixedArray::kHeaderSize,
188 times_pointer_size,
189 edx,
190 edi,
191 ecx,
192 no_reg,
193 &undo_allocation,
194 RESULT_CONTAINS_TOP);
195
196 // Initialize the FixedArray.
197 // ebx: JSObject
198 // edi: FixedArray
199 // edx: number of elements
200 // ecx: start of next object
201 __ mov(eax, Factory::fixed_array_map());
202 __ mov(Operand(edi, JSObject::kMapOffset), eax); // setup the map
203 __ mov(Operand(edi, Array::kLengthOffset), edx); // and length
204
205 // Initialize the fields to undefined.
206 // ebx: JSObject
207 // edi: FixedArray
208 // ecx: start of next object
209 { Label loop, entry;
210 __ mov(edx, Factory::undefined_value());
211 __ lea(eax, Operand(edi, FixedArray::kHeaderSize));
212 __ jmp(&entry);
213 __ bind(&loop);
214 __ mov(Operand(eax, 0), edx);
215 __ add(Operand(eax), Immediate(kPointerSize));
216 __ bind(&entry);
217 __ cmp(eax, Operand(ecx));
218 __ j(below, &loop);
219 }
220
221 // Store the initialized FixedArray into the properties field of
222 // the JSObject
223 // ebx: JSObject
224 // edi: FixedArray
225 __ or_(Operand(edi), Immediate(kHeapObjectTag)); // add the heap tag
226 __ mov(FieldOperand(ebx, JSObject::kPropertiesOffset), edi);
227
228
229 // Continue with JSObject being successfully allocated
230 // ebx: JSObject
231 __ jmp(&allocated);
232
233 // Undo the setting of the new top so that the heap is verifiable. For
234 // example, the map's unused properties potentially do not match the
235 // allocated objects unused properties.
236 // ebx: JSObject (previous new top)
237 __ bind(&undo_allocation);
238 __ UndoAllocationInNewSpace(ebx);
239 }
240
241 // Allocate the new receiver object using the runtime call.
242 __ bind(&rt_call);
243 // Must restore edi (constructor) before calling runtime.
244 __ mov(edi, Operand(esp, 0));
245 // edi: function (constructor)
246 __ push(edi);
247 __ CallRuntime(Runtime::kNewObject, 1);
248 __ mov(ebx, Operand(eax)); // store result in ebx
249
250 // New object allocated.
251 // ebx: newly allocated object
252 __ bind(&allocated);
253 // Retrieve the function from the stack.
254 __ pop(edi);
255
256 // Retrieve smi-tagged arguments count from the stack.
257 __ mov(eax, Operand(esp, 0));
258 __ shr(eax, kSmiTagSize);
259
260 // Push the allocated receiver to the stack. We need two copies
261 // because we may have to return the original one and the calling
262 // conventions dictate that the called function pops the receiver.
263 __ push(ebx);
264 __ push(ebx);
265
266 // Setup pointer to last argument.
267 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
268
269 // Copy arguments and receiver to the expression stack.
270 Label loop, entry;
271 __ mov(ecx, Operand(eax));
272 __ jmp(&entry);
273 __ bind(&loop);
274 __ push(Operand(ebx, ecx, times_4, 0));
275 __ bind(&entry);
276 __ dec(ecx);
277 __ j(greater_equal, &loop);
278
279 // Call the function.
280 ParameterCount actual(eax);
281 __ InvokeFunction(edi, actual, CALL_FUNCTION);
282
283 // Restore context from the frame.
284 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
285
286 // If the result is an object (in the ECMA sense), we should get rid
287 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
288 // on page 74.
289 Label use_receiver, exit;
290
291 // If the result is a smi, it is *not* an object in the ECMA sense.
292 __ test(eax, Immediate(kSmiTagMask));
293 __ j(zero, &use_receiver, not_taken);
294
295 // If the type of the result (stored in its map) is less than
296 // FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense.
297 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
298 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
299 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
300 __ j(greater_equal, &exit, not_taken);
301
302 // Throw away the result of the constructor invocation and use the
303 // on-stack receiver as the result.
304 __ bind(&use_receiver);
305 __ mov(eax, Operand(esp, 0));
306
307 // Restore the arguments count and leave the construct frame.
308 __ bind(&exit);
309 __ mov(ebx, Operand(esp, kPointerSize)); // get arguments count
310 __ LeaveConstructFrame();
311
312 // Remove caller arguments from the stack and return.
313 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
314 __ pop(ecx);
315 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
316 __ push(ecx);
317 __ IncrementCounter(&Counters::constructed_objects, 1);
318 __ ret(0);
319}
320
321
322static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
323 bool is_construct) {
324 // Clear the context before we push it when entering the JS frame.
325 __ xor_(esi, Operand(esi)); // clear esi
326
327 // Enter an internal frame.
328 __ EnterInternalFrame();
329
330 // Load the previous frame pointer (ebx) to access C arguments
331 __ mov(ebx, Operand(ebp, 0));
332
333 // Get the function from the frame and setup the context.
334 __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
335 __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset));
336
337 // Push the function and the receiver onto the stack.
338 __ push(ecx);
339 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
340
341 // Load the number of arguments and setup pointer to the arguments.
342 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
343 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
344
345 // Copy arguments to the stack in a loop.
346 Label loop, entry;
347 __ xor_(ecx, Operand(ecx)); // clear ecx
348 __ jmp(&entry);
349 __ bind(&loop);
350 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv
351 __ push(Operand(edx, 0)); // dereference handle
352 __ inc(Operand(ecx));
353 __ bind(&entry);
354 __ cmp(ecx, Operand(eax));
355 __ j(not_equal, &loop);
356
357 // Get the function from the stack and call it.
358 __ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize)); // +1 ~ receiver
359
360 // Invoke the code.
361 if (is_construct) {
362 __ call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
363 RelocInfo::CODE_TARGET);
364 } else {
365 ParameterCount actual(eax);
366 __ InvokeFunction(edi, actual, CALL_FUNCTION);
367 }
368
369 // Exit the JS frame. Notice that this also removes the empty
370 // context and the function left on the stack by the code
371 // invocation.
372 __ LeaveInternalFrame();
373 __ ret(1 * kPointerSize); // remove receiver
374}
375
376
377void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
378 Generate_JSEntryTrampolineHelper(masm, false);
379}
380
381
382void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
383 Generate_JSEntryTrampolineHelper(masm, true);
384}
385
386
387void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
388 // 1. Make sure we have at least one argument.
389 { Label done;
390 __ test(eax, Operand(eax));
391 __ j(not_zero, &done, taken);
392 __ pop(ebx);
393 __ push(Immediate(Factory::undefined_value()));
394 __ push(ebx);
395 __ inc(eax);
396 __ bind(&done);
397 }
398
399 // 2. Get the function to call from the stack.
400 { Label done, non_function, function;
401 // +1 ~ return address.
402 __ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize));
403 __ test(edi, Immediate(kSmiTagMask));
404 __ j(zero, &non_function, not_taken);
405 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
406 __ j(equal, &function, taken);
407
408 // Non-function called: Clear the function to force exception.
409 __ bind(&non_function);
410 __ xor_(edi, Operand(edi));
411 __ jmp(&done);
412
413 // Function called: Change context eagerly to get the right global object.
414 __ bind(&function);
415 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
416
417 __ bind(&done);
418 }
419
420 // 3. Make sure first argument is an object; convert if necessary.
421 { Label call_to_object, use_global_receiver, patch_receiver, done;
422 __ mov(ebx, Operand(esp, eax, times_4, 0));
423
424 __ test(ebx, Immediate(kSmiTagMask));
425 __ j(zero, &call_to_object);
426
427 __ cmp(ebx, Factory::null_value());
428 __ j(equal, &use_global_receiver);
429 __ cmp(ebx, Factory::undefined_value());
430 __ j(equal, &use_global_receiver);
431
432 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
433 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
434 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
435 __ j(less, &call_to_object);
436 __ cmp(ecx, LAST_JS_OBJECT_TYPE);
437 __ j(less_equal, &done);
438
439 __ bind(&call_to_object);
440 __ EnterInternalFrame(); // preserves eax, ebx, edi
441
442 // Store the arguments count on the stack (smi tagged).
443 ASSERT(kSmiTag == 0);
444 __ shl(eax, kSmiTagSize);
445 __ push(eax);
446
447 __ push(edi); // save edi across the call
448 __ push(ebx);
449 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
450 __ mov(ebx, eax);
451 __ pop(edi); // restore edi after the call
452
453 // Get the arguments count and untag it.
454 __ pop(eax);
455 __ shr(eax, kSmiTagSize);
456
457 __ LeaveInternalFrame();
458 __ jmp(&patch_receiver);
459
460 // Use the global receiver object from the called function as the receiver.
461 __ bind(&use_global_receiver);
462 const int kGlobalIndex =
463 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
464 __ mov(ebx, FieldOperand(esi, kGlobalIndex));
465 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
466
467 __ bind(&patch_receiver);
468 __ mov(Operand(esp, eax, times_4, 0), ebx);
469
470 __ bind(&done);
471 }
472
473 // 4. Shift stuff one slot down the stack.
474 { Label loop;
475 __ lea(ecx, Operand(eax, +1)); // +1 ~ copy receiver too
476 __ bind(&loop);
477 __ mov(ebx, Operand(esp, ecx, times_4, 0));
478 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
479 __ dec(ecx);
480 __ j(not_zero, &loop);
481 }
482
483 // 5. Remove TOS (copy of last arguments), but keep return address.
484 __ pop(ebx);
485 __ pop(ecx);
486 __ push(ebx);
487 __ dec(eax);
488
489 // 6. Check that function really was a function and get the code to
490 // call from the function and check that the number of expected
491 // arguments matches what we're providing.
492 { Label invoke;
493 __ test(edi, Operand(edi));
494 __ j(not_zero, &invoke, taken);
495 __ xor_(ebx, Operand(ebx));
496 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
497 __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
498 RelocInfo::CODE_TARGET);
499
500 __ bind(&invoke);
501 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
502 __ mov(ebx,
503 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
504 __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset));
505 __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
506 __ cmp(eax, Operand(ebx));
507 __ j(not_equal, Handle<Code>(builtin(ArgumentsAdaptorTrampoline)));
508 }
509
510 // 7. Jump (tail-call) to the code in register edx without checking arguments.
511 ParameterCount expected(0);
512 __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION);
513}
514
515
516void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
517 __ EnterInternalFrame();
518
519 __ push(Operand(ebp, 4 * kPointerSize)); // push this
520 __ push(Operand(ebp, 2 * kPointerSize)); // push arguments
521 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
522
523 if (FLAG_check_stack) {
524 // We need to catch preemptions right here, otherwise an unlucky preemption
525 // could show up as a failed apply.
526 ExternalReference stack_guard_limit =
527 ExternalReference::address_of_stack_guard_limit();
528 Label retry_preemption;
529 Label no_preemption;
530 __ bind(&retry_preemption);
531 __ mov(edi, Operand::StaticVariable(stack_guard_limit));
532 __ cmp(esp, Operand(edi));
533 __ j(above, &no_preemption, taken);
534
535 // Preemption!
536 // Because builtins always remove the receiver from the stack, we
537 // have to fake one to avoid underflowing the stack.
538 __ push(eax);
539 __ push(Immediate(Smi::FromInt(0)));
540
541 // Do call to runtime routine.
542 __ CallRuntime(Runtime::kStackGuard, 1);
543 __ pop(eax);
544 __ jmp(&retry_preemption);
545
546 __ bind(&no_preemption);
547
548 Label okay;
549 // Make ecx the space we have left.
550 __ mov(ecx, Operand(esp));
551 __ sub(ecx, Operand(edi));
552 // Make edx the space we need for the array when it is unrolled onto the
553 // stack.
554 __ mov(edx, Operand(eax));
555 __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
556 __ cmp(ecx, Operand(edx));
557 __ j(greater, &okay, taken);
558
559 // Too bad: Out of stack space.
560 __ push(Operand(ebp, 4 * kPointerSize)); // push this
561 __ push(eax);
562 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
563 __ bind(&okay);
564 }
565
566 // Push current index and limit.
567 const int kLimitOffset =
568 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
569 const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
570 __ push(eax); // limit
571 __ push(Immediate(0)); // index
572
573 // Change context eagerly to get the right global object if
574 // necessary.
575 __ mov(edi, Operand(ebp, 4 * kPointerSize));
576 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
577
578 // Compute the receiver.
579 Label call_to_object, use_global_receiver, push_receiver;
580 __ mov(ebx, Operand(ebp, 3 * kPointerSize));
581 __ test(ebx, Immediate(kSmiTagMask));
582 __ j(zero, &call_to_object);
583 __ cmp(ebx, Factory::null_value());
584 __ j(equal, &use_global_receiver);
585 __ cmp(ebx, Factory::undefined_value());
586 __ j(equal, &use_global_receiver);
587
588 // If given receiver is already a JavaScript object then there's no
589 // reason for converting it.
590 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
591 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
592 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
593 __ j(less, &call_to_object);
594 __ cmp(ecx, LAST_JS_OBJECT_TYPE);
595 __ j(less_equal, &push_receiver);
596
597 // Convert the receiver to an object.
598 __ bind(&call_to_object);
599 __ push(ebx);
600 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
601 __ mov(ebx, Operand(eax));
602 __ jmp(&push_receiver);
603
604 // Use the current global receiver object as the receiver.
605 __ bind(&use_global_receiver);
606 const int kGlobalOffset =
607 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
608 __ mov(ebx, FieldOperand(esi, kGlobalOffset));
609 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
610
611 // Push the receiver.
612 __ bind(&push_receiver);
613 __ push(ebx);
614
615 // Copy all arguments from the array to the stack.
616 Label entry, loop;
617 __ mov(eax, Operand(ebp, kIndexOffset));
618 __ jmp(&entry);
619 __ bind(&loop);
620 __ mov(ecx, Operand(ebp, 2 * kPointerSize)); // load arguments
621 __ push(ecx);
622 __ push(eax);
623
624 // Use inline caching to speed up access to arguments.
625 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
626 __ call(ic, RelocInfo::CODE_TARGET);
627 // It is important that we do not have a test instruction after the
628 // call. A test instruction after the call is used to indicate that
629 // we have generated an inline version of the keyed load. In this
630 // case, we know that we are not generating a test instruction next.
631
632 // Remove IC arguments from the stack and push the nth argument.
633 __ add(Operand(esp), Immediate(2 * kPointerSize));
634 __ push(eax);
635
636 // Update the index on the stack and in register eax.
637 __ mov(eax, Operand(ebp, kIndexOffset));
638 __ add(Operand(eax), Immediate(1 << kSmiTagSize));
639 __ mov(Operand(ebp, kIndexOffset), eax);
640
641 __ bind(&entry);
642 __ cmp(eax, Operand(ebp, kLimitOffset));
643 __ j(not_equal, &loop);
644
645 // Invoke the function.
646 ParameterCount actual(eax);
647 __ shr(eax, kSmiTagSize);
648 __ mov(edi, Operand(ebp, 4 * kPointerSize));
649 __ InvokeFunction(edi, actual, CALL_FUNCTION);
650
651 __ LeaveInternalFrame();
652 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
653}
654
655
656// Load the built-in Array function from the current context.
657static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) {
658 // Load the global context.
659 __ mov(result, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
660 __ mov(result, FieldOperand(result, GlobalObject::kGlobalContextOffset));
661 // Load the Array function from the global context.
662 __ mov(result,
663 Operand(result, Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
664}
665
666
667// Number of empty elements to allocate for an empty array.
668static const int kPreallocatedArrayElements = 4;
669
670
671// Allocate an empty JSArray. The allocated array is put into the result
672// register. If the parameter initial_capacity is larger than zero an elements
673// backing store is allocated with this size and filled with the hole values.
674// Otherwise the elements backing store is set to the empty FixedArray.
675static void AllocateEmptyJSArray(MacroAssembler* masm,
676 Register array_function,
677 Register result,
678 Register scratch1,
679 Register scratch2,
680 Register scratch3,
681 int initial_capacity,
682 Label* gc_required) {
683 ASSERT(initial_capacity >= 0);
684
685 // Load the initial map from the array function.
686 __ mov(scratch1, FieldOperand(array_function,
687 JSFunction::kPrototypeOrInitialMapOffset));
688
689 // Allocate the JSArray object together with space for a fixed array with the
690 // requested elements.
691 int size = JSArray::kSize;
692 if (initial_capacity > 0) {
693 size += FixedArray::SizeFor(initial_capacity);
694 }
695 __ AllocateInNewSpace(size,
696 result,
697 scratch2,
698 scratch3,
699 gc_required,
700 TAG_OBJECT);
701
702 // Allocated the JSArray. Now initialize the fields except for the elements
703 // array.
704 // result: JSObject
705 // scratch1: initial map
706 // scratch2: start of next object
707 __ mov(FieldOperand(result, JSObject::kMapOffset), scratch1);
708 __ mov(FieldOperand(result, JSArray::kPropertiesOffset),
709 Factory::empty_fixed_array());
710 // Field JSArray::kElementsOffset is initialized later.
711 __ mov(FieldOperand(result, JSArray::kLengthOffset), Immediate(0));
712
713 // If no storage is requested for the elements array just set the empty
714 // fixed array.
715 if (initial_capacity == 0) {
716 __ mov(FieldOperand(result, JSArray::kElementsOffset),
717 Factory::empty_fixed_array());
718 return;
719 }
720
721 // Calculate the location of the elements array and set elements array member
722 // of the JSArray.
723 // result: JSObject
724 // scratch2: start of next object
725 __ lea(scratch1, Operand(result, JSArray::kSize));
726 __ mov(FieldOperand(result, JSArray::kElementsOffset), scratch1);
727
728 // Initialize the FixedArray and fill it with holes. FixedArray length is not
729 // stored as a smi.
730 // result: JSObject
731 // scratch1: elements array
732 // scratch2: start of next object
733 __ mov(FieldOperand(scratch1, JSObject::kMapOffset),
734 Factory::fixed_array_map());
735 __ mov(FieldOperand(scratch1, Array::kLengthOffset),
736 Immediate(initial_capacity));
737
738 // Fill the FixedArray with the hole value. Inline the code if short.
739 // Reconsider loop unfolding if kPreallocatedArrayElements gets changed.
740 static const int kLoopUnfoldLimit = 4;
741 ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit);
742 if (initial_capacity <= kLoopUnfoldLimit) {
743 // Use a scratch register here to have only one reloc info when unfolding
744 // the loop.
745 __ mov(scratch3, Factory::the_hole_value());
746 for (int i = 0; i < initial_capacity; i++) {
747 __ mov(FieldOperand(scratch1,
748 FixedArray::kHeaderSize + i * kPointerSize),
749 scratch3);
750 }
751 } else {
752 Label loop, entry;
753 __ jmp(&entry);
754 __ bind(&loop);
755 __ mov(Operand(scratch1, 0), Factory::the_hole_value());
756 __ add(Operand(scratch1), Immediate(kPointerSize));
757 __ bind(&entry);
758 __ cmp(scratch1, Operand(scratch2));
759 __ j(below, &loop);
760 }
761}
762
763
764// Allocate a JSArray with the number of elements stored in a register. The
765// register array_function holds the built-in Array function and the register
766// array_size holds the size of the array as a smi. The allocated array is put
767// into the result register and beginning and end of the FixedArray elements
768// storage is put into registers elements_array and elements_array_end (see
769// below for when that is not the case). If the parameter fill_with_holes is
770// true the allocated elements backing store is filled with the hole values
771// otherwise it is left uninitialized. When the backing store is filled the
772// register elements_array is scratched.
773static void AllocateJSArray(MacroAssembler* masm,
774 Register array_function, // Array function.
775 Register array_size, // As a smi.
776 Register result,
777 Register elements_array,
778 Register elements_array_end,
779 Register scratch,
780 bool fill_with_hole,
781 Label* gc_required) {
782 Label not_empty, allocated;
783
784 // Load the initial map from the array function.
785 __ mov(elements_array,
786 FieldOperand(array_function,
787 JSFunction::kPrototypeOrInitialMapOffset));
788
789 // Check whether an empty sized array is requested.
790 __ test(array_size, Operand(array_size));
791 __ j(not_zero, &not_empty);
792
793 // If an empty array is requested allocate a small elements array anyway. This
794 // keeps the code below free of special casing for the empty array.
795 int size = JSArray::kSize + FixedArray::SizeFor(kPreallocatedArrayElements);
796 __ AllocateInNewSpace(size,
797 result,
798 elements_array_end,
799 scratch,
800 gc_required,
801 TAG_OBJECT);
802 __ jmp(&allocated);
803
804 // Allocate the JSArray object together with space for a FixedArray with the
805 // requested elements.
806 __ bind(&not_empty);
807 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
808 __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
809 times_half_pointer_size, // array_size is a smi.
810 array_size,
811 result,
812 elements_array_end,
813 scratch,
814 gc_required,
815 TAG_OBJECT);
816
817 // Allocated the JSArray. Now initialize the fields except for the elements
818 // array.
819 // result: JSObject
820 // elements_array: initial map
821 // elements_array_end: start of next object
822 // array_size: size of array (smi)
823 __ bind(&allocated);
824 __ mov(FieldOperand(result, JSObject::kMapOffset), elements_array);
825 __ mov(elements_array, Factory::empty_fixed_array());
826 __ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
827 // Field JSArray::kElementsOffset is initialized later.
828 __ mov(FieldOperand(result, JSArray::kLengthOffset), array_size);
829
830 // Calculate the location of the elements array and set elements array member
831 // of the JSArray.
832 // result: JSObject
833 // elements_array_end: start of next object
834 // array_size: size of array (smi)
835 __ lea(elements_array, Operand(result, JSArray::kSize));
836 __ mov(FieldOperand(result, JSArray::kElementsOffset), elements_array);
837
838 // Initialize the fixed array. FixedArray length is not stored as a smi.
839 // result: JSObject
840 // elements_array: elements array
841 // elements_array_end: start of next object
842 // array_size: size of array (smi)
843 ASSERT(kSmiTag == 0);
844 __ shr(array_size, kSmiTagSize); // Convert from smi to value.
845 __ mov(FieldOperand(elements_array, JSObject::kMapOffset),
846 Factory::fixed_array_map());
847 Label not_empty_2, fill_array;
848 __ test(array_size, Operand(array_size));
849 __ j(not_zero, &not_empty_2);
850 // Length of the FixedArray is the number of pre-allocated elements even
851 // though the actual JSArray has length 0.
852 __ mov(FieldOperand(elements_array, Array::kLengthOffset),
853 Immediate(kPreallocatedArrayElements));
854 __ jmp(&fill_array);
855 __ bind(&not_empty_2);
856 // For non-empty JSArrays the length of the FixedArray and the JSArray is the
857 // same.
858 __ mov(FieldOperand(elements_array, Array::kLengthOffset), array_size);
859
860 // Fill the allocated FixedArray with the hole value if requested.
861 // result: JSObject
862 // elements_array: elements array
863 // elements_array_end: start of next object
864 __ bind(&fill_array);
865 if (fill_with_hole) {
866 Label loop, entry;
867 __ mov(scratch, Factory::the_hole_value());
868 __ lea(elements_array, Operand(elements_array,
869 FixedArray::kHeaderSize - kHeapObjectTag));
870 __ jmp(&entry);
871 __ bind(&loop);
872 __ mov(Operand(elements_array, 0), scratch);
873 __ add(Operand(elements_array), Immediate(kPointerSize));
874 __ bind(&entry);
875 __ cmp(elements_array, Operand(elements_array_end));
876 __ j(below, &loop);
877 }
878}
879
880
881// Create a new array for the built-in Array function. This function allocates
882// the JSArray object and the FixedArray elements array and initializes these.
883// If the Array cannot be constructed in native code the runtime is called. This
884// function assumes the following state:
885// edi: constructor (built-in Array function)
886// eax: argc
887// esp[0]: return address
888// esp[4]: last argument
889// This function is used for both construct and normal calls of Array. Whether
890// it is a construct call or not is indicated by the construct_call parameter.
891// The only difference between handling a construct call and a normal call is
892// that for a construct call the constructor function in edi needs to be
893// preserved for entering the generic code. In both cases argc in eax needs to
894// be preserved.
895static void ArrayNativeCode(MacroAssembler* masm,
896 bool construct_call,
897 Label *call_generic_code) {
898 Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call;
899
900 // Push the constructor and argc. No need to tag argc as a smi, as there will
901 // be no garbage collection with this on the stack.
902 int push_count = 0;
903 if (construct_call) {
904 push_count++;
905 __ push(edi);
906 }
907 push_count++;
908 __ push(eax);
909
910 // Check for array construction with zero arguments.
911 __ test(eax, Operand(eax));
912 __ j(not_zero, &argc_one_or_more);
913
914 // Handle construction of an empty array.
915 AllocateEmptyJSArray(masm,
916 edi,
917 eax,
918 ebx,
919 ecx,
920 edi,
921 kPreallocatedArrayElements,
922 &prepare_generic_code_call);
923 __ IncrementCounter(&Counters::array_function_native, 1);
924 __ pop(ebx);
925 if (construct_call) {
926 __ pop(edi);
927 }
928 __ ret(kPointerSize);
929
930 // Check for one argument. Bail out if argument is not smi or if it is
931 // negative.
932 __ bind(&argc_one_or_more);
933 __ cmp(eax, 1);
934 __ j(not_equal, &argc_two_or_more);
935 ASSERT(kSmiTag == 0);
936 __ test(Operand(esp, (push_count + 1) * kPointerSize),
937 Immediate(kIntptrSignBit | kSmiTagMask));
938 __ j(not_zero, &prepare_generic_code_call);
939
940 // Handle construction of an empty array of a certain size. Get the size from
941 // the stack and bail out if size is to large to actually allocate an elements
942 // array.
943 __ mov(edx, Operand(esp, (push_count + 1) * kPointerSize));
944 ASSERT(kSmiTag == 0);
945 __ cmp(edx, JSObject::kInitialMaxFastElementArray << kSmiTagSize);
946 __ j(greater_equal, &prepare_generic_code_call);
947
948 // edx: array_size (smi)
949 // edi: constructor
950 // esp[0]: argc
951 // esp[4]: constructor (only if construct_call)
952 // esp[8]: return address
953 // esp[C]: argument
954 AllocateJSArray(masm,
955 edi,
956 edx,
957 eax,
958 ebx,
959 ecx,
960 edi,
961 true,
962 &prepare_generic_code_call);
963 __ IncrementCounter(&Counters::array_function_native, 1);
964 __ pop(ebx);
965 if (construct_call) {
966 __ pop(edi);
967 }
968 __ ret(2 * kPointerSize);
969
970 // Handle construction of an array from a list of arguments.
971 __ bind(&argc_two_or_more);
972 ASSERT(kSmiTag == 0);
973 __ shl(eax, kSmiTagSize); // Convet argc to a smi.
974 // eax: array_size (smi)
975 // edi: constructor
976 // esp[0] : argc
977 // esp[4]: constructor (only if construct_call)
978 // esp[8] : return address
979 // esp[C] : last argument
980 AllocateJSArray(masm,
981 edi,
982 eax,
983 ebx,
984 ecx,
985 edx,
986 edi,
987 false,
988 &prepare_generic_code_call);
989 __ IncrementCounter(&Counters::array_function_native, 1);
990 __ mov(eax, ebx);
991 __ pop(ebx);
992 if (construct_call) {
993 __ pop(edi);
994 }
995 __ push(eax);
996 // eax: JSArray
997 // ebx: argc
998 // edx: elements_array_end (untagged)
999 // esp[0]: JSArray
1000 // esp[4]: return address
1001 // esp[8]: last argument
1002
1003 // Location of the last argument
1004 __ lea(edi, Operand(esp, 2 * kPointerSize));
1005
1006 // Location of the first array element (Parameter fill_with_holes to
1007 // AllocateJSArrayis false, so the FixedArray is returned in ecx).
1008 __ lea(edx, Operand(ecx, FixedArray::kHeaderSize - kHeapObjectTag));
1009
1010 // ebx: argc
1011 // edx: location of the first array element
1012 // edi: location of the last argument
1013 // esp[0]: JSArray
1014 // esp[4]: return address
1015 // esp[8]: last argument
1016 Label loop, entry;
1017 __ mov(ecx, ebx);
1018 __ jmp(&entry);
1019 __ bind(&loop);
1020 __ mov(eax, Operand(edi, ecx, times_pointer_size, 0));
1021 __ mov(Operand(edx, 0), eax);
1022 __ add(Operand(edx), Immediate(kPointerSize));
1023 __ bind(&entry);
1024 __ dec(ecx);
1025 __ j(greater_equal, &loop);
1026
1027 // Remove caller arguments from the stack and return.
1028 // ebx: argc
1029 // esp[0]: JSArray
1030 // esp[4]: return address
1031 // esp[8]: last argument
1032 __ pop(eax);
1033 __ pop(ecx);
1034 __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
1035 __ push(ecx);
1036 __ ret(0);
1037
1038 // Restore argc and constructor before running the generic code.
1039 __ bind(&prepare_generic_code_call);
1040 __ pop(eax);
1041 if (construct_call) {
1042 __ pop(edi);
1043 }
1044 __ jmp(call_generic_code);
1045}
1046
1047
1048void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1049 // ----------- S t a t e -------------
1050 // -- eax : argc
1051 // -- esp[0] : return address
1052 // -- esp[4] : last argument
1053 // -----------------------------------
1054 Label generic_array_code, one_or_more_arguments, two_or_more_arguments;
1055
1056 // Get the Array function.
1057 GenerateLoadArrayFunction(masm, edi);
1058
1059 if (FLAG_debug_code) {
1060 // Initial map for the builtin Array function shoud be a map.
1061 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1062 // Will both indicate a NULL and a Smi.
1063 __ test(ebx, Immediate(kSmiTagMask));
1064 __ Assert(not_zero, "Unexpected initial map for Array function");
1065 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1066 __ Assert(equal, "Unexpected initial map for Array function");
1067 }
1068
1069 // Run the native code for the Array function called as a normal function.
1070 ArrayNativeCode(masm, false, &generic_array_code);
1071
1072 // Jump to the generic array code in case the specialized code cannot handle
1073 // the construction.
1074 __ bind(&generic_array_code);
1075 Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric);
1076 Handle<Code> array_code(code);
1077 __ jmp(array_code, RelocInfo::CODE_TARGET);
1078}
1079
1080
1081void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
1082 // ----------- S t a t e -------------
1083 // -- eax : argc
1084 // -- edi : constructor
1085 // -- esp[0] : return address
1086 // -- esp[4] : last argument
1087 // -----------------------------------
1088 Label generic_constructor;
1089
1090 if (FLAG_debug_code) {
1091 // The array construct code is only set for the builtin Array function which
1092 // does always have a map.
1093 GenerateLoadArrayFunction(masm, ebx);
1094 __ cmp(edi, Operand(ebx));
1095 __ Assert(equal, "Unexpected Array function");
1096 // Initial map for the builtin Array function should be a map.
1097 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1098 // Will both indicate a NULL and a Smi.
1099 __ test(ebx, Immediate(kSmiTagMask));
1100 __ Assert(not_zero, "Unexpected initial map for Array function");
1101 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1102 __ Assert(equal, "Unexpected initial map for Array function");
1103 }
1104
1105 // Run the native code for the Array function called as constructor.
1106 ArrayNativeCode(masm, true, &generic_constructor);
1107
1108 // Jump to the generic construct code in case the specialized code cannot
1109 // handle the construction.
1110 __ bind(&generic_constructor);
1111 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
1112 Handle<Code> generic_construct_stub(code);
1113 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
1114}
1115
1116
1117static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1118 __ push(ebp);
1119 __ mov(ebp, Operand(esp));
1120
1121 // Store the arguments adaptor context sentinel.
1122 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1123
1124 // Push the function on the stack.
1125 __ push(edi);
1126
1127 // Preserve the number of arguments on the stack. Must preserve both
1128 // eax and ebx because these registers are used when copying the
1129 // arguments and the receiver.
1130 ASSERT(kSmiTagSize == 1);
1131 __ lea(ecx, Operand(eax, eax, times_1, kSmiTag));
1132 __ push(ecx);
1133}
1134
1135
1136static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1137 // Retrieve the number of arguments from the stack.
1138 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1139
1140 // Leave the frame.
1141 __ leave();
1142
1143 // Remove caller arguments from the stack.
1144 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
1145 __ pop(ecx);
1146 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
1147 __ push(ecx);
1148}
1149
1150
1151void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1152 // ----------- S t a t e -------------
1153 // -- eax : actual number of arguments
1154 // -- ebx : expected number of arguments
1155 // -- edx : code entry to call
1156 // -----------------------------------
1157
1158 Label invoke, dont_adapt_arguments;
1159 __ IncrementCounter(&Counters::arguments_adaptors, 1);
1160
1161 Label enough, too_few;
1162 __ cmp(eax, Operand(ebx));
1163 __ j(less, &too_few);
1164 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1165 __ j(equal, &dont_adapt_arguments);
1166
1167 { // Enough parameters: Actual >= expected.
1168 __ bind(&enough);
1169 EnterArgumentsAdaptorFrame(masm);
1170
1171 // Copy receiver and all expected arguments.
1172 const int offset = StandardFrameConstants::kCallerSPOffset;
1173 __ lea(eax, Operand(ebp, eax, times_4, offset));
1174 __ mov(ecx, -1); // account for receiver
1175
1176 Label copy;
1177 __ bind(&copy);
1178 __ inc(ecx);
1179 __ push(Operand(eax, 0));
1180 __ sub(Operand(eax), Immediate(kPointerSize));
1181 __ cmp(ecx, Operand(ebx));
1182 __ j(less, &copy);
1183 __ jmp(&invoke);
1184 }
1185
1186 { // Too few parameters: Actual < expected.
1187 __ bind(&too_few);
1188 EnterArgumentsAdaptorFrame(masm);
1189
1190 // Copy receiver and all actual arguments.
1191 const int offset = StandardFrameConstants::kCallerSPOffset;
1192 __ lea(edi, Operand(ebp, eax, times_4, offset));
1193 __ mov(ecx, -1); // account for receiver
1194
1195 Label copy;
1196 __ bind(&copy);
1197 __ inc(ecx);
1198 __ push(Operand(edi, 0));
1199 __ sub(Operand(edi), Immediate(kPointerSize));
1200 __ cmp(ecx, Operand(eax));
1201 __ j(less, &copy);
1202
1203 // Fill remaining expected arguments with undefined values.
1204 Label fill;
1205 __ bind(&fill);
1206 __ inc(ecx);
1207 __ push(Immediate(Factory::undefined_value()));
1208 __ cmp(ecx, Operand(ebx));
1209 __ j(less, &fill);
1210
1211 // Restore function pointer.
1212 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1213 }
1214
1215 // Call the entry point.
1216 __ bind(&invoke);
1217 __ call(Operand(edx));
1218
1219 // Leave frame and return.
1220 LeaveArgumentsAdaptorFrame(masm);
1221 __ ret(0);
1222
1223 // -------------------------------------------
1224 // Dont adapt arguments.
1225 // -------------------------------------------
1226 __ bind(&dont_adapt_arguments);
1227 __ jmp(Operand(edx));
1228}
1229
1230
1231#undef __
1232
1233} } // namespace v8::internal