builtins-ia32.cc revision d0582a6c46733687d045e4188a1bcd0123c758a1
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::kGlobalContextOffset));
466    __ mov(ebx, FieldOperand(ebx, kGlobalIndex));
467    __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
468
469    __ bind(&patch_receiver);
470    __ mov(Operand(esp, eax, times_4, 0), ebx);
471
472    __ bind(&done);
473  }
474
475  // 4. Shift stuff one slot down the stack.
476  { Label loop;
477    __ lea(ecx, Operand(eax, +1));  // +1 ~ copy receiver too
478    __ bind(&loop);
479    __ mov(ebx, Operand(esp, ecx, times_4, 0));
480    __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
481    __ dec(ecx);
482    __ j(not_zero, &loop);
483  }
484
485  // 5. Remove TOS (copy of last arguments), but keep return address.
486  __ pop(ebx);
487  __ pop(ecx);
488  __ push(ebx);
489  __ dec(eax);
490
491  // 6. Check that function really was a function and get the code to
492  //    call from the function and check that the number of expected
493  //    arguments matches what we're providing.
494  { Label invoke;
495    __ test(edi, Operand(edi));
496    __ j(not_zero, &invoke, taken);
497    __ xor_(ebx, Operand(ebx));
498    __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
499    __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
500           RelocInfo::CODE_TARGET);
501
502    __ bind(&invoke);
503    __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
504    __ mov(ebx,
505           FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
506    __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset));
507    __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
508    __ cmp(eax, Operand(ebx));
509    __ j(not_equal, Handle<Code>(builtin(ArgumentsAdaptorTrampoline)));
510  }
511
512  // 7. Jump (tail-call) to the code in register edx without checking arguments.
513  ParameterCount expected(0);
514  __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION);
515}
516
517
518void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
519  __ EnterInternalFrame();
520
521  __ push(Operand(ebp, 4 * kPointerSize));  // push this
522  __ push(Operand(ebp, 2 * kPointerSize));  // push arguments
523  __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
524
525  // Check the stack for overflow. We are not trying need to catch
526  // interruptions (e.g. debug break and preemption) here, so the "real stack
527  // limit" is checked.
528  Label okay;
529  ExternalReference real_stack_limit =
530      ExternalReference::address_of_real_stack_limit();
531  __ mov(edi, Operand::StaticVariable(real_stack_limit));
532  // Make ecx the space we have left. The stack might already be overflowed
533  // here which will cause ecx to become negative.
534  __ mov(ecx, Operand(esp));
535  __ sub(ecx, Operand(edi));
536  // Make edx the space we need for the array when it is unrolled onto the
537  // stack.
538  __ mov(edx, Operand(eax));
539  __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
540  // Check if the arguments will overflow the stack.
541  __ cmp(ecx, Operand(edx));
542  __ j(greater, &okay, taken);  // Signed comparison.
543
544  // Out of stack space.
545  __ push(Operand(ebp, 4 * kPointerSize));  // push this
546  __ push(eax);
547  __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
548  __ bind(&okay);
549  // End of stack check.
550
551  // Push current index and limit.
552  const int kLimitOffset =
553      StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
554  const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
555  __ push(eax);  // limit
556  __ push(Immediate(0));  // index
557
558  // Change context eagerly to get the right global object if
559  // necessary.
560  __ mov(edi, Operand(ebp, 4 * kPointerSize));
561  __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
562
563  // Compute the receiver.
564  Label call_to_object, use_global_receiver, push_receiver;
565  __ mov(ebx, Operand(ebp, 3 * kPointerSize));
566  __ test(ebx, Immediate(kSmiTagMask));
567  __ j(zero, &call_to_object);
568  __ cmp(ebx, Factory::null_value());
569  __ j(equal, &use_global_receiver);
570  __ cmp(ebx, Factory::undefined_value());
571  __ j(equal, &use_global_receiver);
572
573  // If given receiver is already a JavaScript object then there's no
574  // reason for converting it.
575  __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
576  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
577  __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
578  __ j(less, &call_to_object);
579  __ cmp(ecx, LAST_JS_OBJECT_TYPE);
580  __ j(less_equal, &push_receiver);
581
582  // Convert the receiver to an object.
583  __ bind(&call_to_object);
584  __ push(ebx);
585  __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
586  __ mov(ebx, Operand(eax));
587  __ jmp(&push_receiver);
588
589  // Use the current global receiver object as the receiver.
590  __ bind(&use_global_receiver);
591  const int kGlobalOffset =
592      Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
593  __ mov(ebx, FieldOperand(esi, kGlobalOffset));
594  __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset));
595  __ mov(ebx, FieldOperand(ebx, kGlobalOffset));
596  __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
597
598  // Push the receiver.
599  __ bind(&push_receiver);
600  __ push(ebx);
601
602  // Copy all arguments from the array to the stack.
603  Label entry, loop;
604  __ mov(eax, Operand(ebp, kIndexOffset));
605  __ jmp(&entry);
606  __ bind(&loop);
607  __ mov(ecx, Operand(ebp, 2 * kPointerSize));  // load arguments
608  __ push(ecx);
609  __ push(eax);
610
611  // Use inline caching to speed up access to arguments.
612  Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
613  __ call(ic, RelocInfo::CODE_TARGET);
614  // It is important that we do not have a test instruction after the
615  // call.  A test instruction after the call is used to indicate that
616  // we have generated an inline version of the keyed load.  In this
617  // case, we know that we are not generating a test instruction next.
618
619  // Remove IC arguments from the stack and push the nth argument.
620  __ add(Operand(esp), Immediate(2 * kPointerSize));
621  __ push(eax);
622
623  // Update the index on the stack and in register eax.
624  __ mov(eax, Operand(ebp, kIndexOffset));
625  __ add(Operand(eax), Immediate(1 << kSmiTagSize));
626  __ mov(Operand(ebp, kIndexOffset), eax);
627
628  __ bind(&entry);
629  __ cmp(eax, Operand(ebp, kLimitOffset));
630  __ j(not_equal, &loop);
631
632  // Invoke the function.
633  ParameterCount actual(eax);
634  __ shr(eax, kSmiTagSize);
635  __ mov(edi, Operand(ebp, 4 * kPointerSize));
636  __ InvokeFunction(edi, actual, CALL_FUNCTION);
637
638  __ LeaveInternalFrame();
639  __ ret(3 * kPointerSize);  // remove this, receiver, and arguments
640}
641
642
643// Load the built-in Array function from the current context.
644static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) {
645  // Load the global context.
646  __ mov(result, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
647  __ mov(result, FieldOperand(result, GlobalObject::kGlobalContextOffset));
648  // Load the Array function from the global context.
649  __ mov(result,
650         Operand(result, Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
651}
652
653
654// Number of empty elements to allocate for an empty array.
655static const int kPreallocatedArrayElements = 4;
656
657
658// Allocate an empty JSArray. The allocated array is put into the result
659// register. If the parameter initial_capacity is larger than zero an elements
660// backing store is allocated with this size and filled with the hole values.
661// Otherwise the elements backing store is set to the empty FixedArray.
662static void AllocateEmptyJSArray(MacroAssembler* masm,
663                                 Register array_function,
664                                 Register result,
665                                 Register scratch1,
666                                 Register scratch2,
667                                 Register scratch3,
668                                 int initial_capacity,
669                                 Label* gc_required) {
670  ASSERT(initial_capacity >= 0);
671
672  // Load the initial map from the array function.
673  __ mov(scratch1, FieldOperand(array_function,
674                                JSFunction::kPrototypeOrInitialMapOffset));
675
676  // Allocate the JSArray object together with space for a fixed array with the
677  // requested elements.
678  int size = JSArray::kSize;
679  if (initial_capacity > 0) {
680    size += FixedArray::SizeFor(initial_capacity);
681  }
682  __ AllocateInNewSpace(size,
683                        result,
684                        scratch2,
685                        scratch3,
686                        gc_required,
687                        TAG_OBJECT);
688
689  // Allocated the JSArray. Now initialize the fields except for the elements
690  // array.
691  // result: JSObject
692  // scratch1: initial map
693  // scratch2: start of next object
694  __ mov(FieldOperand(result, JSObject::kMapOffset), scratch1);
695  __ mov(FieldOperand(result, JSArray::kPropertiesOffset),
696         Factory::empty_fixed_array());
697  // Field JSArray::kElementsOffset is initialized later.
698  __ mov(FieldOperand(result, JSArray::kLengthOffset), Immediate(0));
699
700  // If no storage is requested for the elements array just set the empty
701  // fixed array.
702  if (initial_capacity == 0) {
703    __ mov(FieldOperand(result, JSArray::kElementsOffset),
704           Factory::empty_fixed_array());
705    return;
706  }
707
708  // Calculate the location of the elements array and set elements array member
709  // of the JSArray.
710  // result: JSObject
711  // scratch2: start of next object
712  __ lea(scratch1, Operand(result, JSArray::kSize));
713  __ mov(FieldOperand(result, JSArray::kElementsOffset), scratch1);
714
715  // Initialize the FixedArray and fill it with holes. FixedArray length is not
716  // stored as a smi.
717  // result: JSObject
718  // scratch1: elements array
719  // scratch2: start of next object
720  __ mov(FieldOperand(scratch1, JSObject::kMapOffset),
721         Factory::fixed_array_map());
722  __ mov(FieldOperand(scratch1, Array::kLengthOffset),
723         Immediate(initial_capacity));
724
725  // Fill the FixedArray with the hole value. Inline the code if short.
726  // Reconsider loop unfolding if kPreallocatedArrayElements gets changed.
727  static const int kLoopUnfoldLimit = 4;
728  ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit);
729  if (initial_capacity <= kLoopUnfoldLimit) {
730    // Use a scratch register here to have only one reloc info when unfolding
731    // the loop.
732    __ mov(scratch3, Factory::the_hole_value());
733    for (int i = 0; i < initial_capacity; i++) {
734      __ mov(FieldOperand(scratch1,
735                          FixedArray::kHeaderSize + i * kPointerSize),
736             scratch3);
737    }
738  } else {
739    Label loop, entry;
740    __ jmp(&entry);
741    __ bind(&loop);
742    __ mov(Operand(scratch1, 0), Factory::the_hole_value());
743    __ add(Operand(scratch1), Immediate(kPointerSize));
744    __ bind(&entry);
745    __ cmp(scratch1, Operand(scratch2));
746    __ j(below, &loop);
747  }
748}
749
750
751// Allocate a JSArray with the number of elements stored in a register. The
752// register array_function holds the built-in Array function and the register
753// array_size holds the size of the array as a smi. The allocated array is put
754// into the result register and beginning and end of the FixedArray elements
755// storage is put into registers elements_array and elements_array_end  (see
756// below for when that is not the case). If the parameter fill_with_holes is
757// true the allocated elements backing store is filled with the hole values
758// otherwise it is left uninitialized. When the backing store is filled the
759// register elements_array is scratched.
760static void AllocateJSArray(MacroAssembler* masm,
761                            Register array_function,  // Array function.
762                            Register array_size,  // As a smi.
763                            Register result,
764                            Register elements_array,
765                            Register elements_array_end,
766                            Register scratch,
767                            bool fill_with_hole,
768                            Label* gc_required) {
769  Label not_empty, allocated;
770
771  // Load the initial map from the array function.
772  __ mov(elements_array,
773         FieldOperand(array_function,
774                      JSFunction::kPrototypeOrInitialMapOffset));
775
776  // Check whether an empty sized array is requested.
777  __ test(array_size, Operand(array_size));
778  __ j(not_zero, &not_empty);
779
780  // If an empty array is requested allocate a small elements array anyway. This
781  // keeps the code below free of special casing for the empty array.
782  int size = JSArray::kSize + FixedArray::SizeFor(kPreallocatedArrayElements);
783  __ AllocateInNewSpace(size,
784                        result,
785                        elements_array_end,
786                        scratch,
787                        gc_required,
788                        TAG_OBJECT);
789  __ jmp(&allocated);
790
791  // Allocate the JSArray object together with space for a FixedArray with the
792  // requested elements.
793  __ bind(&not_empty);
794  ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
795  __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
796                        times_half_pointer_size,  // array_size is a smi.
797                        array_size,
798                        result,
799                        elements_array_end,
800                        scratch,
801                        gc_required,
802                        TAG_OBJECT);
803
804  // Allocated the JSArray. Now initialize the fields except for the elements
805  // array.
806  // result: JSObject
807  // elements_array: initial map
808  // elements_array_end: start of next object
809  // array_size: size of array (smi)
810  __ bind(&allocated);
811  __ mov(FieldOperand(result, JSObject::kMapOffset), elements_array);
812  __ mov(elements_array, Factory::empty_fixed_array());
813  __ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
814  // Field JSArray::kElementsOffset is initialized later.
815  __ mov(FieldOperand(result, JSArray::kLengthOffset), array_size);
816
817  // Calculate the location of the elements array and set elements array member
818  // of the JSArray.
819  // result: JSObject
820  // elements_array_end: start of next object
821  // array_size: size of array (smi)
822  __ lea(elements_array, Operand(result, JSArray::kSize));
823  __ mov(FieldOperand(result, JSArray::kElementsOffset), elements_array);
824
825  // Initialize the fixed array. FixedArray length is not stored as a smi.
826  // result: JSObject
827  // elements_array: elements array
828  // elements_array_end: start of next object
829  // array_size: size of array (smi)
830  ASSERT(kSmiTag == 0);
831  __ shr(array_size, kSmiTagSize);  // Convert from smi to value.
832  __ mov(FieldOperand(elements_array, JSObject::kMapOffset),
833         Factory::fixed_array_map());
834  Label not_empty_2, fill_array;
835  __ test(array_size, Operand(array_size));
836  __ j(not_zero, &not_empty_2);
837  // Length of the FixedArray is the number of pre-allocated elements even
838  // though the actual JSArray has length 0.
839  __ mov(FieldOperand(elements_array, Array::kLengthOffset),
840         Immediate(kPreallocatedArrayElements));
841  __ jmp(&fill_array);
842  __ bind(&not_empty_2);
843  // For non-empty JSArrays the length of the FixedArray and the JSArray is the
844  // same.
845  __ mov(FieldOperand(elements_array, Array::kLengthOffset), array_size);
846
847  // Fill the allocated FixedArray with the hole value if requested.
848  // result: JSObject
849  // elements_array: elements array
850  // elements_array_end: start of next object
851  __ bind(&fill_array);
852  if (fill_with_hole) {
853    Label loop, entry;
854    __ mov(scratch, Factory::the_hole_value());
855    __ lea(elements_array, Operand(elements_array,
856                                   FixedArray::kHeaderSize - kHeapObjectTag));
857    __ jmp(&entry);
858    __ bind(&loop);
859    __ mov(Operand(elements_array, 0), scratch);
860    __ add(Operand(elements_array), Immediate(kPointerSize));
861    __ bind(&entry);
862    __ cmp(elements_array, Operand(elements_array_end));
863    __ j(below, &loop);
864  }
865}
866
867
868// Create a new array for the built-in Array function. This function allocates
869// the JSArray object and the FixedArray elements array and initializes these.
870// If the Array cannot be constructed in native code the runtime is called. This
871// function assumes the following state:
872//   edi: constructor (built-in Array function)
873//   eax: argc
874//   esp[0]: return address
875//   esp[4]: last argument
876// This function is used for both construct and normal calls of Array. Whether
877// it is a construct call or not is indicated by the construct_call parameter.
878// The only difference between handling a construct call and a normal call is
879// that for a construct call the constructor function in edi needs to be
880// preserved for entering the generic code. In both cases argc in eax needs to
881// be preserved.
882static void ArrayNativeCode(MacroAssembler* masm,
883                            bool construct_call,
884                            Label* call_generic_code) {
885  Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call;
886
887  // Push the constructor and argc. No need to tag argc as a smi, as there will
888  // be no garbage collection with this on the stack.
889  int push_count = 0;
890  if (construct_call) {
891    push_count++;
892    __ push(edi);
893  }
894  push_count++;
895  __ push(eax);
896
897  // Check for array construction with zero arguments.
898  __ test(eax, Operand(eax));
899  __ j(not_zero, &argc_one_or_more);
900
901  // Handle construction of an empty array.
902  AllocateEmptyJSArray(masm,
903                       edi,
904                       eax,
905                       ebx,
906                       ecx,
907                       edi,
908                       kPreallocatedArrayElements,
909                       &prepare_generic_code_call);
910  __ IncrementCounter(&Counters::array_function_native, 1);
911  __ pop(ebx);
912  if (construct_call) {
913    __ pop(edi);
914  }
915  __ ret(kPointerSize);
916
917  // Check for one argument. Bail out if argument is not smi or if it is
918  // negative.
919  __ bind(&argc_one_or_more);
920  __ cmp(eax, 1);
921  __ j(not_equal, &argc_two_or_more);
922  ASSERT(kSmiTag == 0);
923  __ test(Operand(esp, (push_count + 1) * kPointerSize),
924          Immediate(kIntptrSignBit | kSmiTagMask));
925  __ j(not_zero, &prepare_generic_code_call);
926
927  // Handle construction of an empty array of a certain size. Get the size from
928  // the stack and bail out if size is to large to actually allocate an elements
929  // array.
930  __ mov(edx, Operand(esp, (push_count + 1) * kPointerSize));
931  ASSERT(kSmiTag == 0);
932  __ cmp(edx, JSObject::kInitialMaxFastElementArray << kSmiTagSize);
933  __ j(greater_equal, &prepare_generic_code_call);
934
935  // edx: array_size (smi)
936  // edi: constructor
937  // esp[0]: argc
938  // esp[4]: constructor (only if construct_call)
939  // esp[8]: return address
940  // esp[C]: argument
941  AllocateJSArray(masm,
942                  edi,
943                  edx,
944                  eax,
945                  ebx,
946                  ecx,
947                  edi,
948                  true,
949                  &prepare_generic_code_call);
950  __ IncrementCounter(&Counters::array_function_native, 1);
951  __ pop(ebx);
952  if (construct_call) {
953    __ pop(edi);
954  }
955  __ ret(2 * kPointerSize);
956
957  // Handle construction of an array from a list of arguments.
958  __ bind(&argc_two_or_more);
959  ASSERT(kSmiTag == 0);
960  __ shl(eax, kSmiTagSize);  // Convet argc to a smi.
961  // eax: array_size (smi)
962  // edi: constructor
963  // esp[0] : argc
964  // esp[4]: constructor (only if construct_call)
965  // esp[8] : return address
966  // esp[C] : last argument
967  AllocateJSArray(masm,
968                  edi,
969                  eax,
970                  ebx,
971                  ecx,
972                  edx,
973                  edi,
974                  false,
975                  &prepare_generic_code_call);
976  __ IncrementCounter(&Counters::array_function_native, 1);
977  __ mov(eax, ebx);
978  __ pop(ebx);
979  if (construct_call) {
980    __ pop(edi);
981  }
982  __ push(eax);
983  // eax: JSArray
984  // ebx: argc
985  // edx: elements_array_end (untagged)
986  // esp[0]: JSArray
987  // esp[4]: return address
988  // esp[8]: last argument
989
990  // Location of the last argument
991  __ lea(edi, Operand(esp, 2 * kPointerSize));
992
993  // Location of the first array element (Parameter fill_with_holes to
994  // AllocateJSArrayis false, so the FixedArray is returned in ecx).
995  __ lea(edx, Operand(ecx, FixedArray::kHeaderSize - kHeapObjectTag));
996
997  // ebx: argc
998  // edx: location of the first array element
999  // edi: location of the last argument
1000  // esp[0]: JSArray
1001  // esp[4]: return address
1002  // esp[8]: last argument
1003  Label loop, entry;
1004  __ mov(ecx, ebx);
1005  __ jmp(&entry);
1006  __ bind(&loop);
1007  __ mov(eax, Operand(edi, ecx, times_pointer_size, 0));
1008  __ mov(Operand(edx, 0), eax);
1009  __ add(Operand(edx), Immediate(kPointerSize));
1010  __ bind(&entry);
1011  __ dec(ecx);
1012  __ j(greater_equal, &loop);
1013
1014  // Remove caller arguments from the stack and return.
1015  // ebx: argc
1016  // esp[0]: JSArray
1017  // esp[4]: return address
1018  // esp[8]: last argument
1019  __ pop(eax);
1020  __ pop(ecx);
1021  __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
1022  __ push(ecx);
1023  __ ret(0);
1024
1025  // Restore argc and constructor before running the generic code.
1026  __ bind(&prepare_generic_code_call);
1027  __ pop(eax);
1028  if (construct_call) {
1029    __ pop(edi);
1030  }
1031  __ jmp(call_generic_code);
1032}
1033
1034
1035void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1036  // ----------- S t a t e -------------
1037  //  -- eax : argc
1038  //  -- esp[0] : return address
1039  //  -- esp[4] : last argument
1040  // -----------------------------------
1041  Label generic_array_code, one_or_more_arguments, two_or_more_arguments;
1042
1043  // Get the Array function.
1044  GenerateLoadArrayFunction(masm, edi);
1045
1046  if (FLAG_debug_code) {
1047    // Initial map for the builtin Array function shoud be a map.
1048    __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1049    // Will both indicate a NULL and a Smi.
1050    __ test(ebx, Immediate(kSmiTagMask));
1051    __ Assert(not_zero, "Unexpected initial map for Array function");
1052    __ CmpObjectType(ebx, MAP_TYPE, ecx);
1053    __ Assert(equal, "Unexpected initial map for Array function");
1054  }
1055
1056  // Run the native code for the Array function called as a normal function.
1057  ArrayNativeCode(masm, false, &generic_array_code);
1058
1059  // Jump to the generic array code in case the specialized code cannot handle
1060  // the construction.
1061  __ bind(&generic_array_code);
1062  Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric);
1063  Handle<Code> array_code(code);
1064  __ jmp(array_code, RelocInfo::CODE_TARGET);
1065}
1066
1067
1068void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
1069  // ----------- S t a t e -------------
1070  //  -- eax : argc
1071  //  -- edi : constructor
1072  //  -- esp[0] : return address
1073  //  -- esp[4] : last argument
1074  // -----------------------------------
1075  Label generic_constructor;
1076
1077  if (FLAG_debug_code) {
1078    // The array construct code is only set for the builtin Array function which
1079    // does always have a map.
1080    GenerateLoadArrayFunction(masm, ebx);
1081    __ cmp(edi, Operand(ebx));
1082    __ Assert(equal, "Unexpected Array function");
1083    // Initial map for the builtin Array function should be a map.
1084    __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1085    // Will both indicate a NULL and a Smi.
1086    __ test(ebx, Immediate(kSmiTagMask));
1087    __ Assert(not_zero, "Unexpected initial map for Array function");
1088    __ CmpObjectType(ebx, MAP_TYPE, ecx);
1089    __ Assert(equal, "Unexpected initial map for Array function");
1090  }
1091
1092  // Run the native code for the Array function called as constructor.
1093  ArrayNativeCode(masm, true, &generic_constructor);
1094
1095  // Jump to the generic construct code in case the specialized code cannot
1096  // handle the construction.
1097  __ bind(&generic_constructor);
1098  Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
1099  Handle<Code> generic_construct_stub(code);
1100  __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
1101}
1102
1103
1104static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1105  __ push(ebp);
1106  __ mov(ebp, Operand(esp));
1107
1108  // Store the arguments adaptor context sentinel.
1109  __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1110
1111  // Push the function on the stack.
1112  __ push(edi);
1113
1114  // Preserve the number of arguments on the stack. Must preserve both
1115  // eax and ebx because these registers are used when copying the
1116  // arguments and the receiver.
1117  ASSERT(kSmiTagSize == 1);
1118  __ lea(ecx, Operand(eax, eax, times_1, kSmiTag));
1119  __ push(ecx);
1120}
1121
1122
1123static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1124  // Retrieve the number of arguments from the stack.
1125  __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1126
1127  // Leave the frame.
1128  __ leave();
1129
1130  // Remove caller arguments from the stack.
1131  ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
1132  __ pop(ecx);
1133  __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize));  // 1 ~ receiver
1134  __ push(ecx);
1135}
1136
1137
1138void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1139  // ----------- S t a t e -------------
1140  //  -- eax : actual number of arguments
1141  //  -- ebx : expected number of arguments
1142  //  -- edx : code entry to call
1143  // -----------------------------------
1144
1145  Label invoke, dont_adapt_arguments;
1146  __ IncrementCounter(&Counters::arguments_adaptors, 1);
1147
1148  Label enough, too_few;
1149  __ cmp(eax, Operand(ebx));
1150  __ j(less, &too_few);
1151  __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1152  __ j(equal, &dont_adapt_arguments);
1153
1154  {  // Enough parameters: Actual >= expected.
1155    __ bind(&enough);
1156    EnterArgumentsAdaptorFrame(masm);
1157
1158    // Copy receiver and all expected arguments.
1159    const int offset = StandardFrameConstants::kCallerSPOffset;
1160    __ lea(eax, Operand(ebp, eax, times_4, offset));
1161    __ mov(ecx, -1);  // account for receiver
1162
1163    Label copy;
1164    __ bind(&copy);
1165    __ inc(ecx);
1166    __ push(Operand(eax, 0));
1167    __ sub(Operand(eax), Immediate(kPointerSize));
1168    __ cmp(ecx, Operand(ebx));
1169    __ j(less, &copy);
1170    __ jmp(&invoke);
1171  }
1172
1173  {  // Too few parameters: Actual < expected.
1174    __ bind(&too_few);
1175    EnterArgumentsAdaptorFrame(masm);
1176
1177    // Copy receiver and all actual arguments.
1178    const int offset = StandardFrameConstants::kCallerSPOffset;
1179    __ lea(edi, Operand(ebp, eax, times_4, offset));
1180    __ mov(ecx, -1);  // account for receiver
1181
1182    Label copy;
1183    __ bind(&copy);
1184    __ inc(ecx);
1185    __ push(Operand(edi, 0));
1186    __ sub(Operand(edi), Immediate(kPointerSize));
1187    __ cmp(ecx, Operand(eax));
1188    __ j(less, &copy);
1189
1190    // Fill remaining expected arguments with undefined values.
1191    Label fill;
1192    __ bind(&fill);
1193    __ inc(ecx);
1194    __ push(Immediate(Factory::undefined_value()));
1195    __ cmp(ecx, Operand(ebx));
1196    __ j(less, &fill);
1197
1198    // Restore function pointer.
1199    __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1200  }
1201
1202  // Call the entry point.
1203  __ bind(&invoke);
1204  __ call(Operand(edx));
1205
1206  // Leave frame and return.
1207  LeaveArgumentsAdaptorFrame(masm);
1208  __ ret(0);
1209
1210  // -------------------------------------------
1211  // Dont adapt arguments.
1212  // -------------------------------------------
1213  __ bind(&dont_adapt_arguments);
1214  __ jmp(Operand(edx));
1215}
1216
1217
1218#undef __
1219
1220} }  // namespace v8::internal
1221