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