builtins-ia32.cc revision a7e24c173cf37484693b9abb38e494fa7bd7baeb
1// 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
1234