• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Generate_Adaptor(MacroAssembler * masm,CFunctionId id)37 void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) {
38   // TODO(428): Don't pass the function in a static variable.
39   ExternalReference passed = ExternalReference::builtin_passed_function();
40   __ movq(kScratchRegister, passed.address(), RelocInfo::EXTERNAL_REFERENCE);
41   __ movq(Operand(kScratchRegister, 0), rdi);
42 
43   // The actual argument count has already been loaded into register
44   // rax, but JumpToBuiltin expects rax to contain the number of
45   // arguments including the receiver.
46   __ incq(rax);
47   __ JumpToBuiltin(ExternalReference(id));
48 }
49 
50 
EnterArgumentsAdaptorFrame(MacroAssembler * masm)51 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
52   __ push(rbp);
53   __ movq(rbp, rsp);
54 
55   // Store the arguments adaptor context sentinel.
56   __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
57 
58   // Push the function on the stack.
59   __ push(rdi);
60 
61   // Preserve the number of arguments on the stack. Must preserve both
62   // rax and rbx because these registers are used when copying the
63   // arguments and the receiver.
64   ASSERT(kSmiTagSize == 1);
65   __ lea(rcx, Operand(rax, rax, times_1, kSmiTag));
66   __ push(rcx);
67 }
68 
69 
LeaveArgumentsAdaptorFrame(MacroAssembler * masm)70 static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
71   // Retrieve the number of arguments from the stack. Number is a Smi.
72   __ movq(rbx, Operand(rbp, ArgumentsAdaptorFrameConstants::kLengthOffset));
73 
74   // Leave the frame.
75   __ movq(rsp, rbp);
76   __ pop(rbp);
77 
78   // Remove caller arguments from the stack.
79   // rbx holds a Smi, so we convery to dword offset by multiplying by 4.
80   ASSERT_EQ(kSmiTagSize, 1 && kSmiTag == 0);
81   ASSERT_EQ(kPointerSize, (1 << kSmiTagSize) * 4);
82   __ pop(rcx);
83   __ lea(rsp, Operand(rsp, rbx, times_4, 1 * kPointerSize));  // 1 ~ receiver
84   __ push(rcx);
85 }
86 
87 
Generate_ArgumentsAdaptorTrampoline(MacroAssembler * masm)88 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
89   // ----------- S t a t e -------------
90   //  -- rax : actual number of arguments
91   //  -- rbx : expected number of arguments
92   //  -- rdx : code entry to call
93   // -----------------------------------
94 
95   Label invoke, dont_adapt_arguments;
96   __ IncrementCounter(&Counters::arguments_adaptors, 1);
97 
98   Label enough, too_few;
99   __ cmpq(rax, rbx);
100   __ j(less, &too_few);
101   __ cmpq(rbx, Immediate(SharedFunctionInfo::kDontAdaptArgumentsSentinel));
102   __ j(equal, &dont_adapt_arguments);
103 
104   {  // Enough parameters: Actual >= expected.
105     __ bind(&enough);
106     EnterArgumentsAdaptorFrame(masm);
107 
108     // Copy receiver and all expected arguments.
109     const int offset = StandardFrameConstants::kCallerSPOffset;
110     __ lea(rax, Operand(rbp, rax, times_pointer_size, offset));
111     __ movq(rcx, Immediate(-1));  // account for receiver
112 
113     Label copy;
114     __ bind(&copy);
115     __ incq(rcx);
116     __ push(Operand(rax, 0));
117     __ subq(rax, Immediate(kPointerSize));
118     __ cmpq(rcx, rbx);
119     __ j(less, &copy);
120     __ jmp(&invoke);
121   }
122 
123   {  // Too few parameters: Actual < expected.
124     __ bind(&too_few);
125     EnterArgumentsAdaptorFrame(masm);
126 
127     // Copy receiver and all actual arguments.
128     const int offset = StandardFrameConstants::kCallerSPOffset;
129     __ lea(rdi, Operand(rbp, rax, times_pointer_size, offset));
130     __ movq(rcx, Immediate(-1));  // account for receiver
131 
132     Label copy;
133     __ bind(&copy);
134     __ incq(rcx);
135     __ push(Operand(rdi, 0));
136     __ subq(rdi, Immediate(kPointerSize));
137     __ cmpq(rcx, rax);
138     __ j(less, &copy);
139 
140     // Fill remaining expected arguments with undefined values.
141     Label fill;
142     __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
143     __ bind(&fill);
144     __ incq(rcx);
145     __ push(kScratchRegister);
146     __ cmpq(rcx, rbx);
147     __ j(less, &fill);
148 
149     // Restore function pointer.
150     __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
151   }
152 
153   // Call the entry point.
154   __ bind(&invoke);
155   __ call(rdx);
156 
157   // Leave frame and return.
158   LeaveArgumentsAdaptorFrame(masm);
159   __ ret(0);
160 
161   // -------------------------------------------
162   // Dont adapt arguments.
163   // -------------------------------------------
164   __ bind(&dont_adapt_arguments);
165   __ jmp(rdx);
166 }
167 
168 
Generate_FunctionCall(MacroAssembler * masm)169 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
170   // Stack Layout:
171   // rsp: return address
172   //  +1: Argument n
173   //  +2: Argument n-1
174   //  ...
175   //  +n: Argument 1 = receiver
176   //  +n+1: Argument 0 = function to call
177   //
178   // rax contains the number of arguments, n, not counting the function.
179   //
180   // 1. Make sure we have at least one argument.
181   { Label done;
182     __ testq(rax, rax);
183     __ j(not_zero, &done);
184     __ pop(rbx);
185     __ Push(Factory::undefined_value());
186     __ push(rbx);
187     __ incq(rax);
188     __ bind(&done);
189   }
190 
191   // 2. Get the function to call from the stack.
192   { Label done, non_function, function;
193     // The function to call is at position n+1 on the stack.
194     __ movq(rdi, Operand(rsp, rax, times_pointer_size, +1 * kPointerSize));
195     __ testl(rdi, Immediate(kSmiTagMask));
196     __ j(zero, &non_function);
197     __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
198     __ j(equal, &function);
199 
200     // Non-function called: Clear the function to force exception.
201     __ bind(&non_function);
202     __ xor_(rdi, rdi);
203     __ jmp(&done);
204 
205     // Function called: Change context eagerly to get the right global object.
206     __ bind(&function);
207     __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
208 
209     __ bind(&done);
210   }
211 
212   // 3. Make sure first argument is an object; convert if necessary.
213   { Label call_to_object, use_global_receiver, patch_receiver, done;
214     __ movq(rbx, Operand(rsp, rax, times_pointer_size, 0));
215 
216     __ testl(rbx, Immediate(kSmiTagMask));
217     __ j(zero, &call_to_object);
218 
219     __ CompareRoot(rbx, Heap::kNullValueRootIndex);
220     __ j(equal, &use_global_receiver);
221     __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
222     __ j(equal, &use_global_receiver);
223 
224     __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, rcx);
225     __ j(below, &call_to_object);
226     __ CmpInstanceType(rcx, LAST_JS_OBJECT_TYPE);
227     __ j(below_equal, &done);
228 
229     __ bind(&call_to_object);
230     __ EnterInternalFrame();  // preserves rax, rbx, rdi
231 
232     // Store the arguments count on the stack (smi tagged).
233     ASSERT(kSmiTag == 0);
234     __ shl(rax, Immediate(kSmiTagSize));
235     __ push(rax);
236 
237     __ push(rdi);  // save edi across the call
238     __ push(rbx);
239     __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
240     __ movq(rbx, rax);
241     __ pop(rdi);  // restore edi after the call
242 
243     // Get the arguments count and untag it.
244     __ pop(rax);
245     __ shr(rax, Immediate(kSmiTagSize));
246 
247     __ LeaveInternalFrame();
248     __ jmp(&patch_receiver);
249 
250     // Use the global receiver object from the called function as the receiver.
251     __ bind(&use_global_receiver);
252     const int kGlobalIndex =
253         Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
254     __ movq(rbx, FieldOperand(rsi, kGlobalIndex));
255     __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
256 
257     __ bind(&patch_receiver);
258     __ movq(Operand(rsp, rax, times_pointer_size, 0), rbx);
259 
260     __ bind(&done);
261   }
262 
263   // 4. Shift stuff one slot down the stack.
264   { Label loop;
265     __ lea(rcx, Operand(rax, +1));  // +1 ~ copy receiver too
266     __ bind(&loop);
267     __ movq(rbx, Operand(rsp, rcx, times_pointer_size, 0));
268     __ movq(Operand(rsp, rcx, times_pointer_size, 1 * kPointerSize), rbx);
269     __ decq(rcx);
270     __ j(not_zero, &loop);
271   }
272 
273   // 5. Remove TOS (copy of last arguments), but keep return address.
274   __ pop(rbx);
275   __ pop(rcx);
276   __ push(rbx);
277   __ decq(rax);
278 
279   // 6. Check that function really was a function and get the code to
280   //    call from the function and check that the number of expected
281   //    arguments matches what we're providing.
282   { Label invoke, trampoline;
283     __ testq(rdi, rdi);
284     __ j(not_zero, &invoke);
285     __ xor_(rbx, rbx);
286     __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
287     __ bind(&trampoline);
288     __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
289             RelocInfo::CODE_TARGET);
290 
291     __ bind(&invoke);
292     __ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
293     __ movsxlq(rbx,
294            FieldOperand(rdx, SharedFunctionInfo::kFormalParameterCountOffset));
295     __ movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kCodeOffset));
296     __ lea(rdx, FieldOperand(rdx, Code::kHeaderSize));
297     __ cmpq(rax, rbx);
298     __ j(not_equal, &trampoline);
299   }
300 
301   // 7. Jump (tail-call) to the code in register edx without checking arguments.
302   ParameterCount expected(0);
303   __ InvokeCode(rdx, expected, expected, JUMP_FUNCTION);
304 }
305 
306 
Generate_FunctionApply(MacroAssembler * masm)307 void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
308   // Stack at entry:
309   //    rsp: return address
310   //  rsp+8: arguments
311   // rsp+16: receiver ("this")
312   // rsp+24: function
313   __ EnterInternalFrame();
314   // Stack frame:
315   //    rbp: Old base pointer
316   // rbp[1]: return address
317   // rbp[2]: function arguments
318   // rbp[3]: receiver
319   // rbp[4]: function
320   static const int kArgumentsOffset = 2 * kPointerSize;
321   static const int kReceiverOffset = 3 * kPointerSize;
322   static const int kFunctionOffset = 4 * kPointerSize;
323   __ push(Operand(rbp, kFunctionOffset));
324   __ push(Operand(rbp, kArgumentsOffset));
325   __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
326 
327   if (FLAG_check_stack) {
328     // We need to catch preemptions right here, otherwise an unlucky preemption
329     // could show up as a failed apply.
330     Label retry_preemption;
331     Label no_preemption;
332     __ bind(&retry_preemption);
333     ExternalReference stack_guard_limit =
334         ExternalReference::address_of_stack_guard_limit();
335     __ movq(kScratchRegister, stack_guard_limit);
336     __ movq(rcx, rsp);
337     __ subq(rcx, Operand(kScratchRegister, 0));
338     // rcx contains the difference between the stack limit and the stack top.
339     // We use it below to check that there is enough room for the arguments.
340     __ j(above, &no_preemption);
341 
342     // Preemption!
343     // Because runtime functions always remove the receiver from the stack, we
344     // have to fake one to avoid underflowing the stack.
345     __ push(rax);
346     __ push(Immediate(Smi::FromInt(0)));
347 
348     // Do call to runtime routine.
349     __ CallRuntime(Runtime::kStackGuard, 1);
350     __ pop(rax);
351     __ jmp(&retry_preemption);
352 
353     __ bind(&no_preemption);
354 
355     Label okay;
356     // Make rdx the space we need for the array when it is unrolled onto the
357     // stack.
358     __ movq(rdx, rax);
359     __ shl(rdx, Immediate(kPointerSizeLog2 - kSmiTagSize));
360     __ cmpq(rcx, rdx);
361     __ j(greater, &okay);
362 
363     // Too bad: Out of stack space.
364     __ push(Operand(rbp, kFunctionOffset));
365     __ push(rax);
366     __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
367     __ bind(&okay);
368   }
369 
370   // Push current index and limit.
371   const int kLimitOffset =
372       StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
373   const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
374   __ push(rax);  // limit
375   __ push(Immediate(0));  // index
376 
377   // Change context eagerly to get the right global object if
378   // necessary.
379   __ movq(rdi, Operand(rbp, kFunctionOffset));
380   __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
381 
382   // Compute the receiver.
383   Label call_to_object, use_global_receiver, push_receiver;
384   __ movq(rbx, Operand(rbp, kReceiverOffset));
385   __ testl(rbx, Immediate(kSmiTagMask));
386   __ j(zero, &call_to_object);
387   __ CompareRoot(rbx, Heap::kNullValueRootIndex);
388   __ j(equal, &use_global_receiver);
389   __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
390   __ j(equal, &use_global_receiver);
391 
392   // If given receiver is already a JavaScript object then there's no
393   // reason for converting it.
394   __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, rcx);
395   __ j(below, &call_to_object);
396   __ CmpInstanceType(rcx, LAST_JS_OBJECT_TYPE);
397   __ j(below_equal, &push_receiver);
398 
399   // Convert the receiver to an object.
400   __ bind(&call_to_object);
401   __ push(rbx);
402   __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
403   __ movq(rbx, rax);
404   __ jmp(&push_receiver);
405 
406   // Use the current global receiver object as the receiver.
407   __ bind(&use_global_receiver);
408   const int kGlobalOffset =
409       Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
410   __ movq(rbx, FieldOperand(rsi, kGlobalOffset));
411   __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
412 
413   // Push the receiver.
414   __ bind(&push_receiver);
415   __ push(rbx);
416 
417   // Copy all arguments from the array to the stack.
418   Label entry, loop;
419   __ movq(rax, Operand(rbp, kIndexOffset));
420   __ jmp(&entry);
421   __ bind(&loop);
422   __ movq(rcx, Operand(rbp, kArgumentsOffset));  // load arguments
423   __ push(rcx);
424   __ push(rax);
425 
426   // Use inline caching to speed up access to arguments.
427   Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
428   __ Call(ic, RelocInfo::CODE_TARGET);
429   // It is important that we do not have a test instruction after the
430   // call.  A test instruction after the call is used to indicate that
431   // we have generated an inline version of the keyed load.  In this
432   // case, we know that we are not generating a test instruction next.
433 
434   // Remove IC arguments from the stack and push the nth argument.
435   __ addq(rsp, Immediate(2 * kPointerSize));
436   __ push(rax);
437 
438   // Update the index on the stack and in register rax.
439   __ movq(rax, Operand(rbp, kIndexOffset));
440   __ addq(rax, Immediate(Smi::FromInt(1)));
441   __ movq(Operand(rbp, kIndexOffset), rax);
442 
443   __ bind(&entry);
444   __ cmpq(rax, Operand(rbp, kLimitOffset));
445   __ j(not_equal, &loop);
446 
447   // Invoke the function.
448   ParameterCount actual(rax);
449   __ shr(rax, Immediate(kSmiTagSize));
450   __ movq(rdi, Operand(rbp, kFunctionOffset));
451   __ InvokeFunction(rdi, actual, CALL_FUNCTION);
452 
453   __ LeaveInternalFrame();
454   __ ret(3 * kPointerSize);  // remove function, receiver, and arguments
455 }
456 
457 
Generate_JSConstructCall(MacroAssembler * masm)458 void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
459   // ----------- S t a t e -------------
460   //  -- rax: number of arguments
461   //  -- rdi: constructor function
462   // -----------------------------------
463 
464   Label non_function_call;
465   // Check that function is not a smi.
466   __ testl(rdi, Immediate(kSmiTagMask));
467   __ j(zero, &non_function_call);
468   // Check that function is a JSFunction.
469   __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
470   __ j(not_equal, &non_function_call);
471 
472   // Jump to the function-specific construct stub.
473   __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
474   __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kConstructStubOffset));
475   __ lea(rbx, FieldOperand(rbx, Code::kHeaderSize));
476   __ jmp(rbx);
477 
478   // edi: called object
479   // eax: number of arguments
480   __ bind(&non_function_call);
481 
482   // Set expected number of arguments to zero (not changing eax).
483   __ movq(rbx, Immediate(0));
484   __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
485   __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
486           RelocInfo::CODE_TARGET);
487 }
488 
489 
Generate_JSConstructStubGeneric(MacroAssembler * masm)490 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
491     // Enter a construct frame.
492   __ EnterConstructFrame();
493 
494   // Store a smi-tagged arguments count on the stack.
495   __ shl(rax, Immediate(kSmiTagSize));
496   __ push(rax);
497 
498   // Push the function to invoke on the stack.
499   __ push(rdi);
500 
501   // Try to allocate the object without transitioning into C code. If any of the
502   // preconditions is not met, the code bails out to the runtime call.
503   Label rt_call, allocated;
504   if (FLAG_inline_new) {
505     Label undo_allocation;
506 
507 #ifdef ENABLE_DEBUGGER_SUPPORT
508     ExternalReference debug_step_in_fp =
509         ExternalReference::debug_step_in_fp_address();
510     __ movq(kScratchRegister, debug_step_in_fp);
511     __ cmpq(Operand(kScratchRegister, 0), Immediate(0));
512     __ j(not_equal, &rt_call);
513 #endif
514 
515     // Verified that the constructor is a JSFunction.
516     // Load the initial map and verify that it is in fact a map.
517     // rdi: constructor
518     __ movq(rax, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
519     // Will both indicate a NULL and a Smi
520     __ testl(rax, Immediate(kSmiTagMask));
521     __ j(zero, &rt_call);
522     // rdi: constructor
523     // rax: initial map (if proven valid below)
524     __ CmpObjectType(rax, MAP_TYPE, rbx);
525     __ j(not_equal, &rt_call);
526 
527     // Check that the constructor is not constructing a JSFunction (see comments
528     // in Runtime_NewObject in runtime.cc). In which case the initial map's
529     // instance type would be JS_FUNCTION_TYPE.
530     // rdi: constructor
531     // rax: initial map
532     __ CmpInstanceType(rax, JS_FUNCTION_TYPE);
533     __ j(equal, &rt_call);
534 
535     // Now allocate the JSObject on the heap.
536     __ movzxbq(rdi, FieldOperand(rax, Map::kInstanceSizeOffset));
537     __ shl(rdi, Immediate(kPointerSizeLog2));
538     // rdi: size of new object
539     __ AllocateObjectInNewSpace(rdi,
540                                 rbx,
541                                 rdi,
542                                 no_reg,
543                                 &rt_call,
544                                 NO_ALLOCATION_FLAGS);
545     // Allocated the JSObject, now initialize the fields.
546     // rax: initial map
547     // rbx: JSObject (not HeapObject tagged - the actual address).
548     // rdi: start of next object
549     __ movq(Operand(rbx, JSObject::kMapOffset), rax);
550     __ LoadRoot(rcx, Heap::kEmptyFixedArrayRootIndex);
551     __ movq(Operand(rbx, JSObject::kPropertiesOffset), rcx);
552     __ movq(Operand(rbx, JSObject::kElementsOffset), rcx);
553     // Set extra fields in the newly allocated object.
554     // rax: initial map
555     // rbx: JSObject
556     // rdi: start of next object
557     { Label loop, entry;
558       __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
559       __ lea(rcx, Operand(rbx, JSObject::kHeaderSize));
560       __ jmp(&entry);
561       __ bind(&loop);
562       __ movq(Operand(rcx, 0), rdx);
563       __ addq(rcx, Immediate(kPointerSize));
564       __ bind(&entry);
565       __ cmpq(rcx, rdi);
566       __ j(less, &loop);
567     }
568 
569     // Add the object tag to make the JSObject real, so that we can continue and
570     // jump into the continuation code at any time from now on. Any failures
571     // need to undo the allocation, so that the heap is in a consistent state
572     // and verifiable.
573     // rax: initial map
574     // rbx: JSObject
575     // rdi: start of next object
576     __ or_(rbx, Immediate(kHeapObjectTag));
577 
578     // Check if a non-empty properties array is needed.
579     // Allocate and initialize a FixedArray if it is.
580     // rax: initial map
581     // rbx: JSObject
582     // rdi: start of next object
583     // Calculate total properties described map.
584     __ movzxbq(rdx, FieldOperand(rax, Map::kUnusedPropertyFieldsOffset));
585     __ movzxbq(rcx, FieldOperand(rax, Map::kPreAllocatedPropertyFieldsOffset));
586     __ addq(rdx, rcx);
587     // Calculate unused properties past the end of the in-object properties.
588     __ movzxbq(rcx, FieldOperand(rax, Map::kInObjectPropertiesOffset));
589     __ subq(rdx, rcx);
590     // Done if no extra properties are to be allocated.
591     __ j(zero, &allocated);
592     __ Assert(positive, "Property allocation count failed.");
593 
594     // Scale the number of elements by pointer size and add the header for
595     // FixedArrays to the start of the next object calculation from above.
596     // rbx: JSObject
597     // rdi: start of next object (will be start of FixedArray)
598     // rdx: number of elements in properties array
599     __ AllocateObjectInNewSpace(FixedArray::kHeaderSize,
600                                 times_pointer_size,
601                                 rdx,
602                                 rdi,
603                                 rax,
604                                 no_reg,
605                                 &undo_allocation,
606                                 RESULT_CONTAINS_TOP);
607 
608     // Initialize the FixedArray.
609     // rbx: JSObject
610     // rdi: FixedArray
611     // rdx: number of elements
612     // rax: start of next object
613     __ LoadRoot(rcx, Heap::kFixedArrayMapRootIndex);
614     __ movq(Operand(rdi, JSObject::kMapOffset), rcx);  // setup the map
615     __ movl(Operand(rdi, FixedArray::kLengthOffset), rdx);  // and length
616 
617     // Initialize the fields to undefined.
618     // rbx: JSObject
619     // rdi: FixedArray
620     // rax: start of next object
621     // rdx: number of elements
622     { Label loop, entry;
623       __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
624       __ lea(rcx, Operand(rdi, FixedArray::kHeaderSize));
625       __ jmp(&entry);
626       __ bind(&loop);
627       __ movq(Operand(rcx, 0), rdx);
628       __ addq(rcx, Immediate(kPointerSize));
629       __ bind(&entry);
630       __ cmpq(rcx, rax);
631       __ j(below, &loop);
632     }
633 
634     // Store the initialized FixedArray into the properties field of
635     // the JSObject
636     // rbx: JSObject
637     // rdi: FixedArray
638     __ or_(rdi, Immediate(kHeapObjectTag));  // add the heap tag
639     __ movq(FieldOperand(rbx, JSObject::kPropertiesOffset), rdi);
640 
641 
642     // Continue with JSObject being successfully allocated
643     // rbx: JSObject
644     __ jmp(&allocated);
645 
646     // Undo the setting of the new top so that the heap is verifiable. For
647     // example, the map's unused properties potentially do not match the
648     // allocated objects unused properties.
649     // rbx: JSObject (previous new top)
650     __ bind(&undo_allocation);
651     __ UndoAllocationInNewSpace(rbx);
652   }
653 
654   // Allocate the new receiver object using the runtime call.
655   // rdi: function (constructor)
656   __ bind(&rt_call);
657   // Must restore rdi (constructor) before calling runtime.
658   __ movq(rdi, Operand(rsp, 0));
659   __ push(rdi);
660   __ CallRuntime(Runtime::kNewObject, 1);
661   __ movq(rbx, rax);  // store result in rbx
662 
663   // New object allocated.
664   // rbx: newly allocated object
665   __ bind(&allocated);
666   // Retrieve the function from the stack.
667   __ pop(rdi);
668 
669   // Retrieve smi-tagged arguments count from the stack.
670   __ movq(rax, Operand(rsp, 0));
671   __ shr(rax, Immediate(kSmiTagSize));
672 
673   // Push the allocated receiver to the stack. We need two copies
674   // because we may have to return the original one and the calling
675   // conventions dictate that the called function pops the receiver.
676   __ push(rbx);
677   __ push(rbx);
678 
679   // Setup pointer to last argument.
680   __ lea(rbx, Operand(rbp, StandardFrameConstants::kCallerSPOffset));
681 
682   // Copy arguments and receiver to the expression stack.
683   Label loop, entry;
684   __ movq(rcx, rax);
685   __ jmp(&entry);
686   __ bind(&loop);
687   __ push(Operand(rbx, rcx, times_pointer_size, 0));
688   __ bind(&entry);
689   __ decq(rcx);
690   __ j(greater_equal, &loop);
691 
692   // Call the function.
693   ParameterCount actual(rax);
694   __ InvokeFunction(rdi, actual, CALL_FUNCTION);
695 
696   // Restore context from the frame.
697   __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
698 
699   // If the result is an object (in the ECMA sense), we should get rid
700   // of the receiver and use the result; see ECMA-262 section 13.2.2-7
701   // on page 74.
702   Label use_receiver, exit;
703   // If the result is a smi, it is *not* an object in the ECMA sense.
704   __ testl(rax, Immediate(kSmiTagMask));
705   __ j(zero, &use_receiver);
706 
707   // If the type of the result (stored in its map) is less than
708   // FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense.
709   __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx);
710   __ j(above_equal, &exit);
711 
712   // Throw away the result of the constructor invocation and use the
713   // on-stack receiver as the result.
714   __ bind(&use_receiver);
715   __ movq(rax, Operand(rsp, 0));
716 
717   // Restore the arguments count and leave the construct frame.
718   __ bind(&exit);
719   __ movq(rbx, Operand(rsp, kPointerSize));  // get arguments count
720   __ LeaveConstructFrame();
721 
722   // Remove caller arguments from the stack and return.
723   ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
724   __ pop(rcx);
725   __ lea(rsp, Operand(rsp, rbx, times_4, 1 * kPointerSize));  // 1 ~ receiver
726   __ push(rcx);
727   __ IncrementCounter(&Counters::constructed_objects, 1);
728   __ ret(0);
729 }
730 
731 
Generate_JSEntryTrampolineHelper(MacroAssembler * masm,bool is_construct)732 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
733                                              bool is_construct) {
734   // Expects five C++ function parameters.
735   // - Address entry (ignored)
736   // - JSFunction* function (
737   // - Object* receiver
738   // - int argc
739   // - Object*** argv
740   // (see Handle::Invoke in execution.cc).
741 
742   // Platform specific argument handling. After this, the stack contains
743   // an internal frame and the pushed function and receiver, and
744   // register rax and rbx holds the argument count and argument array,
745   // while rdi holds the function pointer and rsi the context.
746 #ifdef _WIN64
747   // MSVC parameters in:
748   // rcx : entry (ignored)
749   // rdx : function
750   // r8 : receiver
751   // r9 : argc
752   // [rsp+0x20] : argv
753 
754   // Clear the context before we push it when entering the JS frame.
755   __ xor_(rsi, rsi);
756   __ EnterInternalFrame();
757 
758   // Load the function context into rsi.
759   __ movq(rsi, FieldOperand(rdx, JSFunction::kContextOffset));
760 
761   // Push the function and the receiver onto the stack.
762   __ push(rdx);
763   __ push(r8);
764 
765   // Load the number of arguments and setup pointer to the arguments.
766   __ movq(rax, r9);
767   // Load the previous frame pointer to access C argument on stack
768   __ movq(kScratchRegister, Operand(rbp, 0));
769   __ movq(rbx, Operand(kScratchRegister, EntryFrameConstants::kArgvOffset));
770   // Load the function pointer into rdi.
771   __ movq(rdi, rdx);
772 #else  // !defined(_WIN64)
773   // GCC parameters in:
774   // rdi : entry (ignored)
775   // rsi : function
776   // rdx : receiver
777   // rcx : argc
778   // r8  : argv
779 
780   __ movq(rdi, rsi);
781   // rdi : function
782 
783   // Clear the context before we push it when entering the JS frame.
784   __ xor_(rsi, rsi);
785   // Enter an internal frame.
786   __ EnterInternalFrame();
787 
788   // Push the function and receiver and setup the context.
789   __ push(rdi);
790   __ push(rdx);
791   __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
792 
793   // Load the number of arguments and setup pointer to the arguments.
794   __ movq(rax, rcx);
795   __ movq(rbx, r8);
796 #endif  // _WIN64
797 
798   // Set up the roots register.
799   ExternalReference roots_address = ExternalReference::roots_address();
800   __ movq(r13, roots_address);
801 
802   // Current stack contents:
803   // [rsp + 2 * kPointerSize ... ]: Internal frame
804   // [rsp + kPointerSize]         : function
805   // [rsp]                        : receiver
806   // Current register contents:
807   // rax : argc
808   // rbx : argv
809   // rsi : context
810   // rdi : function
811 
812   // Copy arguments to the stack in a loop.
813   // Register rbx points to array of pointers to handle locations.
814   // Push the values of these handles.
815   Label loop, entry;
816   __ xor_(rcx, rcx);  // Set loop variable to 0.
817   __ jmp(&entry);
818   __ bind(&loop);
819   __ movq(kScratchRegister, Operand(rbx, rcx, times_pointer_size, 0));
820   __ push(Operand(kScratchRegister, 0));  // dereference handle
821   __ addq(rcx, Immediate(1));
822   __ bind(&entry);
823   __ cmpq(rcx, rax);
824   __ j(not_equal, &loop);
825 
826   // Invoke the code.
827   if (is_construct) {
828     // Expects rdi to hold function pointer.
829     __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
830             RelocInfo::CODE_TARGET);
831   } else {
832     ParameterCount actual(rax);
833     // Function must be in rdi.
834     __ InvokeFunction(rdi, actual, CALL_FUNCTION);
835   }
836 
837   // Exit the JS frame. Notice that this also removes the empty
838   // context and the function left on the stack by the code
839   // invocation.
840   __ LeaveInternalFrame();
841   // TODO(X64): Is argument correct? Is there a receiver to remove?
842   __ ret(1 * kPointerSize);  // remove receiver
843 }
844 
845 
Generate_JSEntryTrampoline(MacroAssembler * masm)846 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
847   Generate_JSEntryTrampolineHelper(masm, false);
848 }
849 
850 
Generate_JSConstructEntryTrampoline(MacroAssembler * masm)851 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
852   Generate_JSEntryTrampolineHelper(masm, true);
853 }
854 
855 } }  // namespace v8::internal
856