blob: ef3df659eb7a94d9801d4687f311000a02f9af40 [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Steve Blocka7e24c12009-10-30 11:49:00 +00004
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#include "src/v8.h"
Leon Clarkef7060e22010-06-03 12:02:55 +01006
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#if V8_TARGET_ARCH_X64
Leon Clarkef7060e22010-06-03 12:02:55 +01008
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009#include "src/code-factory.h"
10#include "src/codegen.h"
11#include "src/deoptimizer.h"
12#include "src/full-codegen.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000013
14namespace v8 {
15namespace internal {
16
Ben Murdochb0fe1622011-05-05 13:52:32 +010017
Steve Blocka7e24c12009-10-30 11:49:00 +000018#define __ ACCESS_MASM(masm)
19
Steve Blocka7e24c12009-10-30 11:49:00 +000020
Leon Clarkee46be812010-01-19 14:06:41 +000021void Builtins::Generate_Adaptor(MacroAssembler* masm,
22 CFunctionId id,
23 BuiltinExtraArguments extra_args) {
24 // ----------- S t a t e -------------
Ben Murdochb8a8cc12014-11-26 15:28:44 +000025 // -- rax : number of arguments excluding receiver
26 // -- rdi : called function (only guaranteed when
27 // extra_args requires it)
28 // -- rsi : context
29 // -- rsp[0] : return address
30 // -- rsp[8] : last argument
Leon Clarkee46be812010-01-19 14:06:41 +000031 // -- ...
Ben Murdochb8a8cc12014-11-26 15:28:44 +000032 // -- rsp[8 * argc] : first argument (argc == rax)
33 // -- rsp[8 * (argc + 1)] : receiver
Leon Clarkee46be812010-01-19 14:06:41 +000034 // -----------------------------------
35
36 // Insert extra arguments.
37 int num_extra_args = 0;
38 if (extra_args == NEEDS_CALLED_FUNCTION) {
39 num_extra_args = 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000040 __ PopReturnAddressTo(kScratchRegister);
41 __ Push(rdi);
42 __ PushReturnAddressFrom(kScratchRegister);
Leon Clarkee46be812010-01-19 14:06:41 +000043 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000044 DCHECK(extra_args == NO_EXTRA_ARGUMENTS);
Leon Clarkee46be812010-01-19 14:06:41 +000045 }
46
Steve Block6ded16b2010-05-10 14:33:55 +010047 // JumpToExternalReference expects rax to contain the number of arguments
Leon Clarkee46be812010-01-19 14:06:41 +000048 // including the receiver and the extra arguments.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000049 __ addp(rax, Immediate(num_extra_args + 1));
Steve Block44f0eee2011-05-26 01:26:41 +010050 __ JumpToExternalReference(ExternalReference(id, masm->isolate()), 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000051}
52
53
Ben Murdochb8a8cc12014-11-26 15:28:44 +000054static void CallRuntimePassFunction(
55 MacroAssembler* masm, Runtime::FunctionId function_id) {
56 FrameScope scope(masm, StackFrame::INTERNAL);
57 // Push a copy of the function onto the stack.
58 __ Push(rdi);
59 // Function is also the parameter to the runtime call.
60 __ Push(rdi);
61
62 __ CallRuntime(function_id, 1);
63 // Restore receiver.
64 __ Pop(rdi);
65}
66
67
68static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
69 __ movp(kScratchRegister,
70 FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
71 __ movp(kScratchRegister,
72 FieldOperand(kScratchRegister, SharedFunctionInfo::kCodeOffset));
73 __ leap(kScratchRegister, FieldOperand(kScratchRegister, Code::kHeaderSize));
74 __ jmp(kScratchRegister);
75}
76
77
78static void GenerateTailCallToReturnedCode(MacroAssembler* masm) {
79 __ leap(rax, FieldOperand(rax, Code::kHeaderSize));
80 __ jmp(rax);
81}
82
83
84void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
85 // Checking whether the queued function is ready for install is optional,
86 // since we come across interrupts and stack checks elsewhere. However,
87 // not checking may delay installing ready functions, and always checking
88 // would be quite expensive. A good compromise is to first check against
89 // stack limit as a cue for an interrupt signal.
90 Label ok;
91 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
92 __ j(above_equal, &ok);
93
94 CallRuntimePassFunction(masm, Runtime::kTryInstallOptimizedCode);
95 GenerateTailCallToReturnedCode(masm);
96
97 __ bind(&ok);
98 GenerateTailCallToSharedCode(masm);
99}
100
101
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100102static void Generate_JSConstructStubHelper(MacroAssembler* masm,
103 bool is_api_function,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000104 bool create_memento) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000105 // ----------- S t a t e -------------
106 // -- rax: number of arguments
107 // -- rdi: constructor function
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000108 // -- rbx: allocation site or undefined
Steve Blocka7e24c12009-10-30 11:49:00 +0000109 // -----------------------------------
110
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000111 // Should never create mementos for api functions.
112 DCHECK(!is_api_function || !create_memento);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100113
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100114 // Enter a construct frame.
115 {
116 FrameScope scope(masm, StackFrame::CONSTRUCT);
Steve Blocka7e24c12009-10-30 11:49:00 +0000117
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000118 if (create_memento) {
119 __ AssertUndefinedOrAllocationSite(rbx);
120 __ Push(rbx);
121 }
122
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100123 // Store a smi-tagged arguments count on the stack.
124 __ Integer32ToSmi(rax, rax);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000125 __ Push(rax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000126
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100127 // Push the function to invoke on the stack.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000128 __ Push(rdi);
Steve Blocka7e24c12009-10-30 11:49:00 +0000129
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100130 // Try to allocate the object without transitioning into C code. If any of
131 // the preconditions is not met, the code bails out to the runtime call.
132 Label rt_call, allocated;
133 if (FLAG_inline_new) {
134 Label undo_allocation;
Steve Blocka7e24c12009-10-30 11:49:00 +0000135
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100136 ExternalReference debug_step_in_fp =
137 ExternalReference::debug_step_in_fp_address(masm->isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000138 __ Move(kScratchRegister, debug_step_in_fp);
139 __ cmpp(Operand(kScratchRegister, 0), Immediate(0));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100140 __ j(not_equal, &rt_call);
Steve Blocka7e24c12009-10-30 11:49:00 +0000141
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100142 // Verified that the constructor is a JSFunction.
143 // Load the initial map and verify that it is in fact a map.
144 // rdi: constructor
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000145 __ movp(rax, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100146 // Will both indicate a NULL and a Smi
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000147 DCHECK(kSmiTag == 0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100148 __ JumpIfSmi(rax, &rt_call);
149 // rdi: constructor
150 // rax: initial map (if proven valid below)
151 __ CmpObjectType(rax, MAP_TYPE, rbx);
152 __ j(not_equal, &rt_call);
Steve Blocka7e24c12009-10-30 11:49:00 +0000153
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100154 // Check that the constructor is not constructing a JSFunction (see
155 // comments in Runtime_NewObject in runtime.cc). In which case the
156 // initial map's instance type would be JS_FUNCTION_TYPE.
157 // rdi: constructor
158 // rax: initial map
159 __ CmpInstanceType(rax, JS_FUNCTION_TYPE);
160 __ j(equal, &rt_call);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000161 if (!is_api_function) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100162 Label allocate;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000163 // The code below relies on these assumptions.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400164 STATIC_ASSERT(Map::Counter::kShift + Map::Counter::kSize == 32);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000165 // Check if slack tracking is enabled.
166 __ movl(rsi, FieldOperand(rax, Map::kBitField3Offset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400167 __ shrl(rsi, Immediate(Map::Counter::kShift));
168 __ cmpl(rsi, Immediate(Map::kSlackTrackingCounterEnd));
169 __ j(less, &allocate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100170 // Decrease generous allocation count.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000171 __ subl(FieldOperand(rax, Map::kBitField3Offset),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400172 Immediate(1 << Map::Counter::kShift));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100173
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400174 __ cmpl(rsi, Immediate(Map::kSlackTrackingCounterEnd));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000175 __ j(not_equal, &allocate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100176
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000177 __ Push(rax);
178 __ Push(rdi);
179
180 __ Push(rdi); // constructor
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100181 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
182
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000183 __ Pop(rdi);
184 __ Pop(rax);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400185 __ movl(rsi, Immediate(Map::kSlackTrackingCounterEnd - 1));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100186
187 __ bind(&allocate);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000188 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100189
190 // Now allocate the JSObject on the heap.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000191 __ movzxbp(rdi, FieldOperand(rax, Map::kInstanceSizeOffset));
192 __ shlp(rdi, Immediate(kPointerSizeLog2));
193 if (create_memento) {
194 __ addp(rdi, Immediate(AllocationMemento::kSize));
195 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100196 // rdi: size of new object
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000197 __ Allocate(rdi,
198 rbx,
199 rdi,
200 no_reg,
201 &rt_call,
202 NO_ALLOCATION_FLAGS);
203 Factory* factory = masm->isolate()->factory();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100204 // Allocated the JSObject, now initialize the fields.
205 // rax: initial map
206 // rbx: JSObject (not HeapObject tagged - the actual address).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000207 // rdi: start of next object (including memento if create_memento)
208 __ movp(Operand(rbx, JSObject::kMapOffset), rax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100209 __ LoadRoot(rcx, Heap::kEmptyFixedArrayRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000210 __ movp(Operand(rbx, JSObject::kPropertiesOffset), rcx);
211 __ movp(Operand(rbx, JSObject::kElementsOffset), rcx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100212 // Set extra fields in the newly allocated object.
213 // rax: initial map
214 // rbx: JSObject
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000215 // rdi: start of next object (including memento if create_memento)
216 // rsi: slack tracking counter (non-API function case)
217 __ leap(rcx, Operand(rbx, JSObject::kHeaderSize));
Ben Murdoch85b71792012-04-11 18:30:58 +0100218 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000219 if (!is_api_function) {
220 Label no_inobject_slack_tracking;
221
222 // Check if slack tracking is enabled.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400223 __ cmpl(rsi, Immediate(Map::kSlackTrackingCounterEnd));
224 __ j(less, &no_inobject_slack_tracking);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000225
226 // Allocate object with a slack.
227 __ movzxbp(rsi,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100228 FieldOperand(rax, Map::kPreAllocatedPropertyFieldsOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000229 __ leap(rsi,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100230 Operand(rbx, rsi, times_pointer_size, JSObject::kHeaderSize));
231 // rsi: offset of first field after pre-allocated fields
232 if (FLAG_debug_code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000233 __ cmpp(rsi, rdi);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100234 __ Assert(less_equal,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000235 kUnexpectedNumberOfPreAllocatedPropertyFields);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100236 }
237 __ InitializeFieldsWithFiller(rcx, rsi, rdx);
238 __ LoadRoot(rdx, Heap::kOnePointerFillerMapRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000239 // Fill the remaining fields with one pointer filler map.
240
241 __ bind(&no_inobject_slack_tracking);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100242 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000243 if (create_memento) {
244 __ leap(rsi, Operand(rdi, -AllocationMemento::kSize));
245 __ InitializeFieldsWithFiller(rcx, rsi, rdx);
246
247 // Fill in memento fields if necessary.
248 // rsi: points to the allocated but uninitialized memento.
249 __ Move(Operand(rsi, AllocationMemento::kMapOffset),
250 factory->allocation_memento_map());
251 // Get the cell or undefined.
252 __ movp(rdx, Operand(rsp, kPointerSize*2));
253 __ movp(Operand(rsi, AllocationMemento::kAllocationSiteOffset), rdx);
254 } else {
255 __ InitializeFieldsWithFiller(rcx, rdi, rdx);
256 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100257
258 // Add the object tag to make the JSObject real, so that we can continue
259 // and jump into the continuation code at any time from now on. Any
260 // failures need to undo the allocation, so that the heap is in a
261 // consistent state and verifiable.
262 // rax: initial map
263 // rbx: JSObject
264 // rdi: start of next object
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000265 __ orp(rbx, Immediate(kHeapObjectTag));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100266
267 // Check if a non-empty properties array is needed.
268 // Allocate and initialize a FixedArray if it is.
269 // rax: initial map
270 // rbx: JSObject
271 // rdi: start of next object
272 // Calculate total properties described map.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000273 __ movzxbp(rdx, FieldOperand(rax, Map::kUnusedPropertyFieldsOffset));
274 __ movzxbp(rcx,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100275 FieldOperand(rax, Map::kPreAllocatedPropertyFieldsOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000276 __ addp(rdx, rcx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100277 // Calculate unused properties past the end of the in-object properties.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000278 __ movzxbp(rcx, FieldOperand(rax, Map::kInObjectPropertiesOffset));
279 __ subp(rdx, rcx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100280 // Done if no extra properties are to be allocated.
281 __ j(zero, &allocated);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000282 __ Assert(positive, kPropertyAllocationCountFailed);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100283
284 // Scale the number of elements by pointer size and add the header for
285 // FixedArrays to the start of the next object calculation from above.
286 // rbx: JSObject
287 // rdi: start of next object (will be start of FixedArray)
288 // rdx: number of elements in properties array
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000289 __ Allocate(FixedArray::kHeaderSize,
290 times_pointer_size,
291 rdx,
292 rdi,
293 rax,
294 no_reg,
295 &undo_allocation,
296 RESULT_CONTAINS_TOP);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100297
298 // Initialize the FixedArray.
299 // rbx: JSObject
300 // rdi: FixedArray
301 // rdx: number of elements
302 // rax: start of next object
303 __ LoadRoot(rcx, Heap::kFixedArrayMapRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000304 __ movp(Operand(rdi, HeapObject::kMapOffset), rcx); // setup the map
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100305 __ Integer32ToSmi(rdx, rdx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000306 __ movp(Operand(rdi, FixedArray::kLengthOffset), rdx); // and length
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100307
308 // Initialize the fields to undefined.
309 // rbx: JSObject
310 // rdi: FixedArray
311 // rax: start of next object
312 // rdx: number of elements
313 { Label loop, entry;
314 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000315 __ leap(rcx, Operand(rdi, FixedArray::kHeaderSize));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100316 __ jmp(&entry);
317 __ bind(&loop);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000318 __ movp(Operand(rcx, 0), rdx);
319 __ addp(rcx, Immediate(kPointerSize));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100320 __ bind(&entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000321 __ cmpp(rcx, rax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100322 __ j(below, &loop);
323 }
324
325 // Store the initialized FixedArray into the properties field of
326 // the JSObject
327 // rbx: JSObject
328 // rdi: FixedArray
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000329 __ orp(rdi, Immediate(kHeapObjectTag)); // add the heap tag
330 __ movp(FieldOperand(rbx, JSObject::kPropertiesOffset), rdi);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100331
332
333 // Continue with JSObject being successfully allocated
334 // rbx: JSObject
335 __ jmp(&allocated);
336
337 // Undo the setting of the new top so that the heap is verifiable. For
338 // example, the map's unused properties potentially do not match the
339 // allocated objects unused properties.
340 // rbx: JSObject (previous new top)
341 __ bind(&undo_allocation);
342 __ UndoAllocationInNewSpace(rbx);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000343 }
344
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100345 // Allocate the new receiver object using the runtime call.
346 // rdi: function (constructor)
347 __ bind(&rt_call);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000348 int offset = 0;
349 if (create_memento) {
350 // Get the cell or allocation site.
351 __ movp(rdi, Operand(rsp, kPointerSize*2));
352 __ Push(rdi);
353 offset = kPointerSize;
354 }
355
356 // Must restore rsi (context) and rdi (constructor) before calling runtime.
357 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
358 __ movp(rdi, Operand(rsp, offset));
359 __ Push(rdi);
360 if (create_memento) {
361 __ CallRuntime(Runtime::kNewObjectWithAllocationSite, 2);
362 } else {
363 __ CallRuntime(Runtime::kNewObject, 1);
364 }
365 __ movp(rbx, rax); // store result in rbx
366
367 // If we ended up using the runtime, and we want a memento, then the
368 // runtime call made it for us, and we shouldn't do create count
369 // increment.
370 Label count_incremented;
371 if (create_memento) {
372 __ jmp(&count_incremented);
373 }
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100374
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100375 // New object allocated.
376 // rbx: newly allocated object
377 __ bind(&allocated);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000378
379 if (create_memento) {
380 __ movp(rcx, Operand(rsp, kPointerSize*2));
381 __ Cmp(rcx, masm->isolate()->factory()->undefined_value());
382 __ j(equal, &count_incremented);
383 // rcx is an AllocationSite. We are creating a memento from it, so we
384 // need to increment the memento create count.
385 __ SmiAddConstant(
386 FieldOperand(rcx, AllocationSite::kPretenureCreateCountOffset),
387 Smi::FromInt(1));
388 __ bind(&count_incremented);
389 }
390
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100391 // Retrieve the function from the stack.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000392 __ Pop(rdi);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000393
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100394 // Retrieve smi-tagged arguments count from the stack.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000395 __ movp(rax, Operand(rsp, 0));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100396 __ SmiToInteger32(rax, rax);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000397
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100398 // Push the allocated receiver to the stack. We need two copies
399 // because we may have to return the original one and the calling
400 // conventions dictate that the called function pops the receiver.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000401 __ Push(rbx);
402 __ Push(rbx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100403
404 // Set up pointer to last argument.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000405 __ leap(rbx, Operand(rbp, StandardFrameConstants::kCallerSPOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100406
407 // Copy arguments and receiver to the expression stack.
408 Label loop, entry;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000409 __ movp(rcx, rax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100410 __ jmp(&entry);
411 __ bind(&loop);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000412 __ Push(Operand(rbx, rcx, times_pointer_size, 0));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100413 __ bind(&entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000414 __ decp(rcx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100415 __ j(greater_equal, &loop);
416
417 // Call the function.
418 if (is_api_function) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000419 __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100420 Handle<Code> code =
421 masm->isolate()->builtins()->HandleApiCallConstruct();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000422 __ Call(code, RelocInfo::CODE_TARGET);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100423 } else {
424 ParameterCount actual(rax);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000425 __ InvokeFunction(rdi, actual, CALL_FUNCTION, NullCallWrapper());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100426 }
427
428 // Store offset of return address for deoptimizer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000429 if (!is_api_function) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100430 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
431 }
432
433 // Restore context from the frame.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000434 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100435
436 // If the result is an object (in the ECMA sense), we should get rid
437 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
438 // on page 74.
439 Label use_receiver, exit;
440 // If the result is a smi, it is *not* an object in the ECMA sense.
441 __ JumpIfSmi(rax, &use_receiver);
442
443 // If the type of the result (stored in its map) is less than
444 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
445 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
446 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx);
447 __ j(above_equal, &exit);
448
449 // Throw away the result of the constructor invocation and use the
450 // on-stack receiver as the result.
451 __ bind(&use_receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000452 __ movp(rax, Operand(rsp, 0));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100453
454 // Restore the arguments count and leave the construct frame.
455 __ bind(&exit);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000456 __ movp(rbx, Operand(rsp, kPointerSize)); // Get arguments count.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100457
458 // Leave construct frame.
Steve Blocka7e24c12009-10-30 11:49:00 +0000459 }
460
Steve Blocka7e24c12009-10-30 11:49:00 +0000461 // Remove caller arguments from the stack and return.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000462 __ PopReturnAddressTo(rcx);
Steve Block3ce2e202009-11-05 08:53:23 +0000463 SmiIndex index = masm->SmiToIndex(rbx, rbx, kPointerSizeLog2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000464 __ leap(rsp, Operand(rsp, index.reg, index.scale, 1 * kPointerSize));
465 __ PushReturnAddressFrom(rcx);
Steve Block44f0eee2011-05-26 01:26:41 +0100466 Counters* counters = masm->isolate()->counters();
467 __ IncrementCounter(counters->constructed_objects(), 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000468 __ ret(0);
469}
470
471
Leon Clarkee46be812010-01-19 14:06:41 +0000472void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000473 Generate_JSConstructStubHelper(masm, false, FLAG_pretenuring_call_new);
Leon Clarkee46be812010-01-19 14:06:41 +0000474}
475
476
477void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100478 Generate_JSConstructStubHelper(masm, true, false);
Leon Clarkee46be812010-01-19 14:06:41 +0000479}
480
481
Steve Blocka7e24c12009-10-30 11:49:00 +0000482static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
483 bool is_construct) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000484 ProfileEntryHookStub::MaybeCallEntryHook(masm);
485
Steve Blocka7e24c12009-10-30 11:49:00 +0000486 // Expects five C++ function parameters.
487 // - Address entry (ignored)
488 // - JSFunction* function (
489 // - Object* receiver
490 // - int argc
491 // - Object*** argv
492 // (see Handle::Invoke in execution.cc).
493
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100494 // Open a C++ scope for the FrameScope.
495 {
496 // Platform specific argument handling. After this, the stack contains
497 // an internal frame and the pushed function and receiver, and
498 // register rax and rbx holds the argument count and argument array,
499 // while rdi holds the function pointer and rsi the context.
500
Steve Blocka7e24c12009-10-30 11:49:00 +0000501#ifdef _WIN64
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100502 // MSVC parameters in:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000503 // rcx : entry (ignored)
504 // rdx : function
505 // r8 : receiver
506 // r9 : argc
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100507 // [rsp+0x20] : argv
Steve Blocka7e24c12009-10-30 11:49:00 +0000508
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100509 // Clear the context before we push it when entering the internal frame.
510 __ Set(rsi, 0);
511 // Enter an internal frame.
512 FrameScope scope(masm, StackFrame::INTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000513
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100514 // Load the function context into rsi.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000515 __ movp(rsi, FieldOperand(rdx, JSFunction::kContextOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000516
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100517 // Push the function and the receiver onto the stack.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000518 __ Push(rdx);
519 __ Push(r8);
Steve Blocka7e24c12009-10-30 11:49:00 +0000520
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100521 // Load the number of arguments and setup pointer to the arguments.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000522 __ movp(rax, r9);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100523 // Load the previous frame pointer to access C argument on stack
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000524 __ movp(kScratchRegister, Operand(rbp, 0));
525 __ movp(rbx, Operand(kScratchRegister, EntryFrameConstants::kArgvOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100526 // Load the function pointer into rdi.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000527 __ movp(rdi, rdx);
Steve Block6ded16b2010-05-10 14:33:55 +0100528#else // _WIN64
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100529 // GCC parameters in:
530 // rdi : entry (ignored)
531 // rsi : function
532 // rdx : receiver
533 // rcx : argc
534 // r8 : argv
Steve Blocka7e24c12009-10-30 11:49:00 +0000535
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000536 __ movp(rdi, rsi);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100537 // rdi : function
Steve Blocka7e24c12009-10-30 11:49:00 +0000538
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100539 // Clear the context before we push it when entering the internal frame.
540 __ Set(rsi, 0);
541 // Enter an internal frame.
542 FrameScope scope(masm, StackFrame::INTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000543
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100544 // Push the function and receiver and setup the context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000545 __ Push(rdi);
546 __ Push(rdx);
547 __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000548
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100549 // Load the number of arguments and setup pointer to the arguments.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000550 __ movp(rax, rcx);
551 __ movp(rbx, r8);
Steve Blocka7e24c12009-10-30 11:49:00 +0000552#endif // _WIN64
553
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100554 // Current stack contents:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000555 // [rsp + 2 * kPointerSize ... ] : Internal frame
556 // [rsp + kPointerSize] : function
557 // [rsp] : receiver
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100558 // Current register contents:
559 // rax : argc
560 // rbx : argv
561 // rsi : context
562 // rdi : function
Steve Blocka7e24c12009-10-30 11:49:00 +0000563
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100564 // Copy arguments to the stack in a loop.
565 // Register rbx points to array of pointers to handle locations.
566 // Push the values of these handles.
567 Label loop, entry;
568 __ Set(rcx, 0); // Set loop variable to 0.
569 __ jmp(&entry);
570 __ bind(&loop);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000571 __ movp(kScratchRegister, Operand(rbx, rcx, times_pointer_size, 0));
572 __ Push(Operand(kScratchRegister, 0)); // dereference handle
573 __ addp(rcx, Immediate(1));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100574 __ bind(&entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000575 __ cmpp(rcx, rax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100576 __ j(not_equal, &loop);
Steve Blocka7e24c12009-10-30 11:49:00 +0000577
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100578 // Invoke the code.
579 if (is_construct) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000580 // No type feedback cell is available
581 __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100582 // Expects rdi to hold function pointer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000583 CallConstructStub stub(masm->isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100584 __ CallStub(&stub);
585 } else {
586 ParameterCount actual(rax);
587 // Function must be in rdi.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000588 __ InvokeFunction(rdi, actual, CALL_FUNCTION, NullCallWrapper());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100589 }
590 // Exit the internal frame. Notice that this also removes the empty
591 // context and the function left on the stack by the code
592 // invocation.
Steve Blocka7e24c12009-10-30 11:49:00 +0000593 }
594
Steve Blocka7e24c12009-10-30 11:49:00 +0000595 // TODO(X64): Is argument correct? Is there a receiver to remove?
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100596 __ ret(1 * kPointerSize); // Remove receiver.
Steve Blocka7e24c12009-10-30 11:49:00 +0000597}
598
599
600void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
601 Generate_JSEntryTrampolineHelper(masm, false);
602}
603
604
605void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
606 Generate_JSEntryTrampolineHelper(masm, true);
607}
608
Iain Merrick75681382010-08-19 15:07:18 +0100609
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000610void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
611 CallRuntimePassFunction(masm, Runtime::kCompileLazy);
612 GenerateTailCallToReturnedCode(masm);
Iain Merrick75681382010-08-19 15:07:18 +0100613}
614
Ben Murdochb0fe1622011-05-05 13:52:32 +0100615
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000616static void CallCompileOptimized(MacroAssembler* masm,
617 bool concurrent) {
618 FrameScope scope(masm, StackFrame::INTERNAL);
619 // Push a copy of the function onto the stack.
620 __ Push(rdi);
621 // Function is also the parameter to the runtime call.
622 __ Push(rdi);
623 // Whether to compile in a background thread.
624 __ Push(masm->isolate()->factory()->ToBoolean(concurrent));
625
626 __ CallRuntime(Runtime::kCompileOptimized, 2);
627 // Restore receiver.
628 __ Pop(rdi);
629}
630
631
632void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
633 CallCompileOptimized(masm, false);
634 GenerateTailCallToReturnedCode(masm);
635}
636
637
638void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
639 CallCompileOptimized(masm, true);
640 GenerateTailCallToReturnedCode(masm);
641}
642
643
644static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
645 // For now, we are relying on the fact that make_code_young doesn't do any
646 // garbage collection which allows us to save/restore the registers without
647 // worrying about which of them contain pointers. We also don't build an
648 // internal frame to make the code faster, since we shouldn't have to do stack
649 // crawls in MakeCodeYoung. This seems a bit fragile.
650
651 // Re-execute the code that was patched back to the young age when
652 // the stub returns.
653 __ subp(Operand(rsp, 0), Immediate(5));
654 __ Pushad();
655 __ Move(arg_reg_2, ExternalReference::isolate_address(masm->isolate()));
656 __ movp(arg_reg_1, Operand(rsp, kNumSafepointRegisters * kPointerSize));
657 { // NOLINT
658 FrameScope scope(masm, StackFrame::MANUAL);
659 __ PrepareCallCFunction(2);
660 __ CallCFunction(
661 ExternalReference::get_make_code_young_function(masm->isolate()), 2);
662 }
663 __ Popad();
664 __ ret(0);
665}
666
667
668#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
669void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
670 MacroAssembler* masm) { \
671 GenerateMakeCodeYoungAgainCommon(masm); \
672} \
673void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
674 MacroAssembler* masm) { \
675 GenerateMakeCodeYoungAgainCommon(masm); \
676}
677CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
678#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
679
680
681void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
682 // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
683 // that make_code_young doesn't do any garbage collection which allows us to
684 // save/restore the registers without worrying about which of them contain
685 // pointers.
686 __ Pushad();
687 __ Move(arg_reg_2, ExternalReference::isolate_address(masm->isolate()));
688 __ movp(arg_reg_1, Operand(rsp, kNumSafepointRegisters * kPointerSize));
689 __ subp(arg_reg_1, Immediate(Assembler::kShortCallInstructionLength));
690 { // NOLINT
691 FrameScope scope(masm, StackFrame::MANUAL);
692 __ PrepareCallCFunction(2);
693 __ CallCFunction(
694 ExternalReference::get_mark_code_as_executed_function(masm->isolate()),
695 2);
696 }
697 __ Popad();
698
699 // Perform prologue operations usually performed by the young code stub.
700 __ PopReturnAddressTo(kScratchRegister);
701 __ pushq(rbp); // Caller's frame pointer.
702 __ movp(rbp, rsp);
703 __ Push(rsi); // Callee's context.
704 __ Push(rdi); // Callee's JS Function.
705 __ PushReturnAddressFrom(kScratchRegister);
706
707 // Jump to point after the code-age stub.
708 __ ret(0);
709}
710
711
712void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
713 GenerateMakeCodeYoungAgainCommon(masm);
714}
715
716
717static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
718 SaveFPRegsMode save_doubles) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100719 // Enter an internal frame.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100720 {
721 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100722
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000723 // Preserve registers across notification, this is important for compiled
724 // stubs that tail call the runtime on deopts passing their parameters in
725 // registers.
726 __ Pushad();
727 __ CallRuntime(Runtime::kNotifyStubFailure, 0, save_doubles);
728 __ Popad();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100729 // Tear down internal frame.
730 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100731
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000732 __ DropUnderReturnAddress(1); // Ignore state offset
733 __ ret(0); // Return to IC Miss stub, continuation still on stack.
734}
735
736
737void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
738 Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
739}
740
741
742void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
743 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100744}
745
746
747static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
748 Deoptimizer::BailoutType type) {
Steve Block1e0659c2011-05-24 12:43:12 +0100749 // Enter an internal frame.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100750 {
751 FrameScope scope(masm, StackFrame::INTERNAL);
Steve Block1e0659c2011-05-24 12:43:12 +0100752
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100753 // Pass the deoptimization type to the runtime system.
754 __ Push(Smi::FromInt(static_cast<int>(type)));
Steve Block1e0659c2011-05-24 12:43:12 +0100755
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100756 __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
757 // Tear down internal frame.
758 }
Steve Block1e0659c2011-05-24 12:43:12 +0100759
760 // Get the full codegen state from the stack and untag it.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000761 __ SmiToInteger32(kScratchRegister, Operand(rsp, kPCOnStackSize));
Steve Block1e0659c2011-05-24 12:43:12 +0100762
763 // Switch on the state.
Ben Murdoch257744e2011-11-30 15:57:28 +0000764 Label not_no_registers, not_tos_rax;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000765 __ cmpp(kScratchRegister, Immediate(FullCodeGenerator::NO_REGISTERS));
Ben Murdoch257744e2011-11-30 15:57:28 +0000766 __ j(not_equal, &not_no_registers, Label::kNear);
Steve Block1e0659c2011-05-24 12:43:12 +0100767 __ ret(1 * kPointerSize); // Remove state.
768
769 __ bind(&not_no_registers);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000770 __ movp(rax, Operand(rsp, kPCOnStackSize + kPointerSize));
771 __ cmpp(kScratchRegister, Immediate(FullCodeGenerator::TOS_REG));
Ben Murdoch257744e2011-11-30 15:57:28 +0000772 __ j(not_equal, &not_tos_rax, Label::kNear);
Steve Block1e0659c2011-05-24 12:43:12 +0100773 __ ret(2 * kPointerSize); // Remove state, rax.
774
775 __ bind(&not_tos_rax);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000776 __ Abort(kNoCasesLeft);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100777}
778
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000779
Ben Murdochb0fe1622011-05-05 13:52:32 +0100780void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
781 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
782}
783
784
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000785void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
786 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
787}
788
789
Ben Murdochb0fe1622011-05-05 13:52:32 +0100790void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
Steve Block1e0659c2011-05-24 12:43:12 +0100791 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100792}
793
794
Ben Murdochb0fe1622011-05-05 13:52:32 +0100795void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
796 // Stack Layout:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000797 // rsp[0] : Return address
798 // rsp[8] : Argument n
799 // rsp[16] : Argument n-1
Ben Murdochb0fe1622011-05-05 13:52:32 +0100800 // ...
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000801 // rsp[8 * n] : Argument 1
802 // rsp[8 * (n + 1)] : Receiver (function to call)
Ben Murdochb0fe1622011-05-05 13:52:32 +0100803 //
804 // rax contains the number of arguments, n, not counting the receiver.
805 //
806 // 1. Make sure we have at least one argument.
807 { Label done;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000808 __ testp(rax, rax);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100809 __ j(not_zero, &done);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000810 __ PopReturnAddressTo(rbx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100811 __ Push(masm->isolate()->factory()->undefined_value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000812 __ PushReturnAddressFrom(rbx);
813 __ incp(rax);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100814 __ bind(&done);
815 }
816
817 // 2. Get the function to call (passed as receiver) from the stack, check
818 // if it is a function.
Ben Murdoch589d6972011-11-30 16:04:58 +0000819 Label slow, non_function;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000820 StackArgumentsAccessor args(rsp, rax);
821 __ movp(rdi, args.GetReceiverOperand());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100822 __ JumpIfSmi(rdi, &non_function);
823 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
Ben Murdoch589d6972011-11-30 16:04:58 +0000824 __ j(not_equal, &slow);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100825
826 // 3a. Patch the first argument if necessary when calling a function.
827 Label shift_arguments;
Ben Murdoch589d6972011-11-30 16:04:58 +0000828 __ Set(rdx, 0); // indicate regular JS_FUNCTION
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000829 { Label convert_to_object, use_global_proxy, patch_receiver;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100830 // Change context eagerly in case we need the global receiver.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000831 __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100832
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100833 // Do not transform the receiver for strict mode functions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000834 __ movp(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100835 __ testb(FieldOperand(rbx, SharedFunctionInfo::kStrictModeByteOffset),
836 Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
837 __ j(not_equal, &shift_arguments);
838
Ben Murdoch257744e2011-11-30 15:57:28 +0000839 // Do not transform the receiver for natives.
840 // SharedFunctionInfo is already loaded into rbx.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000841 __ testb(FieldOperand(rbx, SharedFunctionInfo::kNativeByteOffset),
842 Immediate(1 << SharedFunctionInfo::kNativeBitWithinByte));
Ben Murdoch257744e2011-11-30 15:57:28 +0000843 __ j(not_zero, &shift_arguments);
844
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000845 // Compute the receiver in sloppy mode.
846 __ movp(rbx, args.GetArgumentOperand(1));
Ben Murdoch257744e2011-11-30 15:57:28 +0000847 __ JumpIfSmi(rbx, &convert_to_object, Label::kNear);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100848
849 __ CompareRoot(rbx, Heap::kNullValueRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000850 __ j(equal, &use_global_proxy);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100851 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000852 __ j(equal, &use_global_proxy);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100853
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000854 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
855 __ CmpObjectType(rbx, FIRST_SPEC_OBJECT_TYPE, rcx);
Ben Murdoch257744e2011-11-30 15:57:28 +0000856 __ j(above_equal, &shift_arguments);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100857
858 __ bind(&convert_to_object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100859 {
860 // Enter an internal frame in order to preserve argument count.
861 FrameScope scope(masm, StackFrame::INTERNAL);
862 __ Integer32ToSmi(rax, rax);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000863 __ Push(rax);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100864
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000865 __ Push(rbx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100866 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000867 __ movp(rbx, rax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100868 __ Set(rdx, 0); // indicate regular JS_FUNCTION
Ben Murdochb0fe1622011-05-05 13:52:32 +0100869
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000870 __ Pop(rax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100871 __ SmiToInteger32(rax, rax);
872 }
873
Ben Murdochb0fe1622011-05-05 13:52:32 +0100874 // Restore the function to rdi.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000875 __ movp(rdi, args.GetReceiverOperand());
Ben Murdoch257744e2011-11-30 15:57:28 +0000876 __ jmp(&patch_receiver, Label::kNear);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100877
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000878 __ bind(&use_global_proxy);
879 __ movp(rbx,
880 Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
881 __ movp(rbx, FieldOperand(rbx, GlobalObject::kGlobalProxyOffset));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100882
883 __ bind(&patch_receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000884 __ movp(args.GetArgumentOperand(1), rbx);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100885
886 __ jmp(&shift_arguments);
887 }
888
Ben Murdoch589d6972011-11-30 16:04:58 +0000889 // 3b. Check for function proxy.
890 __ bind(&slow);
891 __ Set(rdx, 1); // indicate function proxy
892 __ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE);
893 __ j(equal, &shift_arguments);
894 __ bind(&non_function);
895 __ Set(rdx, 2); // indicate non-function
Ben Murdochb0fe1622011-05-05 13:52:32 +0100896
Ben Murdoch589d6972011-11-30 16:04:58 +0000897 // 3c. Patch the first argument when calling a non-function. The
Ben Murdochb0fe1622011-05-05 13:52:32 +0100898 // CALL_NON_FUNCTION builtin expects the non-function callee as
899 // receiver, so overwrite the first argument which will ultimately
900 // become the receiver.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000901 __ movp(args.GetArgumentOperand(1), rdi);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100902
903 // 4. Shift arguments and return address one slot down on the stack
904 // (overwriting the original receiver). Adjust argument count to make
905 // the original first argument the new receiver.
906 __ bind(&shift_arguments);
907 { Label loop;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000908 __ movp(rcx, rax);
909 StackArgumentsAccessor args(rsp, rcx);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100910 __ bind(&loop);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000911 __ movp(rbx, args.GetArgumentOperand(1));
912 __ movp(args.GetArgumentOperand(0), rbx);
913 __ decp(rcx);
914 __ j(not_zero, &loop); // While non-zero.
915 __ DropUnderReturnAddress(1, rbx); // Drop one slot under return address.
916 __ decp(rax); // One fewer argument (first argument is new receiver).
Ben Murdochb0fe1622011-05-05 13:52:32 +0100917 }
918
Ben Murdoch589d6972011-11-30 16:04:58 +0000919 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
920 // or a function proxy via CALL_FUNCTION_PROXY.
921 { Label function, non_proxy;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000922 __ testp(rdx, rdx);
Ben Murdoch589d6972011-11-30 16:04:58 +0000923 __ j(zero, &function);
Steve Block9fac8402011-05-12 15:51:54 +0100924 __ Set(rbx, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000925 __ cmpp(rdx, Immediate(1));
Ben Murdoch589d6972011-11-30 16:04:58 +0000926 __ j(not_equal, &non_proxy);
927
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000928 __ PopReturnAddressTo(rdx);
929 __ Push(rdi); // re-add proxy object as additional argument
930 __ PushReturnAddressFrom(rdx);
931 __ incp(rax);
Ben Murdoch589d6972011-11-30 16:04:58 +0000932 __ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY);
933 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
934 RelocInfo::CODE_TARGET);
935
936 __ bind(&non_proxy);
937 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
Steve Block44f0eee2011-05-26 01:26:41 +0100938 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100939 RelocInfo::CODE_TARGET);
940 __ bind(&function);
941 }
942
943 // 5b. Get the code to call from the function and check that the number of
944 // expected arguments matches what we're providing. If so, jump
945 // (tail-call) to the code in register edx without checking arguments.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000946 __ movp(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
947 __ LoadSharedFunctionInfoSpecialField(rbx, rdx,
948 SharedFunctionInfo::kFormalParameterCountOffset);
949 __ movp(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
950 __ cmpp(rax, rbx);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100951 __ j(not_equal,
Steve Block44f0eee2011-05-26 01:26:41 +0100952 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100953 RelocInfo::CODE_TARGET);
954
955 ParameterCount expected(0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000956 __ InvokeCode(rdx, expected, expected, JUMP_FUNCTION, NullCallWrapper());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100957}
958
959
960void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
961 // Stack at entry:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000962 // rsp : return address
963 // rsp[8] : arguments
964 // rsp[16] : receiver ("this")
965 // rsp[24] : function
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100966 {
967 FrameScope frame_scope(masm, StackFrame::INTERNAL);
968 // Stack frame:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000969 // rbp : Old base pointer
970 // rbp[8] : return address
971 // rbp[16] : function arguments
972 // rbp[24] : receiver
973 // rbp[32] : function
974 static const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize;
975 static const int kReceiverOffset = kArgumentsOffset + kPointerSize;
976 static const int kFunctionOffset = kReceiverOffset + kPointerSize;
Ben Murdoch589d6972011-11-30 16:04:58 +0000977
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000978 __ Push(Operand(rbp, kFunctionOffset));
979 __ Push(Operand(rbp, kArgumentsOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100980 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100981
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100982 // Check the stack for overflow. We are not trying to catch
983 // interruptions (e.g. debug break and preemption) here, so the "real stack
984 // limit" is checked.
985 Label okay;
986 __ LoadRoot(kScratchRegister, Heap::kRealStackLimitRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000987 __ movp(rcx, rsp);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100988 // Make rcx the space we have left. The stack might already be overflowed
989 // here which will cause rcx to become negative.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000990 __ subp(rcx, kScratchRegister);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100991 // Make rdx the space we need for the array when it is unrolled onto the
992 // stack.
993 __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rax, kPointerSizeLog2);
994 // Check if the arguments will overflow the stack.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000995 __ cmpp(rcx, rdx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100996 __ j(greater, &okay); // Signed comparison.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100997
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100998 // Out of stack space.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000999 __ Push(Operand(rbp, kFunctionOffset));
1000 __ Push(rax);
1001 __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001002 __ bind(&okay);
1003 // End of stack check.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001004
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001005 // Push current index and limit.
1006 const int kLimitOffset =
1007 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
1008 const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001009 __ Push(rax); // limit
1010 __ Push(Immediate(0)); // index
Ben Murdochb0fe1622011-05-05 13:52:32 +01001011
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001012 // Get the receiver.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001013 __ movp(rbx, Operand(rbp, kReceiverOffset));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001014
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001015 // Check that the function is a JS function (otherwise it must be a proxy).
1016 Label push_receiver;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001017 __ movp(rdi, Operand(rbp, kFunctionOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001018 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
1019 __ j(not_equal, &push_receiver);
Ben Murdoch589d6972011-11-30 16:04:58 +00001020
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001021 // Change context eagerly to get the right global object if necessary.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001022 __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
Ben Murdoch589d6972011-11-30 16:04:58 +00001023
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001024 // Do not transform the receiver for strict mode functions.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001025 Label call_to_object, use_global_proxy;
1026 __ movp(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001027 __ testb(FieldOperand(rdx, SharedFunctionInfo::kStrictModeByteOffset),
1028 Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
1029 __ j(not_equal, &push_receiver);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001030
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001031 // Do not transform the receiver for natives.
1032 __ testb(FieldOperand(rdx, SharedFunctionInfo::kNativeByteOffset),
1033 Immediate(1 << SharedFunctionInfo::kNativeBitWithinByte));
1034 __ j(not_equal, &push_receiver);
Ben Murdoch257744e2011-11-30 15:57:28 +00001035
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001036 // Compute the receiver in sloppy mode.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001037 __ JumpIfSmi(rbx, &call_to_object, Label::kNear);
1038 __ CompareRoot(rbx, Heap::kNullValueRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001039 __ j(equal, &use_global_proxy);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001040 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001041 __ j(equal, &use_global_proxy);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001042
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001043 // If given receiver is already a JavaScript object then there's no
1044 // reason for converting it.
1045 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
1046 __ CmpObjectType(rbx, FIRST_SPEC_OBJECT_TYPE, rcx);
1047 __ j(above_equal, &push_receiver);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001048
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001049 // Convert the receiver to an object.
1050 __ bind(&call_to_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001051 __ Push(rbx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001052 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001053 __ movp(rbx, rax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001054 __ jmp(&push_receiver, Label::kNear);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001055
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001056 __ bind(&use_global_proxy);
1057 __ movp(rbx,
1058 Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
1059 __ movp(rbx, FieldOperand(rbx, GlobalObject::kGlobalProxyOffset));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001060
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001061 // Push the receiver.
1062 __ bind(&push_receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001063 __ Push(rbx);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001064
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001065 // Copy all arguments from the array to the stack.
1066 Label entry, loop;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001067 Register receiver = LoadDescriptor::ReceiverRegister();
1068 Register key = LoadDescriptor::NameRegister();
1069 __ movp(key, Operand(rbp, kIndexOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001070 __ jmp(&entry);
1071 __ bind(&loop);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001072 __ movp(receiver, Operand(rbp, kArgumentsOffset)); // load arguments
Ben Murdochb0fe1622011-05-05 13:52:32 +01001073
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001074 // Use inline caching to speed up access to arguments.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001075 if (FLAG_vector_ics) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001076 // TODO(mvstanton): Vector-based ics need additional infrastructure to
1077 // be embedded here. For now, just call the runtime.
1078 __ Push(receiver);
1079 __ Push(key);
1080 __ CallRuntime(Runtime::kGetProperty, 2);
1081 } else {
1082 Handle<Code> ic = CodeFactory::KeyedLoadIC(masm->isolate()).code();
1083 __ Call(ic, RelocInfo::CODE_TARGET);
1084 // It is important that we do not have a test instruction after the
1085 // call. A test instruction after the call is used to indicate that
1086 // we have generated an inline version of the keyed load. In this
1087 // case, we know that we are not generating a test instruction next.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001088 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001089
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001090 // Push the nth argument.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001091 __ Push(rax);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001092
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001093 // Update the index on the stack and in register key.
1094 __ movp(key, Operand(rbp, kIndexOffset));
1095 __ SmiAddConstant(key, key, Smi::FromInt(1));
1096 __ movp(Operand(rbp, kIndexOffset), key);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001097
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001098 __ bind(&entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001099 __ cmpp(key, Operand(rbp, kLimitOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001100 __ j(not_equal, &loop);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001101
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001102 // Call the function.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001103 Label call_proxy;
1104 ParameterCount actual(rax);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001105 __ SmiToInteger32(rax, key);
1106 __ movp(rdi, Operand(rbp, kFunctionOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001107 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
1108 __ j(not_equal, &call_proxy);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001109 __ InvokeFunction(rdi, actual, CALL_FUNCTION, NullCallWrapper());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001110
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001111 frame_scope.GenerateLeaveFrame();
1112 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
Ben Murdoch589d6972011-11-30 16:04:58 +00001113
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001114 // Call the function proxy.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001115 __ bind(&call_proxy);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001116 __ Push(rdi); // add function proxy as last argument
1117 __ incp(rax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001118 __ Set(rbx, 0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001119 __ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY);
1120 __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1121 RelocInfo::CODE_TARGET);
Ben Murdoch589d6972011-11-30 16:04:58 +00001122
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001123 // Leave internal frame.
1124 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001125 __ ret(3 * kPointerSize); // remove this, receiver, and arguments
Ben Murdochb0fe1622011-05-05 13:52:32 +01001126}
1127
1128
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001129void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
1130 // ----------- S t a t e -------------
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001131 // -- rax : argc
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001132 // -- rsp[0] : return address
1133 // -- rsp[8] : last argument
1134 // -----------------------------------
1135 Label generic_array_code;
1136
1137 // Get the InternalArray function.
1138 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, rdi);
1139
1140 if (FLAG_debug_code) {
1141 // Initial map for the builtin InternalArray functions should be maps.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001142 __ movp(rbx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001143 // Will both indicate a NULL and a Smi.
1144 STATIC_ASSERT(kSmiTag == 0);
1145 Condition not_smi = NegateCondition(masm->CheckSmi(rbx));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001146 __ Check(not_smi, kUnexpectedInitialMapForInternalArrayFunction);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001147 __ CmpObjectType(rbx, MAP_TYPE, rcx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001148 __ Check(equal, kUnexpectedInitialMapForInternalArrayFunction);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001149 }
1150
1151 // Run the native code for the InternalArray function called as a normal
1152 // function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001153 // tail call a stub
1154 InternalArrayConstructorStub stub(masm->isolate());
1155 __ TailCallStub(&stub);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001156}
1157
1158
1159void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1160 // ----------- S t a t e -------------
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001161 // -- rax : argc
Ben Murdochb0fe1622011-05-05 13:52:32 +01001162 // -- rsp[0] : return address
1163 // -- rsp[8] : last argument
1164 // -----------------------------------
1165 Label generic_array_code;
1166
1167 // Get the Array function.
1168 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, rdi);
1169
1170 if (FLAG_debug_code) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001171 // Initial map for the builtin Array functions should be maps.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001172 __ movp(rbx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001173 // Will both indicate a NULL and a Smi.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001174 STATIC_ASSERT(kSmiTag == 0);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001175 Condition not_smi = NegateCondition(masm->CheckSmi(rbx));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001176 __ Check(not_smi, kUnexpectedInitialMapForArrayFunction);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001177 __ CmpObjectType(rbx, MAP_TYPE, rcx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001178 __ Check(equal, kUnexpectedInitialMapForArrayFunction);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001179 }
1180
1181 // Run the native code for the Array function called as a normal function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001182 // tail call a stub
1183 __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
1184 ArrayConstructorStub stub(masm->isolate());
1185 __ TailCallStub(&stub);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001186}
1187
1188
1189void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001190 // ----------- S t a t e -------------
1191 // -- rax : number of arguments
1192 // -- rdi : constructor function
1193 // -- rsp[0] : return address
1194 // -- rsp[(argc - n) * 8] : arg[n] (zero-based)
1195 // -- rsp[(argc + 1) * 8] : receiver
1196 // -----------------------------------
1197 Counters* counters = masm->isolate()->counters();
1198 __ IncrementCounter(counters->string_ctor_calls(), 1);
1199
1200 if (FLAG_debug_code) {
1201 __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, rcx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001202 __ cmpp(rdi, rcx);
1203 __ Assert(equal, kUnexpectedStringFunction);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001204 }
1205
1206 // Load the first argument into rax and get rid of the rest
1207 // (including the receiver).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001208 StackArgumentsAccessor args(rsp, rax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001209 Label no_arguments;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001210 __ testp(rax, rax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001211 __ j(zero, &no_arguments);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001212 __ movp(rbx, args.GetArgumentOperand(1));
1213 __ PopReturnAddressTo(rcx);
1214 __ leap(rsp, Operand(rsp, rax, times_pointer_size, kPointerSize));
1215 __ PushReturnAddressFrom(rcx);
1216 __ movp(rax, rbx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001217
1218 // Lookup the argument in the number to string cache.
1219 Label not_cached, argument_is_string;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001220 __ LookupNumberStringCache(rax, // Input.
1221 rbx, // Result.
1222 rcx, // Scratch 1.
1223 rdx, // Scratch 2.
1224 &not_cached);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001225 __ IncrementCounter(counters->string_ctor_cached_number(), 1);
1226 __ bind(&argument_is_string);
1227
1228 // ----------- S t a t e -------------
1229 // -- rbx : argument converted to string
1230 // -- rdi : constructor function
1231 // -- rsp[0] : return address
1232 // -----------------------------------
1233
1234 // Allocate a JSValue and put the tagged pointer into rax.
1235 Label gc_required;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001236 __ Allocate(JSValue::kSize,
1237 rax, // Result.
1238 rcx, // New allocation top (we ignore it).
1239 no_reg,
1240 &gc_required,
1241 TAG_OBJECT);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001242
1243 // Set the map.
1244 __ LoadGlobalFunctionInitialMap(rdi, rcx);
1245 if (FLAG_debug_code) {
1246 __ cmpb(FieldOperand(rcx, Map::kInstanceSizeOffset),
1247 Immediate(JSValue::kSize >> kPointerSizeLog2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001248 __ Assert(equal, kUnexpectedStringWrapperInstanceSize);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001249 __ cmpb(FieldOperand(rcx, Map::kUnusedPropertyFieldsOffset), Immediate(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001250 __ Assert(equal, kUnexpectedUnusedPropertiesOfStringWrapper);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001251 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001252 __ movp(FieldOperand(rax, HeapObject::kMapOffset), rcx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001253
1254 // Set properties and elements.
1255 __ LoadRoot(rcx, Heap::kEmptyFixedArrayRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001256 __ movp(FieldOperand(rax, JSObject::kPropertiesOffset), rcx);
1257 __ movp(FieldOperand(rax, JSObject::kElementsOffset), rcx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001258
1259 // Set the value.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001260 __ movp(FieldOperand(rax, JSValue::kValueOffset), rbx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001261
1262 // Ensure the object is fully initialized.
1263 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
1264
1265 // We're done. Return.
1266 __ ret(0);
1267
1268 // The argument was not found in the number to string cache. Check
1269 // if it's a string already before calling the conversion builtin.
1270 Label convert_argument;
1271 __ bind(&not_cached);
1272 STATIC_ASSERT(kSmiTag == 0);
1273 __ JumpIfSmi(rax, &convert_argument);
1274 Condition is_string = masm->IsObjectStringType(rax, rbx, rcx);
1275 __ j(NegateCondition(is_string), &convert_argument);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001276 __ movp(rbx, rax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001277 __ IncrementCounter(counters->string_ctor_string_value(), 1);
1278 __ jmp(&argument_is_string);
1279
1280 // Invoke the conversion builtin and put the result into rbx.
1281 __ bind(&convert_argument);
1282 __ IncrementCounter(counters->string_ctor_conversions(), 1);
1283 {
1284 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001285 __ Push(rdi); // Preserve the function.
1286 __ Push(rax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001287 __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001288 __ Pop(rdi);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001289 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001290 __ movp(rbx, rax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001291 __ jmp(&argument_is_string);
1292
1293 // Load the empty string into rbx, remove the receiver from the
1294 // stack, and jump back to the case where the argument is a string.
1295 __ bind(&no_arguments);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001296 __ LoadRoot(rbx, Heap::kempty_stringRootIndex);
1297 __ PopReturnAddressTo(rcx);
1298 __ leap(rsp, Operand(rsp, kPointerSize));
1299 __ PushReturnAddressFrom(rcx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001300 __ jmp(&argument_is_string);
1301
1302 // At this point the argument is already a string. Call runtime to
1303 // create a string wrapper.
1304 __ bind(&gc_required);
1305 __ IncrementCounter(counters->string_ctor_gc_required(), 1);
1306 {
1307 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001308 __ Push(rbx);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001309 __ CallRuntime(Runtime::kNewStringWrapper, 1);
1310 }
1311 __ ret(0);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001312}
1313
1314
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001315static void ArgumentsAdaptorStackCheck(MacroAssembler* masm,
1316 Label* stack_overflow) {
1317 // ----------- S t a t e -------------
1318 // -- rax : actual number of arguments
1319 // -- rbx : expected number of arguments
1320 // -- rdi: function (passed through to callee)
1321 // -----------------------------------
1322 // Check the stack for overflow. We are not trying to catch
1323 // interruptions (e.g. debug break and preemption) here, so the "real stack
1324 // limit" is checked.
1325 Label okay;
1326 __ LoadRoot(rdx, Heap::kRealStackLimitRootIndex);
1327 __ movp(rcx, rsp);
1328 // Make rcx the space we have left. The stack might already be overflowed
1329 // here which will cause rcx to become negative.
1330 __ subp(rcx, rdx);
1331 // Make rdx the space we need for the array when it is unrolled onto the
1332 // stack.
1333 __ movp(rdx, rbx);
1334 __ shlp(rdx, Immediate(kPointerSizeLog2));
1335 // Check if the arguments will overflow the stack.
1336 __ cmpp(rcx, rdx);
1337 __ j(less_equal, stack_overflow); // Signed comparison.
1338}
1339
1340
Ben Murdochb0fe1622011-05-05 13:52:32 +01001341static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001342 __ pushq(rbp);
1343 __ movp(rbp, rsp);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001344
1345 // Store the arguments adaptor context sentinel.
1346 __ Push(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
1347
1348 // Push the function on the stack.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001349 __ Push(rdi);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001350
Ben Murdoch257744e2011-11-30 15:57:28 +00001351 // Preserve the number of arguments on the stack. Must preserve rax,
1352 // rbx and rcx because these registers are used when copying the
Ben Murdochb0fe1622011-05-05 13:52:32 +01001353 // arguments and the receiver.
Ben Murdoch257744e2011-11-30 15:57:28 +00001354 __ Integer32ToSmi(r8, rax);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001355 __ Push(r8);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001356}
1357
1358
1359static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1360 // Retrieve the number of arguments from the stack. Number is a Smi.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001361 __ movp(rbx, Operand(rbp, ArgumentsAdaptorFrameConstants::kLengthOffset));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001362
1363 // Leave the frame.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001364 __ movp(rsp, rbp);
1365 __ popq(rbp);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001366
1367 // Remove caller arguments from the stack.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001368 __ PopReturnAddressTo(rcx);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001369 SmiIndex index = masm->SmiToIndex(rbx, rbx, kPointerSizeLog2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001370 __ leap(rsp, Operand(rsp, index.reg, index.scale, 1 * kPointerSize));
1371 __ PushReturnAddressFrom(rcx);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001372}
1373
1374
1375void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1376 // ----------- S t a t e -------------
1377 // -- rax : actual number of arguments
1378 // -- rbx : expected number of arguments
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001379 // -- rdi: function (passed through to callee)
Ben Murdochb0fe1622011-05-05 13:52:32 +01001380 // -----------------------------------
1381
1382 Label invoke, dont_adapt_arguments;
Steve Block44f0eee2011-05-26 01:26:41 +01001383 Counters* counters = masm->isolate()->counters();
1384 __ IncrementCounter(counters->arguments_adaptors(), 1);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001385
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001386 Label stack_overflow;
1387 ArgumentsAdaptorStackCheck(masm, &stack_overflow);
1388
Ben Murdochb0fe1622011-05-05 13:52:32 +01001389 Label enough, too_few;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001390 __ movp(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
1391 __ cmpp(rax, rbx);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001392 __ j(less, &too_few);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001393 __ cmpp(rbx, Immediate(SharedFunctionInfo::kDontAdaptArgumentsSentinel));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001394 __ j(equal, &dont_adapt_arguments);
1395
1396 { // Enough parameters: Actual >= expected.
1397 __ bind(&enough);
1398 EnterArgumentsAdaptorFrame(masm);
1399
1400 // Copy receiver and all expected arguments.
1401 const int offset = StandardFrameConstants::kCallerSPOffset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001402 __ leap(rax, Operand(rbp, rax, times_pointer_size, offset));
Ben Murdoch257744e2011-11-30 15:57:28 +00001403 __ Set(r8, -1); // account for receiver
Ben Murdochb0fe1622011-05-05 13:52:32 +01001404
1405 Label copy;
1406 __ bind(&copy);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001407 __ incp(r8);
1408 __ Push(Operand(rax, 0));
1409 __ subp(rax, Immediate(kPointerSize));
1410 __ cmpp(r8, rbx);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001411 __ j(less, &copy);
1412 __ jmp(&invoke);
1413 }
1414
1415 { // Too few parameters: Actual < expected.
1416 __ bind(&too_few);
1417 EnterArgumentsAdaptorFrame(masm);
1418
1419 // Copy receiver and all actual arguments.
1420 const int offset = StandardFrameConstants::kCallerSPOffset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001421 __ leap(rdi, Operand(rbp, rax, times_pointer_size, offset));
Ben Murdoch257744e2011-11-30 15:57:28 +00001422 __ Set(r8, -1); // account for receiver
Ben Murdochb0fe1622011-05-05 13:52:32 +01001423
1424 Label copy;
1425 __ bind(&copy);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001426 __ incp(r8);
1427 __ Push(Operand(rdi, 0));
1428 __ subp(rdi, Immediate(kPointerSize));
1429 __ cmpp(r8, rax);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001430 __ j(less, &copy);
1431
1432 // Fill remaining expected arguments with undefined values.
1433 Label fill;
1434 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
1435 __ bind(&fill);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001436 __ incp(r8);
1437 __ Push(kScratchRegister);
1438 __ cmpp(r8, rbx);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001439 __ j(less, &fill);
1440
1441 // Restore function pointer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001442 __ movp(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001443 }
1444
1445 // Call the entry point.
1446 __ bind(&invoke);
1447 __ call(rdx);
1448
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001449 // Store offset of return address for deoptimizer.
1450 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
1451
Ben Murdochb0fe1622011-05-05 13:52:32 +01001452 // Leave frame and return.
1453 LeaveArgumentsAdaptorFrame(masm);
1454 __ ret(0);
1455
1456 // -------------------------------------------
1457 // Dont adapt arguments.
1458 // -------------------------------------------
1459 __ bind(&dont_adapt_arguments);
1460 __ jmp(rdx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001461
1462 __ bind(&stack_overflow);
1463 {
1464 FrameScope frame(masm, StackFrame::MANUAL);
1465 EnterArgumentsAdaptorFrame(masm);
1466 __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
1467 __ int3();
1468 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001469}
1470
1471
1472void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001473 // Lookup the function in the JavaScript frame.
1474 __ movp(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001475 {
1476 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001477 // Pass function as argument.
1478 __ Push(rax);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001479 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
1480 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001481
Ben Murdoch257744e2011-11-30 15:57:28 +00001482 Label skip;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001483 // If the code object is null, just return to the unoptimized code.
1484 __ cmpp(rax, Immediate(0));
Ben Murdoch257744e2011-11-30 15:57:28 +00001485 __ j(not_equal, &skip, Label::kNear);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001486 __ ret(0);
1487
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001488 __ bind(&skip);
1489
1490 // Load deoptimization data from the code object.
1491 __ movp(rbx, Operand(rax, Code::kDeoptimizationDataOffset - kHeapObjectTag));
1492
1493 // Load the OSR entrypoint offset from the deoptimization data.
1494 __ SmiToInteger32(rbx, Operand(rbx, FixedArray::OffsetOfElementAt(
1495 DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag));
1496
1497 // Compute the target address = code_obj + header_size + osr_offset
1498 __ leap(rax, Operand(rax, rbx, times_1, Code::kHeaderSize - kHeapObjectTag));
1499
1500 // Overwrite the return address on the stack.
1501 __ movq(StackOperandForReturnAddress(0), rax);
1502
1503 // And "return" to the OSR entry point of the function.
1504 __ ret(0);
1505}
1506
1507
1508void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
1509 // We check the stack limit as indicator that recompilation might be done.
Ben Murdoch257744e2011-11-30 15:57:28 +00001510 Label ok;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001511 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001512 __ j(above_equal, &ok);
1513 {
1514 FrameScope scope(masm, StackFrame::INTERNAL);
1515 __ CallRuntime(Runtime::kStackGuard, 0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001516 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001517 __ jmp(masm->isolate()->builtins()->OnStackReplacement(),
1518 RelocInfo::CODE_TARGET);
1519
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001520 __ bind(&ok);
1521 __ ret(0);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001522}
1523
1524
1525#undef __
1526
Steve Blocka7e24c12009-10-30 11:49:00 +00001527} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01001528
1529#endif // V8_TARGET_ARCH_X64