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