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