blob: 55ec55fc6f8683e8c335fa5a587bb612388d4557 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#if V8_TARGET_ARCH_X87
6
7#include "src/code-factory.h"
8#include "src/codegen.h"
9#include "src/deoptimizer.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010#include "src/full-codegen/full-codegen.h"
11#include "src/x87/frames-x87.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012
13namespace v8 {
14namespace internal {
15
16
17#define __ ACCESS_MASM(masm)
18
19
20void Builtins::Generate_Adaptor(MacroAssembler* masm,
21 CFunctionId id,
22 BuiltinExtraArguments extra_args) {
23 // ----------- S t a t e -------------
24 // -- eax : number of arguments excluding receiver
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000025 // -- edi : target
26 // -- edx : new.target
Ben Murdochb8a8cc12014-11-26 15:28:44 +000027 // -- esp[0] : return address
28 // -- esp[4] : last argument
29 // -- ...
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000030 // -- esp[4 * argc] : first argument
Ben Murdochb8a8cc12014-11-26 15:28:44 +000031 // -- esp[4 * (argc +1)] : receiver
32 // -----------------------------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000033 __ AssertFunction(edi);
34
35 // Make sure we operate in the context of the called function (for example
36 // ConstructStubs implemented in C++ will be run in the context of the caller
37 // instead of the callee, due to the way that [[Construct]] is defined for
38 // ordinary functions).
39 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000040
41 // Insert extra arguments.
42 int num_extra_args = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000043 if (extra_args != BuiltinExtraArguments::kNone) {
44 __ PopReturnAddressTo(ecx);
45 if (extra_args & BuiltinExtraArguments::kTarget) {
46 ++num_extra_args;
47 __ Push(edi);
48 }
49 if (extra_args & BuiltinExtraArguments::kNewTarget) {
50 ++num_extra_args;
51 __ Push(edx);
52 }
53 __ PushReturnAddressFrom(ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000054 }
55
56 // JumpToExternalReference expects eax to contain the number of arguments
57 // including the receiver and the extra arguments.
58 __ add(eax, Immediate(num_extra_args + 1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000059
Ben Murdochb8a8cc12014-11-26 15:28:44 +000060 __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
61}
62
63
64static void CallRuntimePassFunction(
65 MacroAssembler* masm, Runtime::FunctionId function_id) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000066 // ----------- S t a t e -------------
67 // -- edx : new target (preserved for callee)
68 // -- edi : target function (preserved for callee)
69 // -----------------------------------
70
Ben Murdochb8a8cc12014-11-26 15:28:44 +000071 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000072 // Push a copy of the target function and the new target.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000073 __ push(edi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000074 __ push(edx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000075 // Function is also the parameter to the runtime call.
76 __ push(edi);
77
78 __ CallRuntime(function_id, 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000079 // Restore target function and new target.
80 __ pop(edx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000081 __ pop(edi);
82}
83
84
85static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
86 __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
87 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kCodeOffset));
88 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
89 __ jmp(eax);
90}
91
92
93static void GenerateTailCallToReturnedCode(MacroAssembler* masm) {
94 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
95 __ jmp(eax);
96}
97
98
99void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
100 // Checking whether the queued function is ready for install is optional,
101 // since we come across interrupts and stack checks elsewhere. However,
102 // not checking may delay installing ready functions, and always checking
103 // would be quite expensive. A good compromise is to first check against
104 // stack limit as a cue for an interrupt signal.
105 Label ok;
106 ExternalReference stack_limit =
107 ExternalReference::address_of_stack_limit(masm->isolate());
108 __ cmp(esp, Operand::StaticVariable(stack_limit));
109 __ j(above_equal, &ok, Label::kNear);
110
111 CallRuntimePassFunction(masm, Runtime::kTryInstallOptimizedCode);
112 GenerateTailCallToReturnedCode(masm);
113
114 __ bind(&ok);
115 GenerateTailCallToSharedCode(masm);
116}
117
118
119static void Generate_JSConstructStubHelper(MacroAssembler* masm,
120 bool is_api_function,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000121 bool create_implicit_receiver) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000122 // ----------- S t a t e -------------
123 // -- eax: number of arguments
124 // -- edi: constructor function
125 // -- ebx: allocation site or undefined
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000126 // -- edx: new target
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000127 // -----------------------------------
128
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000129 // Enter a construct frame.
130 {
131 FrameScope scope(masm, StackFrame::CONSTRUCT);
132
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000133 // Preserve the incoming parameters on the stack.
134 __ AssertUndefinedOrAllocationSite(ebx);
135 __ push(ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000136 __ SmiTag(eax);
137 __ push(eax);
138
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000139 if (create_implicit_receiver) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000140 __ push(edi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000141 __ push(edx);
142
143 // Try to allocate the object without transitioning into C code. If any of
144 // the preconditions is not met, the code bails out to the runtime call.
145 Label rt_call, allocated;
146 if (FLAG_inline_new) {
147 // Verify that the new target is a JSFunction.
148 __ CmpObjectType(edx, JS_FUNCTION_TYPE, ebx);
149 __ j(not_equal, &rt_call);
150
151 // Load the initial map and verify that it is in fact a map.
152 // edx: new target
153 __ mov(eax,
154 FieldOperand(edx, JSFunction::kPrototypeOrInitialMapOffset));
155 // Will both indicate a NULL and a Smi
156 __ JumpIfSmi(eax, &rt_call);
157 // edi: constructor
158 // eax: initial map (if proven valid below)
159 __ CmpObjectType(eax, MAP_TYPE, ebx);
160 __ j(not_equal, &rt_call);
161
162 // Fall back to runtime if the expected base constructor and base
163 // constructor differ.
164 __ cmp(edi, FieldOperand(eax, Map::kConstructorOrBackPointerOffset));
165 __ j(not_equal, &rt_call);
166
167 // Check that the constructor is not constructing a JSFunction (see
168 // comments in Runtime_NewObject in runtime.cc). In which case the
169 // initial map's instance type would be JS_FUNCTION_TYPE.
170 // edi: constructor
171 // eax: initial map
172 __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
173 __ j(equal, &rt_call);
174
175 // Now allocate the JSObject on the heap.
176 // edi: constructor
177 // eax: initial map
178 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset));
179 __ shl(edi, kPointerSizeLog2);
180
181 __ Allocate(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS);
182
183 Factory* factory = masm->isolate()->factory();
184
185 // Allocated the JSObject, now initialize the fields.
186 // eax: initial map
187 // ebx: JSObject (not HeapObject tagged - the actual address).
188 // edi: start of next object
189 __ mov(Operand(ebx, JSObject::kMapOffset), eax);
190 __ mov(ecx, factory->empty_fixed_array());
191 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
192 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
193 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
194
195 // Add the object tag to make the JSObject real, so that we can continue
196 // and jump into the continuation code at any time from now on.
197 __ or_(ebx, Immediate(kHeapObjectTag));
198
199 // Fill all the in-object properties with the appropriate filler.
200 // ebx: JSObject (tagged)
201 // ecx: First in-object property of JSObject (not tagged)
202 __ mov(edx, factory->undefined_value());
203
204 if (!is_api_function) {
205 Label no_inobject_slack_tracking;
206
207 // The code below relies on these assumptions.
208 STATIC_ASSERT(Map::kNoSlackTracking == 0);
209 STATIC_ASSERT(Map::ConstructionCounter::kNext == 32);
210 // Check if slack tracking is enabled.
211 __ mov(esi, FieldOperand(eax, Map::kBitField3Offset));
212 __ shr(esi, Map::ConstructionCounter::kShift);
213 __ j(zero, &no_inobject_slack_tracking); // Map::kNoSlackTracking
214 __ push(esi); // Save allocation count value.
215 // Decrease generous allocation count.
216 __ sub(FieldOperand(eax, Map::kBitField3Offset),
217 Immediate(1 << Map::ConstructionCounter::kShift));
218
219 // Allocate object with a slack.
220 __ movzx_b(esi, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
221 __ neg(esi);
222 __ lea(esi, Operand(edi, esi, times_pointer_size, 0));
223 // esi: offset of first field after pre-allocated fields
224 if (FLAG_debug_code) {
225 __ cmp(ecx, esi);
226 __ Assert(less_equal,
227 kUnexpectedNumberOfPreAllocatedPropertyFields);
228 }
229 __ InitializeFieldsWithFiller(ecx, esi, edx);
230
231 // To allow truncation fill the remaining fields with one pointer
232 // filler map.
233 __ mov(edx, factory->one_pointer_filler_map());
234 __ InitializeFieldsWithFiller(ecx, edi, edx);
235
236 __ pop(esi); // Restore allocation count value before decreasing.
237 __ cmp(esi, Map::kSlackTrackingCounterEnd);
238 __ j(not_equal, &allocated);
239
240 // Push the object to the stack, and then the initial map as
241 // an argument to the runtime call.
242 __ push(ebx);
243 __ push(eax); // initial map
244 __ CallRuntime(Runtime::kFinalizeInstanceSize);
245 __ pop(ebx);
246
247 // Continue with JSObject being successfully allocated
248 // ebx: JSObject (tagged)
249 __ jmp(&allocated);
250
251 __ bind(&no_inobject_slack_tracking);
252 }
253
254 __ InitializeFieldsWithFiller(ecx, edi, edx);
255
256 // Continue with JSObject being successfully allocated
257 // ebx: JSObject (tagged)
258 __ jmp(&allocated);
259 }
260
261 // Allocate the new receiver object using the runtime call.
262 // edx: new target
263 __ bind(&rt_call);
264 int offset = kPointerSize;
265
266 // Must restore esi (context) and edi (constructor) before calling
267 // runtime.
268 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
269 __ mov(edi, Operand(esp, offset));
270 __ push(edi); // constructor function
271 __ push(edx); // new target
272 __ CallRuntime(Runtime::kNewObject);
273 __ mov(ebx, eax); // store result in ebx
274
275 // New object allocated.
276 // ebx: newly allocated object
277 __ bind(&allocated);
278
279 // Restore the parameters.
280 __ pop(edx); // new.target
281 __ pop(edi); // Constructor function.
282
283 // Retrieve smi-tagged arguments count from the stack.
284 __ mov(eax, Operand(esp, 0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000285 }
286
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000287 __ SmiUntag(eax);
288
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000289 if (create_implicit_receiver) {
290 // Push the allocated receiver to the stack. We need two copies
291 // because we may have to return the original one and the calling
292 // conventions dictate that the called function pops the receiver.
293 __ push(ebx);
294 __ push(ebx);
295 } else {
296 __ PushRoot(Heap::kTheHoleValueRootIndex);
297 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000298
299 // Set up pointer to last argument.
300 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
301
302 // Copy arguments and receiver to the expression stack.
303 Label loop, entry;
304 __ mov(ecx, eax);
305 __ jmp(&entry);
306 __ bind(&loop);
307 __ push(Operand(ebx, ecx, times_4, 0));
308 __ bind(&entry);
309 __ dec(ecx);
310 __ j(greater_equal, &loop);
311
312 // Call the function.
313 if (is_api_function) {
314 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
315 Handle<Code> code =
316 masm->isolate()->builtins()->HandleApiCallConstruct();
317 __ call(code, RelocInfo::CODE_TARGET);
318 } else {
319 ParameterCount actual(eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000320 __ InvokeFunction(edi, edx, actual, CALL_FUNCTION,
321 CheckDebugStepCallWrapper());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000322 }
323
324 // Store offset of return address for deoptimizer.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000325 if (create_implicit_receiver && !is_api_function) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000326 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
327 }
328
329 // Restore context from the frame.
330 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
331
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000332 if (create_implicit_receiver) {
333 // If the result is an object (in the ECMA sense), we should get rid
334 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
335 // on page 74.
336 Label use_receiver, exit;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000337
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000338 // If the result is a smi, it is *not* an object in the ECMA sense.
339 __ JumpIfSmi(eax, &use_receiver);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000340
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000341 // If the type of the result (stored in its map) is less than
342 // FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
343 __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx);
344 __ j(above_equal, &exit);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000345
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000346 // Throw away the result of the constructor invocation and use the
347 // on-stack receiver as the result.
348 __ bind(&use_receiver);
349 __ mov(eax, Operand(esp, 0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000350
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000351 // Restore the arguments count and leave the construct frame. The
352 // arguments count is stored below the receiver.
353 __ bind(&exit);
354 __ mov(ebx, Operand(esp, 1 * kPointerSize));
355 } else {
356 __ mov(ebx, Operand(esp, 0));
357 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000358
359 // Leave construct frame.
360 }
361
362 // Remove caller arguments from the stack and return.
363 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
364 __ pop(ecx);
365 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
366 __ push(ecx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000367 if (create_implicit_receiver) {
368 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
369 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000370 __ ret(0);
371}
372
373
374void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000375 Generate_JSConstructStubHelper(masm, false, true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000376}
377
378
379void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000380 Generate_JSConstructStubHelper(masm, true, true);
381}
382
383
384void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {
385 Generate_JSConstructStubHelper(masm, false, false);
386}
387
388
389void Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) {
390 FrameScope scope(masm, StackFrame::INTERNAL);
391 __ push(edi);
392 __ CallRuntime(Runtime::kThrowConstructedNonConstructable);
393}
394
395
396enum IsTagged { kEaxIsSmiTagged, kEaxIsUntaggedInt };
397
398
399// Clobbers ecx, edx, edi; preserves all other registers.
400static void Generate_CheckStackOverflow(MacroAssembler* masm,
401 IsTagged eax_is_tagged) {
402 // eax : the number of items to be pushed to the stack
403 //
404 // Check the stack for overflow. We are not trying to catch
405 // interruptions (e.g. debug break and preemption) here, so the "real stack
406 // limit" is checked.
407 Label okay;
408 ExternalReference real_stack_limit =
409 ExternalReference::address_of_real_stack_limit(masm->isolate());
410 __ mov(edi, Operand::StaticVariable(real_stack_limit));
411 // Make ecx the space we have left. The stack might already be overflowed
412 // here which will cause ecx to become negative.
413 __ mov(ecx, esp);
414 __ sub(ecx, edi);
415 // Make edx the space we need for the array when it is unrolled onto the
416 // stack.
417 __ mov(edx, eax);
418 int smi_tag = eax_is_tagged == kEaxIsSmiTagged ? kSmiTagSize : 0;
419 __ shl(edx, kPointerSizeLog2 - smi_tag);
420 // Check if the arguments will overflow the stack.
421 __ cmp(ecx, edx);
422 __ j(greater, &okay); // Signed comparison.
423
424 // Out of stack space.
425 __ CallRuntime(Runtime::kThrowStackOverflow);
426
427 __ bind(&okay);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000428}
429
430
431static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
432 bool is_construct) {
433 ProfileEntryHookStub::MaybeCallEntryHook(masm);
434
435 // Clear the context before we push it when entering the internal frame.
436 __ Move(esi, Immediate(0));
437
438 {
439 FrameScope scope(masm, StackFrame::INTERNAL);
440
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000441 // Setup the context (we need to use the caller context from the isolate).
442 ExternalReference context_address(Isolate::kContextAddress,
443 masm->isolate());
444 __ mov(esi, Operand::StaticVariable(context_address));
445
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000446 // Load the previous frame pointer (ebx) to access C arguments
447 __ mov(ebx, Operand(ebp, 0));
448
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000449 // Push the function and the receiver onto the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000450 __ push(Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000451 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
452
453 // Load the number of arguments and setup pointer to the arguments.
454 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
455 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
456
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000457 // Check if we have enough stack space to push all arguments.
458 // Expects argument count in eax. Clobbers ecx, edx, edi.
459 Generate_CheckStackOverflow(masm, kEaxIsUntaggedInt);
460
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000461 // Copy arguments to the stack in a loop.
462 Label loop, entry;
463 __ Move(ecx, Immediate(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000464 __ jmp(&entry, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000465 __ bind(&loop);
466 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv
467 __ push(Operand(edx, 0)); // dereference handle
468 __ inc(ecx);
469 __ bind(&entry);
470 __ cmp(ecx, eax);
471 __ j(not_equal, &loop);
472
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000473 // Load the previous frame pointer (ebx) to access C arguments
474 __ mov(ebx, Operand(ebp, 0));
475
476 // Get the new.target and function from the frame.
477 __ mov(edx, Operand(ebx, EntryFrameConstants::kNewTargetArgOffset));
478 __ mov(edi, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000479
480 // Invoke the code.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000481 Handle<Code> builtin = is_construct
482 ? masm->isolate()->builtins()->Construct()
483 : masm->isolate()->builtins()->Call();
484 __ Call(builtin, RelocInfo::CODE_TARGET);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000485
486 // Exit the internal frame. Notice that this also removes the empty.
487 // context and the function left on the stack by the code
488 // invocation.
489 }
490 __ ret(kPointerSize); // Remove receiver.
491}
492
493
494void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
495 Generate_JSEntryTrampolineHelper(masm, false);
496}
497
498
499void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
500 Generate_JSEntryTrampolineHelper(masm, true);
501}
502
503
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000504// Generate code for entering a JS function with the interpreter.
505// On entry to the function the receiver and arguments have been pushed on the
506// stack left to right. The actual argument count matches the formal parameter
507// count expected by the function.
508//
509// The live registers are:
510// o edi: the JS function object being called
511// o edx: the new target
512// o esi: our context
513// o ebp: the caller's frame pointer
514// o esp: stack pointer (pointing to return address)
515//
516// The function builds a JS frame. Please see JavaScriptFrameConstants in
517// frames-ia32.h for its layout.
518// TODO(rmcilroy): We will need to include the current bytecode pointer in the
519// frame.
520void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
521 // Open a frame scope to indicate that there is a frame on the stack. The
522 // MANUAL indicates that the scope shouldn't actually generate code to set up
523 // the frame (that is done below).
524 FrameScope frame_scope(masm, StackFrame::MANUAL);
525 __ push(ebp); // Caller's frame pointer.
526 __ mov(ebp, esp);
527 __ push(esi); // Callee's context.
528 __ push(edi); // Callee's JS function.
529 __ push(edx); // Callee's new target.
530
531 // Push zero for bytecode array offset.
532 __ push(Immediate(0));
533
534 // Get the bytecode array from the function object and load the pointer to the
535 // first entry into edi (InterpreterBytecodeRegister).
536 __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
537 __ mov(kInterpreterBytecodeArrayRegister,
538 FieldOperand(eax, SharedFunctionInfo::kFunctionDataOffset));
539
540 if (FLAG_debug_code) {
541 // Check function data field is actually a BytecodeArray object.
542 __ AssertNotSmi(kInterpreterBytecodeArrayRegister);
543 __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE,
544 eax);
545 __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
546 }
547
548 // Allocate the local and temporary register file on the stack.
549 {
550 // Load frame size from the BytecodeArray object.
551 __ mov(ebx, FieldOperand(kInterpreterBytecodeArrayRegister,
552 BytecodeArray::kFrameSizeOffset));
553
554 // Do a stack check to ensure we don't go over the limit.
555 Label ok;
556 __ mov(ecx, esp);
557 __ sub(ecx, ebx);
558 ExternalReference stack_limit =
559 ExternalReference::address_of_real_stack_limit(masm->isolate());
560 __ cmp(ecx, Operand::StaticVariable(stack_limit));
561 __ j(above_equal, &ok);
562 __ CallRuntime(Runtime::kThrowStackOverflow);
563 __ bind(&ok);
564
565 // If ok, push undefined as the initial value for all register file entries.
566 Label loop_header;
567 Label loop_check;
568 __ mov(eax, Immediate(masm->isolate()->factory()->undefined_value()));
569 __ jmp(&loop_check);
570 __ bind(&loop_header);
571 // TODO(rmcilroy): Consider doing more than one push per loop iteration.
572 __ push(eax);
573 // Continue loop if not done.
574 __ bind(&loop_check);
575 __ sub(ebx, Immediate(kPointerSize));
576 __ j(greater_equal, &loop_header);
577 }
578
579 // TODO(rmcilroy): List of things not currently dealt with here but done in
580 // fullcodegen's prologue:
581 // - Support profiler (specifically profiling_counter).
582 // - Call ProfileEntryHookStub when isolate has a function_entry_hook.
583 // - Allow simulator stop operations if FLAG_stop_at is set.
584 // - Code aging of the BytecodeArray object.
585
586 // Perform stack guard check.
587 {
588 Label ok;
589 ExternalReference stack_limit =
590 ExternalReference::address_of_stack_limit(masm->isolate());
591 __ cmp(esp, Operand::StaticVariable(stack_limit));
592 __ j(above_equal, &ok);
593 __ push(kInterpreterBytecodeArrayRegister);
594 __ CallRuntime(Runtime::kStackGuard);
595 __ pop(kInterpreterBytecodeArrayRegister);
596 __ bind(&ok);
597 }
598
599 // Load accumulator, register file, bytecode offset, dispatch table into
600 // registers.
601 __ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
602 __ mov(kInterpreterRegisterFileRegister, ebp);
603 __ add(kInterpreterRegisterFileRegister,
604 Immediate(InterpreterFrameConstants::kRegisterFilePointerFromFp));
605 __ mov(kInterpreterBytecodeOffsetRegister,
606 Immediate(BytecodeArray::kHeaderSize - kHeapObjectTag));
607 // Since the dispatch table root might be set after builtins are generated,
608 // load directly from the roots table.
609 __ LoadRoot(ebx, Heap::kInterpreterTableRootIndex);
610 __ add(ebx, Immediate(FixedArray::kHeaderSize - kHeapObjectTag));
611
612 // Push dispatch table as a stack located parameter to the bytecode handler.
613 DCHECK_EQ(-1, kInterpreterDispatchTableSpillSlot);
614 __ push(ebx);
615
616 // Dispatch to the first bytecode handler for the function.
617 __ movzx_b(eax, Operand(kInterpreterBytecodeArrayRegister,
618 kInterpreterBytecodeOffsetRegister, times_1, 0));
619 __ mov(ebx, Operand(ebx, eax, times_pointer_size, 0));
620 // Restore undefined_value in accumulator (eax)
621 // TODO(rmcilroy): Remove this once we move the dispatch table back into a
622 // register.
623 __ mov(eax, Immediate(masm->isolate()->factory()->undefined_value()));
624 // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
625 // and header removal.
626 __ add(ebx, Immediate(Code::kHeaderSize - kHeapObjectTag));
627 __ call(ebx);
628 __ nop(); // Ensure that return address still counts as interpreter entry
629 // trampoline.
630}
631
632
633void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
634 // TODO(rmcilroy): List of things not currently dealt with here but done in
635 // fullcodegen's EmitReturnSequence.
636 // - Supporting FLAG_trace for Runtime::TraceExit.
637 // - Support profiler (specifically decrementing profiling_counter
638 // appropriately and calling out to HandleInterrupts if necessary).
639
640 // The return value is in accumulator, which is already in rax.
641
642 // Leave the frame (also dropping the register file).
643 __ leave();
644
645 // Drop receiver + arguments and return.
646 __ mov(ebx, FieldOperand(kInterpreterBytecodeArrayRegister,
647 BytecodeArray::kParameterSizeOffset));
648 __ pop(ecx);
649 __ add(esp, ebx);
650 __ push(ecx);
651 __ ret(0);
652}
653
654
655static void Generate_InterpreterPushArgs(MacroAssembler* masm,
656 Register array_limit) {
657 // ----------- S t a t e -------------
658 // -- ebx : Pointer to the last argument in the args array.
659 // -- array_limit : Pointer to one before the first argument in the
660 // args array.
661 // -----------------------------------
662 Label loop_header, loop_check;
663 __ jmp(&loop_check);
664 __ bind(&loop_header);
665 __ Push(Operand(ebx, 0));
666 __ sub(ebx, Immediate(kPointerSize));
667 __ bind(&loop_check);
668 __ cmp(ebx, array_limit);
669 __ j(greater, &loop_header, Label::kNear);
670}
671
672
673// static
674void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) {
675 // ----------- S t a t e -------------
676 // -- eax : the number of arguments (not including the receiver)
677 // -- ebx : the address of the first argument to be pushed. Subsequent
678 // arguments should be consecutive above this, in the same order as
679 // they are to be pushed onto the stack.
680 // -- edi : the target to call (can be any Object).
681 // -----------------------------------
682
683 // Pop return address to allow tail-call after pushing arguments.
684 __ Pop(edx);
685
686 // Find the address of the last argument.
687 __ mov(ecx, eax);
688 __ add(ecx, Immediate(1)); // Add one for receiver.
689 __ shl(ecx, kPointerSizeLog2);
690 __ neg(ecx);
691 __ add(ecx, ebx);
692
693 Generate_InterpreterPushArgs(masm, ecx);
694
695 // Call the target.
696 __ Push(edx); // Re-push return address.
697 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
698}
699
700
701// static
702void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) {
703 // ----------- S t a t e -------------
704 // -- eax : the number of arguments (not including the receiver)
705 // -- edx : the new target
706 // -- edi : the constructor
707 // -- ebx : the address of the first argument to be pushed. Subsequent
708 // arguments should be consecutive above this, in the same order as
709 // they are to be pushed onto the stack.
710 // -----------------------------------
711
712 // Save number of arguments on the stack below where arguments are going
713 // to be pushed.
714 __ mov(ecx, eax);
715 __ neg(ecx);
716 __ mov(Operand(esp, ecx, times_pointer_size, -kPointerSize), eax);
717 __ mov(eax, ecx);
718
719 // Pop return address to allow tail-call after pushing arguments.
720 __ Pop(ecx);
721
722 // Find the address of the last argument.
723 __ shl(eax, kPointerSizeLog2);
724 __ add(eax, ebx);
725
726 // Push padding for receiver.
727 __ Push(Immediate(0));
728
729 Generate_InterpreterPushArgs(masm, eax);
730
731 // Restore number of arguments from slot on stack.
732 __ mov(eax, Operand(esp, -kPointerSize));
733
734 // Re-push return address.
735 __ Push(ecx);
736
737 // Call the constructor with unmodified eax, edi, ebi values.
738 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
739}
740
741
742static void Generate_InterpreterNotifyDeoptimizedHelper(
743 MacroAssembler* masm, Deoptimizer::BailoutType type) {
744 // Enter an internal frame.
745 {
746 FrameScope scope(masm, StackFrame::INTERNAL);
747 __ Push(kInterpreterAccumulatorRegister); // Save accumulator register.
748
749 // Pass the deoptimization type to the runtime system.
750 __ Push(Smi::FromInt(static_cast<int>(type)));
751
752 __ CallRuntime(Runtime::kNotifyDeoptimized);
753
754 __ Pop(kInterpreterAccumulatorRegister); // Restore accumulator register.
755 // Tear down internal frame.
756 }
757
758 // Initialize register file register.
759 __ mov(kInterpreterRegisterFileRegister, ebp);
760 __ add(kInterpreterRegisterFileRegister,
761 Immediate(InterpreterFrameConstants::kRegisterFilePointerFromFp));
762
763 // Get the bytecode array pointer from the frame.
764 __ mov(ebx, Operand(kInterpreterRegisterFileRegister,
765 InterpreterFrameConstants::kFunctionFromRegisterPointer));
766 __ mov(ebx, FieldOperand(ebx, JSFunction::kSharedFunctionInfoOffset));
767 __ mov(kInterpreterBytecodeArrayRegister,
768 FieldOperand(ebx, SharedFunctionInfo::kFunctionDataOffset));
769
770 if (FLAG_debug_code) {
771 // Check function data field is actually a BytecodeArray object.
772 __ AssertNotSmi(kInterpreterBytecodeArrayRegister);
773 __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE,
774 ebx);
775 __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
776 }
777
778 // Get the target bytecode offset from the frame.
779 __ mov(
780 kInterpreterBytecodeOffsetRegister,
781 Operand(kInterpreterRegisterFileRegister,
782 InterpreterFrameConstants::kBytecodeOffsetFromRegisterPointer));
783 __ SmiUntag(kInterpreterBytecodeOffsetRegister);
784
785 // Push dispatch table as a stack located parameter to the bytecode handler -
786 // overwrite the state slot (we don't use these for interpreter deopts).
787 __ LoadRoot(ebx, Heap::kInterpreterTableRootIndex);
788 __ add(ebx, Immediate(FixedArray::kHeaderSize - kHeapObjectTag));
789 DCHECK_EQ(-1, kInterpreterDispatchTableSpillSlot);
790 __ mov(Operand(esp, kPointerSize), ebx);
791
792 // Dispatch to the target bytecode.
793 __ movzx_b(esi, Operand(kInterpreterBytecodeArrayRegister,
794 kInterpreterBytecodeOffsetRegister, times_1, 0));
795 __ mov(ebx, Operand(ebx, esi, times_pointer_size, 0));
796
797 // Get the context from the frame.
798 // TODO(rmcilroy): Update interpreter frame to expect current context at the
799 // context slot instead of the function context.
800 __ mov(kContextRegister,
801 Operand(kInterpreterRegisterFileRegister,
802 InterpreterFrameConstants::kContextFromRegisterPointer));
803
804 // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
805 // and header removal.
806 __ add(ebx, Immediate(Code::kHeaderSize - kHeapObjectTag));
807 __ jmp(ebx);
808}
809
810
811void Builtins::Generate_InterpreterNotifyDeoptimized(MacroAssembler* masm) {
812 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
813}
814
815
816void Builtins::Generate_InterpreterNotifySoftDeoptimized(MacroAssembler* masm) {
817 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
818}
819
820
821void Builtins::Generate_InterpreterNotifyLazyDeoptimized(MacroAssembler* masm) {
822 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
823}
824
825
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000826void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
827 CallRuntimePassFunction(masm, Runtime::kCompileLazy);
828 GenerateTailCallToReturnedCode(masm);
829}
830
831
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000832void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000833 CallRuntimePassFunction(masm, Runtime::kCompileOptimized_NotConcurrent);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000834 GenerateTailCallToReturnedCode(masm);
835}
836
837
838void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000839 CallRuntimePassFunction(masm, Runtime::kCompileOptimized_Concurrent);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000840 GenerateTailCallToReturnedCode(masm);
841}
842
843
844static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
845 // For now, we are relying on the fact that make_code_young doesn't do any
846 // garbage collection which allows us to save/restore the registers without
847 // worrying about which of them contain pointers. We also don't build an
848 // internal frame to make the code faster, since we shouldn't have to do stack
849 // crawls in MakeCodeYoung. This seems a bit fragile.
850
851 // Re-execute the code that was patched back to the young age when
852 // the stub returns.
853 __ sub(Operand(esp, 0), Immediate(5));
854 __ pushad();
855 __ mov(eax, Operand(esp, 8 * kPointerSize));
856 {
857 FrameScope scope(masm, StackFrame::MANUAL);
858 __ PrepareCallCFunction(2, ebx);
859 __ mov(Operand(esp, 1 * kPointerSize),
860 Immediate(ExternalReference::isolate_address(masm->isolate())));
861 __ mov(Operand(esp, 0), eax);
862 __ CallCFunction(
863 ExternalReference::get_make_code_young_function(masm->isolate()), 2);
864 }
865 __ popad();
866 __ ret(0);
867}
868
869#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
870void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
871 MacroAssembler* masm) { \
872 GenerateMakeCodeYoungAgainCommon(masm); \
873} \
874void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
875 MacroAssembler* masm) { \
876 GenerateMakeCodeYoungAgainCommon(masm); \
877}
878CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
879#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
880
881
882void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
883 // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
884 // that make_code_young doesn't do any garbage collection which allows us to
885 // save/restore the registers without worrying about which of them contain
886 // pointers.
887 __ pushad();
888 __ mov(eax, Operand(esp, 8 * kPointerSize));
889 __ sub(eax, Immediate(Assembler::kCallInstructionLength));
890 { // NOLINT
891 FrameScope scope(masm, StackFrame::MANUAL);
892 __ PrepareCallCFunction(2, ebx);
893 __ mov(Operand(esp, 1 * kPointerSize),
894 Immediate(ExternalReference::isolate_address(masm->isolate())));
895 __ mov(Operand(esp, 0), eax);
896 __ CallCFunction(
897 ExternalReference::get_mark_code_as_executed_function(masm->isolate()),
898 2);
899 }
900 __ popad();
901
902 // Perform prologue operations usually performed by the young code stub.
903 __ pop(eax); // Pop return address into scratch register.
904 __ push(ebp); // Caller's frame pointer.
905 __ mov(ebp, esp);
906 __ push(esi); // Callee's context.
907 __ push(edi); // Callee's JS Function.
908 __ push(eax); // Push return address after frame prologue.
909
910 // Jump to point after the code-age stub.
911 __ ret(0);
912}
913
914
915void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
916 GenerateMakeCodeYoungAgainCommon(masm);
917}
918
919
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000920void Builtins::Generate_MarkCodeAsToBeExecutedOnce(MacroAssembler* masm) {
921 Generate_MarkCodeAsExecutedOnce(masm);
922}
923
924
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000925static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
926 SaveFPRegsMode save_doubles) {
927 // Enter an internal frame.
928 {
929 FrameScope scope(masm, StackFrame::INTERNAL);
930
931 // Preserve registers across notification, this is important for compiled
932 // stubs that tail call the runtime on deopts passing their parameters in
933 // registers.
934 __ pushad();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000935 __ CallRuntime(Runtime::kNotifyStubFailure, save_doubles);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000936 __ popad();
937 // Tear down internal frame.
938 }
939
940 __ pop(MemOperand(esp, 0)); // Ignore state offset
941 __ ret(0); // Return to IC Miss stub, continuation still on stack.
942}
943
944
945void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
946 Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
947}
948
949
950void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
951 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
952}
953
954
955static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
956 Deoptimizer::BailoutType type) {
957 {
958 FrameScope scope(masm, StackFrame::INTERNAL);
959
960 // Pass deoptimization type to the runtime system.
961 __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000962 __ CallRuntime(Runtime::kNotifyDeoptimized);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000963
964 // Tear down internal frame.
965 }
966
967 // Get the full codegen state from the stack and untag it.
968 __ mov(ecx, Operand(esp, 1 * kPointerSize));
969 __ SmiUntag(ecx);
970
971 // Switch on the state.
972 Label not_no_registers, not_tos_eax;
973 __ cmp(ecx, FullCodeGenerator::NO_REGISTERS);
974 __ j(not_equal, &not_no_registers, Label::kNear);
975 __ ret(1 * kPointerSize); // Remove state.
976
977 __ bind(&not_no_registers);
978 __ mov(eax, Operand(esp, 2 * kPointerSize));
979 __ cmp(ecx, FullCodeGenerator::TOS_REG);
980 __ j(not_equal, &not_tos_eax, Label::kNear);
981 __ ret(2 * kPointerSize); // Remove state, eax.
982
983 __ bind(&not_tos_eax);
984 __ Abort(kNoCasesLeft);
985}
986
987
988void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
989 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
990}
991
992
993void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
994 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
995}
996
997
998void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
999 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
1000}
1001
1002
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001003// static
1004void Builtins::Generate_DatePrototype_GetField(MacroAssembler* masm,
1005 int field_index) {
1006 // ----------- S t a t e -------------
1007 // -- esp[0] : return address
1008 // -- esp[4] : receiver
1009 // -----------------------------------
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001010
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001011 // 1. Load receiver into eax and check that it's actually a JSDate object.
1012 Label receiver_not_date;
1013 {
1014 __ mov(eax, Operand(esp, kPointerSize));
1015 __ JumpIfSmi(eax, &receiver_not_date);
1016 __ CmpObjectType(eax, JS_DATE_TYPE, ebx);
1017 __ j(not_equal, &receiver_not_date);
1018 }
1019
1020 // 2. Load the specified date field, falling back to the runtime as necessary.
1021 if (field_index == JSDate::kDateValue) {
1022 __ mov(eax, FieldOperand(eax, JSDate::kValueOffset));
1023 } else {
1024 if (field_index < JSDate::kFirstUncachedField) {
1025 Label stamp_mismatch;
1026 __ mov(edx, Operand::StaticVariable(
1027 ExternalReference::date_cache_stamp(masm->isolate())));
1028 __ cmp(edx, FieldOperand(eax, JSDate::kCacheStampOffset));
1029 __ j(not_equal, &stamp_mismatch, Label::kNear);
1030 __ mov(eax, FieldOperand(
1031 eax, JSDate::kValueOffset + field_index * kPointerSize));
1032 __ ret(1 * kPointerSize);
1033 __ bind(&stamp_mismatch);
1034 }
1035 FrameScope scope(masm, StackFrame::INTERNAL);
1036 __ PrepareCallCFunction(2, ebx);
1037 __ mov(Operand(esp, 0), eax);
1038 __ mov(Operand(esp, 1 * kPointerSize),
1039 Immediate(Smi::FromInt(field_index)));
1040 __ CallCFunction(
1041 ExternalReference::get_date_field_function(masm->isolate()), 2);
1042 }
1043 __ ret(1 * kPointerSize);
1044
1045 // 3. Raise a TypeError if the receiver is not a date.
1046 __ bind(&receiver_not_date);
1047 {
1048 FrameScope scope(masm, StackFrame::MANUAL);
1049 __ EnterFrame(StackFrame::INTERNAL);
1050 __ CallRuntime(Runtime::kThrowNotDateError);
1051 }
1052}
1053
1054
1055// static
1056void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) {
1057 // ----------- S t a t e -------------
1058 // -- eax : argc
1059 // -- esp[0] : return address
1060 // -- esp[4] : argArray
1061 // -- esp[8] : thisArg
1062 // -- esp[12] : receiver
1063 // -----------------------------------
1064
1065 // 1. Load receiver into edi, argArray into eax (if present), remove all
1066 // arguments from the stack (including the receiver), and push thisArg (if
1067 // present) instead.
1068 {
1069 Label no_arg_array, no_this_arg;
1070 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
1071 __ mov(ebx, edx);
1072 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001073 __ test(eax, eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001074 __ j(zero, &no_this_arg, Label::kNear);
1075 {
1076 __ mov(edx, Operand(esp, eax, times_pointer_size, 0));
1077 __ cmp(eax, Immediate(1));
1078 __ j(equal, &no_arg_array, Label::kNear);
1079 __ mov(ebx, Operand(esp, eax, times_pointer_size, -kPointerSize));
1080 __ bind(&no_arg_array);
1081 }
1082 __ bind(&no_this_arg);
1083 __ PopReturnAddressTo(ecx);
1084 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1085 __ Push(edx);
1086 __ PushReturnAddressFrom(ecx);
1087 __ Move(eax, ebx);
1088 }
1089
1090 // ----------- S t a t e -------------
1091 // -- eax : argArray
1092 // -- edi : receiver
1093 // -- esp[0] : return address
1094 // -- esp[4] : thisArg
1095 // -----------------------------------
1096
1097 // 2. Make sure the receiver is actually callable.
1098 Label receiver_not_callable;
1099 __ JumpIfSmi(edi, &receiver_not_callable, Label::kNear);
1100 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
1101 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable);
1102 __ j(zero, &receiver_not_callable, Label::kNear);
1103
1104 // 3. Tail call with no arguments if argArray is null or undefined.
1105 Label no_arguments;
1106 __ JumpIfRoot(eax, Heap::kNullValueRootIndex, &no_arguments, Label::kNear);
1107 __ JumpIfRoot(eax, Heap::kUndefinedValueRootIndex, &no_arguments,
1108 Label::kNear);
1109
1110 // 4a. Apply the receiver to the given argArray (passing undefined for
1111 // new.target).
1112 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
1113 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1114
1115 // 4b. The argArray is either null or undefined, so we tail call without any
1116 // arguments to the receiver.
1117 __ bind(&no_arguments);
1118 {
1119 __ Set(eax, 0);
1120 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1121 }
1122
1123 // 4c. The receiver is not callable, throw an appropriate TypeError.
1124 __ bind(&receiver_not_callable);
1125 {
1126 __ mov(Operand(esp, kPointerSize), edi);
1127 __ TailCallRuntime(Runtime::kThrowApplyNonFunction);
1128 }
1129}
1130
1131
1132// static
1133void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) {
1134 // Stack Layout:
1135 // esp[0] : Return address
1136 // esp[8] : Argument n
1137 // esp[16] : Argument n-1
1138 // ...
1139 // esp[8 * n] : Argument 1
1140 // esp[8 * (n + 1)] : Receiver (callable to call)
1141 //
1142 // eax contains the number of arguments, n, not counting the receiver.
1143 //
1144 // 1. Make sure we have at least one argument.
1145 {
1146 Label done;
1147 __ test(eax, eax);
1148 __ j(not_zero, &done, Label::kNear);
1149 __ PopReturnAddressTo(ebx);
1150 __ PushRoot(Heap::kUndefinedValueRootIndex);
1151 __ PushReturnAddressFrom(ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001152 __ inc(eax);
1153 __ bind(&done);
1154 }
1155
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001156 // 2. Get the callable to call (passed as receiver) from the stack.
1157 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001158
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001159 // 3. Shift arguments and return address one slot down on the stack
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001160 // (overwriting the original receiver). Adjust argument count to make
1161 // the original first argument the new receiver.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001162 {
1163 Label loop;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001164 __ mov(ecx, eax);
1165 __ bind(&loop);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001166 __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0));
1167 __ mov(Operand(esp, ecx, times_pointer_size, kPointerSize), ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001168 __ dec(ecx);
1169 __ j(not_sign, &loop); // While non-negative (to copy return address).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001170 __ pop(ebx); // Discard copy of return address.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001171 __ dec(eax); // One fewer argument (first argument is new receiver).
1172 }
1173
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001174 // 4. Call the callable.
1175 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001176}
1177
1178
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001179void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
1180 // ----------- S t a t e -------------
1181 // -- eax : argc
1182 // -- esp[0] : return address
1183 // -- esp[4] : argumentsList
1184 // -- esp[8] : thisArgument
1185 // -- esp[12] : target
1186 // -- esp[16] : receiver
1187 // -----------------------------------
1188
1189 // 1. Load target into edi (if present), argumentsList into eax (if present),
1190 // remove all arguments from the stack (including the receiver), and push
1191 // thisArgument (if present) instead.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001192 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001193 Label done;
1194 __ LoadRoot(edi, Heap::kUndefinedValueRootIndex);
1195 __ mov(edx, edi);
1196 __ mov(ebx, edi);
1197 __ cmp(eax, Immediate(1));
1198 __ j(below, &done, Label::kNear);
1199 __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize));
1200 __ j(equal, &done, Label::kNear);
1201 __ mov(edx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize));
1202 __ cmp(eax, Immediate(3));
1203 __ j(below, &done, Label::kNear);
1204 __ mov(ebx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize));
1205 __ bind(&done);
1206 __ PopReturnAddressTo(ecx);
1207 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1208 __ Push(edx);
1209 __ PushReturnAddressFrom(ecx);
1210 __ Move(eax, ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001211 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001212
1213 // ----------- S t a t e -------------
1214 // -- eax : argumentsList
1215 // -- edi : target
1216 // -- esp[0] : return address
1217 // -- esp[4] : thisArgument
1218 // -----------------------------------
1219
1220 // 2. Make sure the target is actually callable.
1221 Label target_not_callable;
1222 __ JumpIfSmi(edi, &target_not_callable, Label::kNear);
1223 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
1224 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable);
1225 __ j(zero, &target_not_callable, Label::kNear);
1226
1227 // 3a. Apply the target to the given argumentsList (passing undefined for
1228 // new.target).
1229 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex);
1230 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1231
1232 // 3b. The target is not callable, throw an appropriate TypeError.
1233 __ bind(&target_not_callable);
1234 {
1235 __ mov(Operand(esp, kPointerSize), edi);
1236 __ TailCallRuntime(Runtime::kThrowApplyNonFunction);
1237 }
1238}
1239
1240
1241void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
1242 // ----------- S t a t e -------------
1243 // -- eax : argc
1244 // -- esp[0] : return address
1245 // -- esp[4] : new.target (optional)
1246 // -- esp[8] : argumentsList
1247 // -- esp[12] : target
1248 // -- esp[16] : receiver
1249 // -----------------------------------
1250
1251 // 1. Load target into edi (if present), argumentsList into eax (if present),
1252 // new.target into edx (if present, otherwise use target), remove all
1253 // arguments from the stack (including the receiver), and push thisArgument
1254 // (if present) instead.
1255 {
1256 Label done;
1257 __ LoadRoot(edi, Heap::kUndefinedValueRootIndex);
1258 __ mov(edx, edi);
1259 __ mov(ebx, edi);
1260 __ cmp(eax, Immediate(1));
1261 __ j(below, &done, Label::kNear);
1262 __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize));
1263 __ mov(edx, edi);
1264 __ j(equal, &done, Label::kNear);
1265 __ mov(ebx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize));
1266 __ cmp(eax, Immediate(3));
1267 __ j(below, &done, Label::kNear);
1268 __ mov(edx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize));
1269 __ bind(&done);
1270 __ PopReturnAddressTo(ecx);
1271 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1272 __ PushRoot(Heap::kUndefinedValueRootIndex);
1273 __ PushReturnAddressFrom(ecx);
1274 __ Move(eax, ebx);
1275 }
1276
1277 // ----------- S t a t e -------------
1278 // -- eax : argumentsList
1279 // -- edx : new.target
1280 // -- edi : target
1281 // -- esp[0] : return address
1282 // -- esp[4] : receiver (undefined)
1283 // -----------------------------------
1284
1285 // 2. Make sure the target is actually a constructor.
1286 Label target_not_constructor;
1287 __ JumpIfSmi(edi, &target_not_constructor, Label::kNear);
1288 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset));
1289 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor);
1290 __ j(zero, &target_not_constructor, Label::kNear);
1291
1292 // 3. Make sure the target is actually a constructor.
1293 Label new_target_not_constructor;
1294 __ JumpIfSmi(edx, &new_target_not_constructor, Label::kNear);
1295 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
1296 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor);
1297 __ j(zero, &new_target_not_constructor, Label::kNear);
1298
1299 // 4a. Construct the target with the given new.target and argumentsList.
1300 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET);
1301
1302 // 4b. The target is not a constructor, throw an appropriate TypeError.
1303 __ bind(&target_not_constructor);
1304 {
1305 __ mov(Operand(esp, kPointerSize), edi);
1306 __ TailCallRuntime(Runtime::kThrowCalledNonCallable);
1307 }
1308
1309 // 4c. The new.target is not a constructor, throw an appropriate TypeError.
1310 __ bind(&new_target_not_constructor);
1311 {
1312 __ mov(Operand(esp, kPointerSize), edx);
1313 __ TailCallRuntime(Runtime::kThrowCalledNonCallable);
1314 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001315}
1316
1317
1318void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
1319 // ----------- S t a t e -------------
1320 // -- eax : argc
1321 // -- esp[0] : return address
1322 // -- esp[4] : last argument
1323 // -----------------------------------
1324 Label generic_array_code;
1325
1326 // Get the InternalArray function.
1327 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi);
1328
1329 if (FLAG_debug_code) {
1330 // Initial map for the builtin InternalArray function should be a map.
1331 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1332 // Will both indicate a NULL and a Smi.
1333 __ test(ebx, Immediate(kSmiTagMask));
1334 __ Assert(not_zero, kUnexpectedInitialMapForInternalArrayFunction);
1335 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1336 __ Assert(equal, kUnexpectedInitialMapForInternalArrayFunction);
1337 }
1338
1339 // Run the native code for the InternalArray function called as a normal
1340 // function.
1341 // tail call a stub
1342 InternalArrayConstructorStub stub(masm->isolate());
1343 __ TailCallStub(&stub);
1344}
1345
1346
1347void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1348 // ----------- S t a t e -------------
1349 // -- eax : argc
1350 // -- esp[0] : return address
1351 // -- esp[4] : last argument
1352 // -----------------------------------
1353 Label generic_array_code;
1354
1355 // Get the Array function.
1356 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001357 __ mov(edx, edi);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001358
1359 if (FLAG_debug_code) {
1360 // Initial map for the builtin Array function should be a map.
1361 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1362 // Will both indicate a NULL and a Smi.
1363 __ test(ebx, Immediate(kSmiTagMask));
1364 __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
1365 __ CmpObjectType(ebx, MAP_TYPE, ecx);
1366 __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
1367 }
1368
1369 // Run the native code for the Array function called as a normal function.
1370 // tail call a stub
1371 __ mov(ebx, masm->isolate()->factory()->undefined_value());
1372 ArrayConstructorStub stub(masm->isolate());
1373 __ TailCallStub(&stub);
1374}
1375
1376
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001377// static
1378void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001379 // ----------- S t a t e -------------
1380 // -- eax : number of arguments
1381 // -- edi : constructor function
1382 // -- esp[0] : return address
1383 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1384 // -- esp[(argc + 1) * 4] : receiver
1385 // -----------------------------------
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001386
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001387 // 1. Load the first argument into eax and get rid of the rest (including the
1388 // receiver).
1389 Label no_arguments;
1390 {
1391 __ test(eax, eax);
1392 __ j(zero, &no_arguments, Label::kNear);
1393 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1394 __ PopReturnAddressTo(ecx);
1395 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1396 __ PushReturnAddressFrom(ecx);
1397 __ mov(eax, ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001398 }
1399
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001400 // 2a. Convert the first argument to a number.
1401 ToNumberStub stub(masm->isolate());
1402 __ TailCallStub(&stub);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001403
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001404 // 2b. No arguments, return +0 (already in eax).
1405 __ bind(&no_arguments);
1406 __ ret(1 * kPointerSize);
1407}
1408
1409
1410// static
1411void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001412 // ----------- S t a t e -------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001413 // -- eax : number of arguments
1414 // -- edi : constructor function
1415 // -- edx : new target
1416 // -- esp[0] : return address
1417 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1418 // -- esp[(argc + 1) * 4] : receiver
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001419 // -----------------------------------
1420
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001421 // 1. Make sure we operate in the context of the called function.
1422 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001423
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001424 // 2. Load the first argument into ebx and get rid of the rest (including the
1425 // receiver).
1426 {
1427 Label no_arguments, done;
1428 __ test(eax, eax);
1429 __ j(zero, &no_arguments, Label::kNear);
1430 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1431 __ jmp(&done, Label::kNear);
1432 __ bind(&no_arguments);
1433 __ Move(ebx, Smi::FromInt(0));
1434 __ bind(&done);
1435 __ PopReturnAddressTo(ecx);
1436 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1437 __ PushReturnAddressFrom(ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001438 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001439
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001440 // 3. Make sure ebx is a number.
1441 {
1442 Label done_convert;
1443 __ JumpIfSmi(ebx, &done_convert);
1444 __ CompareRoot(FieldOperand(ebx, HeapObject::kMapOffset),
1445 Heap::kHeapNumberMapRootIndex);
1446 __ j(equal, &done_convert);
1447 {
1448 FrameScope scope(masm, StackFrame::INTERNAL);
1449 __ Push(edi);
1450 __ Push(edx);
1451 __ Move(eax, ebx);
1452 ToNumberStub stub(masm->isolate());
1453 __ CallStub(&stub);
1454 __ Move(ebx, eax);
1455 __ Pop(edx);
1456 __ Pop(edi);
1457 }
1458 __ bind(&done_convert);
1459 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001460
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001461 // 4. Check if new target and constructor differ.
1462 Label new_object;
1463 __ cmp(edx, edi);
1464 __ j(not_equal, &new_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001465
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001466 // 5. Allocate a JSValue wrapper for the number.
1467 __ AllocateJSValue(eax, edi, ebx, ecx, &new_object);
1468 __ Ret();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001469
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001470 // 6. Fallback to the runtime to create new object.
1471 __ bind(&new_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001472 {
1473 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001474 __ Push(ebx); // the first argument
1475 __ Push(edi); // constructor function
1476 __ Push(edx); // new target
1477 __ CallRuntime(Runtime::kNewObject);
1478 __ Pop(FieldOperand(eax, JSValue::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001479 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001480 __ Ret();
1481}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001482
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001483
1484// static
1485void Builtins::Generate_StringConstructor(MacroAssembler* masm) {
1486 // ----------- S t a t e -------------
1487 // -- eax : number of arguments
1488 // -- edi : constructor function
1489 // -- esp[0] : return address
1490 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1491 // -- esp[(argc + 1) * 4] : receiver
1492 // -----------------------------------
1493
1494 // 1. Load the first argument into eax and get rid of the rest (including the
1495 // receiver).
1496 Label no_arguments;
1497 {
1498 __ test(eax, eax);
1499 __ j(zero, &no_arguments, Label::kNear);
1500 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1501 __ PopReturnAddressTo(ecx);
1502 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1503 __ PushReturnAddressFrom(ecx);
1504 __ mov(eax, ebx);
1505 }
1506
1507 // 2a. At least one argument, return eax if it's a string, otherwise
1508 // dispatch to appropriate conversion.
1509 Label to_string, symbol_descriptive_string;
1510 {
1511 __ JumpIfSmi(eax, &to_string, Label::kNear);
1512 STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE);
1513 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
1514 __ j(above, &to_string, Label::kNear);
1515 __ j(equal, &symbol_descriptive_string, Label::kNear);
1516 __ Ret();
1517 }
1518
1519 // 2b. No arguments, return the empty string (and pop the receiver).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001520 __ bind(&no_arguments);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001521 {
1522 __ LoadRoot(eax, Heap::kempty_stringRootIndex);
1523 __ ret(1 * kPointerSize);
1524 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001525
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001526 // 3a. Convert eax to a string.
1527 __ bind(&to_string);
1528 {
1529 ToStringStub stub(masm->isolate());
1530 __ TailCallStub(&stub);
1531 }
1532
1533 // 3b. Convert symbol in eax to a string.
1534 __ bind(&symbol_descriptive_string);
1535 {
1536 __ PopReturnAddressTo(ecx);
1537 __ Push(eax);
1538 __ PushReturnAddressFrom(ecx);
1539 __ TailCallRuntime(Runtime::kSymbolDescriptiveString);
1540 }
1541}
1542
1543
1544// static
1545void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) {
1546 // ----------- S t a t e -------------
1547 // -- eax : number of arguments
1548 // -- edi : constructor function
1549 // -- edx : new target
1550 // -- esp[0] : return address
1551 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1552 // -- esp[(argc + 1) * 4] : receiver
1553 // -----------------------------------
1554
1555 // 1. Make sure we operate in the context of the called function.
1556 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1557
1558 // 2. Load the first argument into ebx and get rid of the rest (including the
1559 // receiver).
1560 {
1561 Label no_arguments, done;
1562 __ test(eax, eax);
1563 __ j(zero, &no_arguments, Label::kNear);
1564 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1565 __ jmp(&done, Label::kNear);
1566 __ bind(&no_arguments);
1567 __ LoadRoot(ebx, Heap::kempty_stringRootIndex);
1568 __ bind(&done);
1569 __ PopReturnAddressTo(ecx);
1570 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1571 __ PushReturnAddressFrom(ecx);
1572 }
1573
1574 // 3. Make sure ebx is a string.
1575 {
1576 Label convert, done_convert;
1577 __ JumpIfSmi(ebx, &convert, Label::kNear);
1578 __ CmpObjectType(ebx, FIRST_NONSTRING_TYPE, ecx);
1579 __ j(below, &done_convert);
1580 __ bind(&convert);
1581 {
1582 FrameScope scope(masm, StackFrame::INTERNAL);
1583 ToStringStub stub(masm->isolate());
1584 __ Push(edi);
1585 __ Push(edx);
1586 __ Move(eax, ebx);
1587 __ CallStub(&stub);
1588 __ Move(ebx, eax);
1589 __ Pop(edx);
1590 __ Pop(edi);
1591 }
1592 __ bind(&done_convert);
1593 }
1594
1595 // 4. Check if new target and constructor differ.
1596 Label new_object;
1597 __ cmp(edx, edi);
1598 __ j(not_equal, &new_object);
1599
1600 // 5. Allocate a JSValue wrapper for the string.
1601 __ AllocateJSValue(eax, edi, ebx, ecx, &new_object);
1602 __ Ret();
1603
1604 // 6. Fallback to the runtime to create new object.
1605 __ bind(&new_object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001606 {
1607 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001608 __ Push(ebx); // the first argument
1609 __ Push(edi); // constructor function
1610 __ Push(edx); // new target
1611 __ CallRuntime(Runtime::kNewObject);
1612 __ Pop(FieldOperand(eax, JSValue::kValueOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001613 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001614 __ Ret();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001615}
1616
1617
1618static void ArgumentsAdaptorStackCheck(MacroAssembler* masm,
1619 Label* stack_overflow) {
1620 // ----------- S t a t e -------------
1621 // -- eax : actual number of arguments
1622 // -- ebx : expected number of arguments
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001623 // -- edx : new target (passed through to callee)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001624 // -----------------------------------
1625 // Check the stack for overflow. We are not trying to catch
1626 // interruptions (e.g. debug break and preemption) here, so the "real stack
1627 // limit" is checked.
1628 ExternalReference real_stack_limit =
1629 ExternalReference::address_of_real_stack_limit(masm->isolate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001630 __ mov(edi, Operand::StaticVariable(real_stack_limit));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001631 // Make ecx the space we have left. The stack might already be overflowed
1632 // here which will cause ecx to become negative.
1633 __ mov(ecx, esp);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001634 __ sub(ecx, edi);
1635 // Make edi the space we need for the array when it is unrolled onto the
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001636 // stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001637 __ mov(edi, ebx);
1638 __ shl(edi, kPointerSizeLog2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001639 // Check if the arguments will overflow the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001640 __ cmp(ecx, edi);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001641 __ j(less_equal, stack_overflow); // Signed comparison.
1642}
1643
1644
1645static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1646 __ push(ebp);
1647 __ mov(ebp, esp);
1648
1649 // Store the arguments adaptor context sentinel.
1650 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1651
1652 // Push the function on the stack.
1653 __ push(edi);
1654
1655 // Preserve the number of arguments on the stack. Must preserve eax,
1656 // ebx and ecx because these registers are used when copying the
1657 // arguments and the receiver.
1658 STATIC_ASSERT(kSmiTagSize == 1);
1659 __ lea(edi, Operand(eax, eax, times_1, kSmiTag));
1660 __ push(edi);
1661}
1662
1663
1664static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1665 // Retrieve the number of arguments from the stack.
1666 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1667
1668 // Leave the frame.
1669 __ leave();
1670
1671 // Remove caller arguments from the stack.
1672 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
1673 __ pop(ecx);
1674 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
1675 __ push(ecx);
1676}
1677
1678
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001679// static
1680void Builtins::Generate_Apply(MacroAssembler* masm) {
1681 // ----------- S t a t e -------------
1682 // -- eax : argumentsList
1683 // -- edi : target
1684 // -- edx : new.target (checked to be constructor or undefined)
1685 // -- esp[0] : return address.
1686 // -- esp[4] : thisArgument
1687 // -----------------------------------
1688
1689 // Create the list of arguments from the array-like argumentsList.
1690 {
1691 Label create_arguments, create_array, create_runtime, done_create;
1692 __ JumpIfSmi(eax, &create_runtime);
1693
1694 // Load the map of argumentsList into ecx.
1695 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
1696
1697 // Load native context into ebx.
1698 __ mov(ebx, NativeContextOperand());
1699
1700 // Check if argumentsList is an (unmodified) arguments object.
1701 __ cmp(ecx, ContextOperand(ebx, Context::SLOPPY_ARGUMENTS_MAP_INDEX));
1702 __ j(equal, &create_arguments);
1703 __ cmp(ecx, ContextOperand(ebx, Context::STRICT_ARGUMENTS_MAP_INDEX));
1704 __ j(equal, &create_arguments);
1705
1706 // Check if argumentsList is a fast JSArray.
1707 __ CmpInstanceType(ecx, JS_ARRAY_TYPE);
1708 __ j(equal, &create_array);
1709
1710 // Ask the runtime to create the list (actually a FixedArray).
1711 __ bind(&create_runtime);
1712 {
1713 FrameScope scope(masm, StackFrame::INTERNAL);
1714 __ Push(edi);
1715 __ Push(edx);
1716 __ Push(eax);
1717 __ CallRuntime(Runtime::kCreateListFromArrayLike);
1718 __ Pop(edx);
1719 __ Pop(edi);
1720 __ mov(ebx, FieldOperand(eax, FixedArray::kLengthOffset));
1721 __ SmiUntag(ebx);
1722 }
1723 __ jmp(&done_create);
1724
1725 // Try to create the list from an arguments object.
1726 __ bind(&create_arguments);
1727 __ mov(ebx,
1728 FieldOperand(eax, JSObject::kHeaderSize +
1729 Heap::kArgumentsLengthIndex * kPointerSize));
1730 __ mov(ecx, FieldOperand(eax, JSObject::kElementsOffset));
1731 __ cmp(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
1732 __ j(not_equal, &create_runtime);
1733 __ SmiUntag(ebx);
1734 __ mov(eax, ecx);
1735 __ jmp(&done_create);
1736
1737 // Try to create the list from a JSArray object.
1738 __ bind(&create_array);
1739 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
1740 __ DecodeField<Map::ElementsKindBits>(ecx);
1741 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
1742 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
1743 STATIC_ASSERT(FAST_ELEMENTS == 2);
1744 __ cmp(ecx, Immediate(FAST_ELEMENTS));
1745 __ j(above, &create_runtime);
1746 __ cmp(ecx, Immediate(FAST_HOLEY_SMI_ELEMENTS));
1747 __ j(equal, &create_runtime);
1748 __ mov(ebx, FieldOperand(eax, JSArray::kLengthOffset));
1749 __ SmiUntag(ebx);
1750 __ mov(eax, FieldOperand(eax, JSArray::kElementsOffset));
1751
1752 __ bind(&done_create);
1753 }
1754
1755 // Check for stack overflow.
1756 {
1757 // Check the stack for overflow. We are not trying to catch interruptions
1758 // (i.e. debug break and preemption) here, so check the "real stack limit".
1759 Label done;
1760 ExternalReference real_stack_limit =
1761 ExternalReference::address_of_real_stack_limit(masm->isolate());
1762 __ mov(ecx, Operand::StaticVariable(real_stack_limit));
1763 // Make ecx the space we have left. The stack might already be overflowed
1764 // here which will cause ecx to become negative.
1765 __ neg(ecx);
1766 __ add(ecx, esp);
1767 __ sar(ecx, kPointerSizeLog2);
1768 // Check if the arguments will overflow the stack.
1769 __ cmp(ecx, ebx);
1770 __ j(greater, &done, Label::kNear); // Signed comparison.
1771 __ TailCallRuntime(Runtime::kThrowStackOverflow);
1772 __ bind(&done);
1773 }
1774
1775 // ----------- S t a t e -------------
1776 // -- edi : target
1777 // -- eax : args (a FixedArray built from argumentsList)
1778 // -- ebx : len (number of elements to push from args)
1779 // -- edx : new.target (checked to be constructor or undefined)
1780 // -- esp[0] : return address.
1781 // -- esp[4] : thisArgument
1782 // -----------------------------------
1783
1784 // Push arguments onto the stack (thisArgument is already on the stack).
1785 {
1786 __ push(edx);
1787 __ fld_s(MemOperand(esp, 0));
1788 __ lea(esp, Operand(esp, kFloatSize));
1789
1790 __ PopReturnAddressTo(edx);
1791 __ Move(ecx, Immediate(0));
1792 Label done, loop;
1793 __ bind(&loop);
1794 __ cmp(ecx, ebx);
1795 __ j(equal, &done, Label::kNear);
1796 __ Push(
1797 FieldOperand(eax, ecx, times_pointer_size, FixedArray::kHeaderSize));
1798 __ inc(ecx);
1799 __ jmp(&loop);
1800 __ bind(&done);
1801 __ PushReturnAddressFrom(edx);
1802
1803 __ lea(esp, Operand(esp, -kFloatSize));
1804 __ fstp_s(MemOperand(esp, 0));
1805 __ pop(edx);
1806
1807 __ Move(eax, ebx);
1808 }
1809
1810 // Dispatch to Call or Construct depending on whether new.target is undefined.
1811 {
1812 __ CompareRoot(edx, Heap::kUndefinedValueRootIndex);
1813 __ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1814 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
1815 }
1816}
1817
1818
1819// static
1820void Builtins::Generate_CallFunction(MacroAssembler* masm,
1821 ConvertReceiverMode mode) {
1822 // ----------- S t a t e -------------
1823 // -- eax : the number of arguments (not including the receiver)
1824 // -- edi : the function to call (checked to be a JSFunction)
1825 // -----------------------------------
1826 __ AssertFunction(edi);
1827
1828 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
1829 // Check that the function is not a "classConstructor".
1830 Label class_constructor;
1831 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1832 __ test_b(FieldOperand(edx, SharedFunctionInfo::kFunctionKindByteOffset),
1833 SharedFunctionInfo::kClassConstructorBitsWithinByte);
1834 __ j(not_zero, &class_constructor);
1835
1836 // Enter the context of the function; ToObject has to run in the function
1837 // context, and we also need to take the global proxy from the function
1838 // context in case of conversion.
1839 STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset ==
1840 SharedFunctionInfo::kStrictModeByteOffset);
1841 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1842 // We need to convert the receiver for non-native sloppy mode functions.
1843 Label done_convert;
1844 __ test_b(FieldOperand(edx, SharedFunctionInfo::kNativeByteOffset),
1845 (1 << SharedFunctionInfo::kNativeBitWithinByte) |
1846 (1 << SharedFunctionInfo::kStrictModeBitWithinByte));
1847 __ j(not_zero, &done_convert);
1848 {
1849 // ----------- S t a t e -------------
1850 // -- eax : the number of arguments (not including the receiver)
1851 // -- edx : the shared function info.
1852 // -- edi : the function to call (checked to be a JSFunction)
1853 // -- esi : the function context.
1854 // -----------------------------------
1855
1856 if (mode == ConvertReceiverMode::kNullOrUndefined) {
1857 // Patch receiver to global proxy.
1858 __ LoadGlobalProxy(ecx);
1859 } else {
1860 Label convert_to_object, convert_receiver;
1861 __ mov(ecx, Operand(esp, eax, times_pointer_size, kPointerSize));
1862 __ JumpIfSmi(ecx, &convert_to_object, Label::kNear);
1863 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
1864 __ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ebx);
1865 __ j(above_equal, &done_convert);
1866 if (mode != ConvertReceiverMode::kNotNullOrUndefined) {
1867 Label convert_global_proxy;
1868 __ JumpIfRoot(ecx, Heap::kUndefinedValueRootIndex,
1869 &convert_global_proxy, Label::kNear);
1870 __ JumpIfNotRoot(ecx, Heap::kNullValueRootIndex, &convert_to_object,
1871 Label::kNear);
1872 __ bind(&convert_global_proxy);
1873 {
1874 // Patch receiver to global proxy.
1875 __ LoadGlobalProxy(ecx);
1876 }
1877 __ jmp(&convert_receiver);
1878 }
1879 __ bind(&convert_to_object);
1880 {
1881 // Convert receiver using ToObject.
1882 // TODO(bmeurer): Inline the allocation here to avoid building the frame
1883 // in the fast case? (fall back to AllocateInNewSpace?)
1884 FrameScope scope(masm, StackFrame::INTERNAL);
1885 __ SmiTag(eax);
1886 __ Push(eax);
1887 __ Push(edi);
1888 __ mov(eax, ecx);
1889 ToObjectStub stub(masm->isolate());
1890 __ CallStub(&stub);
1891 __ mov(ecx, eax);
1892 __ Pop(edi);
1893 __ Pop(eax);
1894 __ SmiUntag(eax);
1895 }
1896 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1897 __ bind(&convert_receiver);
1898 }
1899 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ecx);
1900 }
1901 __ bind(&done_convert);
1902
1903 // ----------- S t a t e -------------
1904 // -- eax : the number of arguments (not including the receiver)
1905 // -- edx : the shared function info.
1906 // -- edi : the function to call (checked to be a JSFunction)
1907 // -- esi : the function context.
1908 // -----------------------------------
1909
1910 __ mov(ebx,
1911 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
1912 __ SmiUntag(ebx);
1913 ParameterCount actual(eax);
1914 ParameterCount expected(ebx);
1915 __ InvokeFunctionCode(edi, no_reg, expected, actual, JUMP_FUNCTION,
1916 CheckDebugStepCallWrapper());
1917 // The function is a "classConstructor", need to raise an exception.
1918 __ bind(&class_constructor);
1919 {
1920 FrameScope frame(masm, StackFrame::INTERNAL);
1921 __ push(edi);
1922 __ CallRuntime(Runtime::kThrowConstructorNonCallableError);
1923 }
1924}
1925
1926
1927namespace {
1928
1929void Generate_PushBoundArguments(MacroAssembler* masm) {
1930 // ----------- S t a t e -------------
1931 // -- eax : the number of arguments (not including the receiver)
1932 // -- edx : new.target (only in case of [[Construct]])
1933 // -- edi : target (checked to be a JSBoundFunction)
1934 // -----------------------------------
1935
1936 // Load [[BoundArguments]] into ecx and length of that into ebx.
1937 Label no_bound_arguments;
1938 __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset));
1939 __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
1940 __ SmiUntag(ebx);
1941 __ test(ebx, ebx);
1942 __ j(zero, &no_bound_arguments);
1943 {
1944 // ----------- S t a t e -------------
1945 // -- eax : the number of arguments (not including the receiver)
1946 // -- edx : new.target (only in case of [[Construct]])
1947 // -- edi : target (checked to be a JSBoundFunction)
1948 // -- ecx : the [[BoundArguments]] (implemented as FixedArray)
1949 // -- ebx : the number of [[BoundArguments]]
1950 // -----------------------------------
1951
1952 // Reserve stack space for the [[BoundArguments]].
1953 {
1954 Label done;
1955 __ lea(ecx, Operand(ebx, times_pointer_size, 0));
1956 __ sub(esp, ecx);
1957 // Check the stack for overflow. We are not trying to catch interruptions
1958 // (i.e. debug break and preemption) here, so check the "real stack
1959 // limit".
1960 __ CompareRoot(esp, ecx, Heap::kRealStackLimitRootIndex);
1961 __ j(greater, &done, Label::kNear); // Signed comparison.
1962 // Restore the stack pointer.
1963 __ lea(esp, Operand(esp, ebx, times_pointer_size, 0));
1964 {
1965 FrameScope scope(masm, StackFrame::MANUAL);
1966 __ EnterFrame(StackFrame::INTERNAL);
1967 __ CallRuntime(Runtime::kThrowStackOverflow);
1968 }
1969 __ bind(&done);
1970 }
1971
1972 // Adjust effective number of arguments to include return address.
1973 __ inc(eax);
1974
1975 // Relocate arguments and return address down the stack.
1976 {
1977 Label loop;
1978 __ Set(ecx, 0);
1979 __ lea(ebx, Operand(esp, ebx, times_pointer_size, 0));
1980 __ bind(&loop);
1981 __ fld_s(Operand(ebx, ecx, times_pointer_size, 0));
1982 __ fstp_s(Operand(esp, ecx, times_pointer_size, 0));
1983 __ inc(ecx);
1984 __ cmp(ecx, eax);
1985 __ j(less, &loop);
1986 }
1987
1988 // Copy [[BoundArguments]] to the stack (below the arguments).
1989 {
1990 Label loop;
1991 __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset));
1992 __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
1993 __ SmiUntag(ebx);
1994 __ bind(&loop);
1995 __ dec(ebx);
1996 __ fld_s(
1997 FieldOperand(ecx, ebx, times_pointer_size, FixedArray::kHeaderSize));
1998 __ fstp_s(Operand(esp, eax, times_pointer_size, 0));
1999 __ lea(eax, Operand(eax, 1));
2000 __ j(greater, &loop);
2001 }
2002
2003 // Adjust effective number of arguments (eax contains the number of
2004 // arguments from the call plus return address plus the number of
2005 // [[BoundArguments]]), so we need to subtract one for the return address.
2006 __ dec(eax);
2007 }
2008 __ bind(&no_bound_arguments);
2009}
2010
2011} // namespace
2012
2013
2014// static
2015void Builtins::Generate_CallBoundFunction(MacroAssembler* masm) {
2016 // ----------- S t a t e -------------
2017 // -- eax : the number of arguments (not including the receiver)
2018 // -- edi : the function to call (checked to be a JSBoundFunction)
2019 // -----------------------------------
2020 __ AssertBoundFunction(edi);
2021
2022 // Patch the receiver to [[BoundThis]].
2023 __ mov(ebx, FieldOperand(edi, JSBoundFunction::kBoundThisOffset));
2024 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ebx);
2025
2026 // Push the [[BoundArguments]] onto the stack.
2027 Generate_PushBoundArguments(masm);
2028
2029 // Call the [[BoundTargetFunction]] via the Call builtin.
2030 __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2031 __ mov(ecx, Operand::StaticVariable(ExternalReference(
2032 Builtins::kCall_ReceiverIsAny, masm->isolate())));
2033 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2034 __ jmp(ecx);
2035}
2036
2037
2038// static
2039void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
2040 // ----------- S t a t e -------------
2041 // -- eax : the number of arguments (not including the receiver)
2042 // -- edi : the target to call (can be any Object).
2043 // -----------------------------------
2044
2045 Label non_callable, non_function, non_smi;
2046 __ JumpIfSmi(edi, &non_callable);
2047 __ bind(&non_smi);
2048 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
2049 __ j(equal, masm->isolate()->builtins()->CallFunction(mode),
2050 RelocInfo::CODE_TARGET);
2051 __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
2052 __ j(equal, masm->isolate()->builtins()->CallBoundFunction(),
2053 RelocInfo::CODE_TARGET);
2054 __ CmpInstanceType(ecx, JS_PROXY_TYPE);
2055 __ j(not_equal, &non_function);
2056
2057 // 1. Runtime fallback for Proxy [[Call]].
2058 __ PopReturnAddressTo(ecx);
2059 __ Push(edi);
2060 __ PushReturnAddressFrom(ecx);
2061 // Increase the arguments size to include the pushed function and the
2062 // existing receiver on the stack.
2063 __ add(eax, Immediate(2));
2064 // Tail-call to the runtime.
2065 __ JumpToExternalReference(
2066 ExternalReference(Runtime::kJSProxyCall, masm->isolate()));
2067
2068 // 2. Call to something else, which might have a [[Call]] internal method (if
2069 // not we raise an exception).
2070 __ bind(&non_function);
2071 // Check if target has a [[Call]] internal method.
2072 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable);
2073 __ j(zero, &non_callable, Label::kNear);
2074 // Overwrite the original receiver with the (original) target.
2075 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
2076 // Let the "call_as_function_delegate" take care of the rest.
2077 __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, edi);
2078 __ Jump(masm->isolate()->builtins()->CallFunction(
2079 ConvertReceiverMode::kNotNullOrUndefined),
2080 RelocInfo::CODE_TARGET);
2081
2082 // 3. Call to something that is not callable.
2083 __ bind(&non_callable);
2084 {
2085 FrameScope scope(masm, StackFrame::INTERNAL);
2086 __ Push(edi);
2087 __ CallRuntime(Runtime::kThrowCalledNonCallable);
2088 }
2089}
2090
2091
2092// static
2093void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
2094 // ----------- S t a t e -------------
2095 // -- eax : the number of arguments (not including the receiver)
2096 // -- edx : the new target (checked to be a constructor)
2097 // -- edi : the constructor to call (checked to be a JSFunction)
2098 // -----------------------------------
2099 __ AssertFunction(edi);
2100
2101 // Calling convention for function specific ConstructStubs require
2102 // ebx to contain either an AllocationSite or undefined.
2103 __ LoadRoot(ebx, Heap::kUndefinedValueRootIndex);
2104
2105 // Tail call to the function-specific construct stub (still in the caller
2106 // context at this point).
2107 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2108 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset));
2109 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2110 __ jmp(ecx);
2111}
2112
2113
2114// static
2115void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
2116 // ----------- S t a t e -------------
2117 // -- eax : the number of arguments (not including the receiver)
2118 // -- edx : the new target (checked to be a constructor)
2119 // -- edi : the constructor to call (checked to be a JSBoundFunction)
2120 // -----------------------------------
2121 __ AssertBoundFunction(edi);
2122
2123 // Push the [[BoundArguments]] onto the stack.
2124 Generate_PushBoundArguments(masm);
2125
2126 // Patch new.target to [[BoundTargetFunction]] if new.target equals target.
2127 {
2128 Label done;
2129 __ cmp(edi, edx);
2130 __ j(not_equal, &done, Label::kNear);
2131 __ mov(edx, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2132 __ bind(&done);
2133 }
2134
2135 // Construct the [[BoundTargetFunction]] via the Construct builtin.
2136 __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2137 __ mov(ecx, Operand::StaticVariable(
2138 ExternalReference(Builtins::kConstruct, masm->isolate())));
2139 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2140 __ jmp(ecx);
2141}
2142
2143
2144// static
2145void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
2146 // ----------- S t a t e -------------
2147 // -- eax : the number of arguments (not including the receiver)
2148 // -- edi : the constructor to call (checked to be a JSProxy)
2149 // -- edx : the new target (either the same as the constructor or
2150 // the JSFunction on which new was invoked initially)
2151 // -----------------------------------
2152
2153 // Call into the Runtime for Proxy [[Construct]].
2154 __ PopReturnAddressTo(ecx);
2155 __ Push(edi);
2156 __ Push(edx);
2157 __ PushReturnAddressFrom(ecx);
2158 // Include the pushed new_target, constructor and the receiver.
2159 __ add(eax, Immediate(3));
2160 // Tail-call to the runtime.
2161 __ JumpToExternalReference(
2162 ExternalReference(Runtime::kJSProxyConstruct, masm->isolate()));
2163}
2164
2165
2166// static
2167void Builtins::Generate_Construct(MacroAssembler* masm) {
2168 // ----------- S t a t e -------------
2169 // -- eax : the number of arguments (not including the receiver)
2170 // -- edx : the new target (either the same as the constructor or
2171 // the JSFunction on which new was invoked initially)
2172 // -- edi : the constructor to call (can be any Object)
2173 // -----------------------------------
2174
2175 // Check if target is a Smi.
2176 Label non_constructor;
2177 __ JumpIfSmi(edi, &non_constructor, Label::kNear);
2178
2179 // Dispatch based on instance type.
2180 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
2181 __ j(equal, masm->isolate()->builtins()->ConstructFunction(),
2182 RelocInfo::CODE_TARGET);
2183
2184 // Check if target has a [[Construct]] internal method.
2185 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor);
2186 __ j(zero, &non_constructor, Label::kNear);
2187
2188 // Only dispatch to bound functions after checking whether they are
2189 // constructors.
2190 __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
2191 __ j(equal, masm->isolate()->builtins()->ConstructBoundFunction(),
2192 RelocInfo::CODE_TARGET);
2193
2194 // Only dispatch to proxies after checking whether they are constructors.
2195 __ CmpInstanceType(ecx, JS_PROXY_TYPE);
2196 __ j(equal, masm->isolate()->builtins()->ConstructProxy(),
2197 RelocInfo::CODE_TARGET);
2198
2199 // Called Construct on an exotic Object with a [[Construct]] internal method.
2200 {
2201 // Overwrite the original receiver with the (original) target.
2202 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
2203 // Let the "call_as_constructor_delegate" take care of the rest.
2204 __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, edi);
2205 __ Jump(masm->isolate()->builtins()->CallFunction(),
2206 RelocInfo::CODE_TARGET);
2207 }
2208
2209 // Called Construct on an Object that doesn't have a [[Construct]] internal
2210 // method.
2211 __ bind(&non_constructor);
2212 __ Jump(masm->isolate()->builtins()->ConstructedNonConstructable(),
2213 RelocInfo::CODE_TARGET);
2214}
2215
2216
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002217void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
2218 // ----------- S t a t e -------------
2219 // -- eax : actual number of arguments
2220 // -- ebx : expected number of arguments
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002221 // -- edx : new target (passed through to callee)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002222 // -- edi : function (passed through to callee)
2223 // -----------------------------------
2224
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002225 Label invoke, dont_adapt_arguments, stack_overflow;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002226 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
2227
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002228 Label enough, too_few;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002229 __ cmp(eax, ebx);
2230 __ j(less, &too_few);
2231 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
2232 __ j(equal, &dont_adapt_arguments);
2233
2234 { // Enough parameters: Actual >= expected.
2235 __ bind(&enough);
2236 EnterArgumentsAdaptorFrame(masm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002237 ArgumentsAdaptorStackCheck(masm, &stack_overflow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002238
2239 // Copy receiver and all expected arguments.
2240 const int offset = StandardFrameConstants::kCallerSPOffset;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002241 __ lea(edi, Operand(ebp, eax, times_4, offset));
2242 __ mov(eax, -1); // account for receiver
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002243
2244 Label copy;
2245 __ bind(&copy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002246 __ inc(eax);
2247 __ push(Operand(edi, 0));
2248 __ sub(edi, Immediate(kPointerSize));
2249 __ cmp(eax, ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002250 __ j(less, &copy);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002251 // eax now contains the expected number of arguments.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002252 __ jmp(&invoke);
2253 }
2254
2255 { // Too few parameters: Actual < expected.
2256 __ bind(&too_few);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002257
2258 // If the function is strong we need to throw an error.
2259 Label no_strong_error;
2260 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2261 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrongModeByteOffset),
2262 1 << SharedFunctionInfo::kStrongModeBitWithinByte);
2263 __ j(equal, &no_strong_error, Label::kNear);
2264
2265 // What we really care about is the required number of arguments.
2266 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kLengthOffset));
2267 __ SmiUntag(ecx);
2268 __ cmp(eax, ecx);
2269 __ j(greater_equal, &no_strong_error, Label::kNear);
2270
2271 {
2272 FrameScope frame(masm, StackFrame::MANUAL);
2273 EnterArgumentsAdaptorFrame(masm);
2274 __ CallRuntime(Runtime::kThrowStrongModeTooFewArguments);
2275 }
2276
2277 __ bind(&no_strong_error);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002278 EnterArgumentsAdaptorFrame(masm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002279 ArgumentsAdaptorStackCheck(masm, &stack_overflow);
2280
2281 // Remember expected arguments in ecx.
2282 __ mov(ecx, ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002283
2284 // Copy receiver and all actual arguments.
2285 const int offset = StandardFrameConstants::kCallerSPOffset;
2286 __ lea(edi, Operand(ebp, eax, times_4, offset));
2287 // ebx = expected - actual.
2288 __ sub(ebx, eax);
2289 // eax = -actual - 1
2290 __ neg(eax);
2291 __ sub(eax, Immediate(1));
2292
2293 Label copy;
2294 __ bind(&copy);
2295 __ inc(eax);
2296 __ push(Operand(edi, 0));
2297 __ sub(edi, Immediate(kPointerSize));
2298 __ test(eax, eax);
2299 __ j(not_zero, &copy);
2300
2301 // Fill remaining expected arguments with undefined values.
2302 Label fill;
2303 __ bind(&fill);
2304 __ inc(eax);
2305 __ push(Immediate(masm->isolate()->factory()->undefined_value()));
2306 __ cmp(eax, ebx);
2307 __ j(less, &fill);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002308
2309 // Restore expected arguments.
2310 __ mov(eax, ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002311 }
2312
2313 // Call the entry point.
2314 __ bind(&invoke);
2315 // Restore function pointer.
2316 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002317 // eax : expected number of arguments
2318 // edx : new target (passed through to callee)
2319 // edi : function (passed through to callee)
2320 __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2321 __ call(ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002322
2323 // Store offset of return address for deoptimizer.
2324 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
2325
2326 // Leave frame and return.
2327 LeaveArgumentsAdaptorFrame(masm);
2328 __ ret(0);
2329
2330 // -------------------------------------------
2331 // Dont adapt arguments.
2332 // -------------------------------------------
2333 __ bind(&dont_adapt_arguments);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002334 __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2335 __ jmp(ecx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002336
2337 __ bind(&stack_overflow);
2338 {
2339 FrameScope frame(masm, StackFrame::MANUAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002340 __ CallRuntime(Runtime::kThrowStackOverflow);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002341 __ int3();
2342 }
2343}
2344
2345
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002346static void CompatibleReceiverCheck(MacroAssembler* masm, Register receiver,
2347 Register function_template_info,
2348 Register scratch0, Register scratch1,
2349 Label* receiver_check_failed) {
2350 // If there is no signature, return the holder.
2351 __ CompareRoot(FieldOperand(function_template_info,
2352 FunctionTemplateInfo::kSignatureOffset),
2353 Heap::kUndefinedValueRootIndex);
2354 Label receiver_check_passed;
2355 __ j(equal, &receiver_check_passed, Label::kNear);
2356
2357 // Walk the prototype chain.
2358 __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
2359 Label prototype_loop_start;
2360 __ bind(&prototype_loop_start);
2361
2362 // Get the constructor, if any.
2363 __ GetMapConstructor(scratch0, scratch0, scratch1);
2364 __ CmpInstanceType(scratch1, JS_FUNCTION_TYPE);
2365 Label next_prototype;
2366 __ j(not_equal, &next_prototype, Label::kNear);
2367
2368 // Get the constructor's signature.
2369 __ mov(scratch0,
2370 FieldOperand(scratch0, JSFunction::kSharedFunctionInfoOffset));
2371 __ mov(scratch0,
2372 FieldOperand(scratch0, SharedFunctionInfo::kFunctionDataOffset));
2373
2374 // Loop through the chain of inheriting function templates.
2375 Label function_template_loop;
2376 __ bind(&function_template_loop);
2377
2378 // If the signatures match, we have a compatible receiver.
2379 __ cmp(scratch0, FieldOperand(function_template_info,
2380 FunctionTemplateInfo::kSignatureOffset));
2381 __ j(equal, &receiver_check_passed, Label::kNear);
2382
2383 // If the current type is not a FunctionTemplateInfo, load the next prototype
2384 // in the chain.
2385 __ JumpIfSmi(scratch0, &next_prototype, Label::kNear);
2386 __ CmpObjectType(scratch0, FUNCTION_TEMPLATE_INFO_TYPE, scratch1);
2387 __ j(not_equal, &next_prototype, Label::kNear);
2388
2389 // Otherwise load the parent function template and iterate.
2390 __ mov(scratch0,
2391 FieldOperand(scratch0, FunctionTemplateInfo::kParentTemplateOffset));
2392 __ jmp(&function_template_loop, Label::kNear);
2393
2394 // Load the next prototype.
2395 __ bind(&next_prototype);
2396 __ mov(receiver, FieldOperand(receiver, HeapObject::kMapOffset));
2397 __ mov(receiver, FieldOperand(receiver, Map::kPrototypeOffset));
2398 // End if the prototype is null or not hidden.
2399 __ CompareRoot(receiver, Heap::kNullValueRootIndex);
2400 __ j(equal, receiver_check_failed);
2401 __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
2402 __ test(FieldOperand(scratch0, Map::kBitField3Offset),
2403 Immediate(Map::IsHiddenPrototype::kMask));
2404 __ j(zero, receiver_check_failed);
2405 // Iterate.
2406 __ jmp(&prototype_loop_start, Label::kNear);
2407
2408 __ bind(&receiver_check_passed);
2409}
2410
2411
2412void Builtins::Generate_HandleFastApiCall(MacroAssembler* masm) {
2413 // ----------- S t a t e -------------
2414 // -- eax : number of arguments (not including the receiver)
2415 // -- edi : callee
2416 // -- esi : context
2417 // -- esp[0] : return address
2418 // -- esp[4] : last argument
2419 // -- ...
2420 // -- esp[eax * 4] : first argument
2421 // -- esp[(eax + 1) * 4] : receiver
2422 // -----------------------------------
2423
2424 // Load the FunctionTemplateInfo.
2425 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2426 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kFunctionDataOffset));
2427
2428 // Do the compatible receiver check.
2429 Label receiver_check_failed;
2430 __ mov(ecx, Operand(esp, eax, times_pointer_size, kPCOnStackSize));
2431 __ Push(eax);
2432 CompatibleReceiverCheck(masm, ecx, ebx, edx, eax, &receiver_check_failed);
2433 __ Pop(eax);
2434 // Get the callback offset from the FunctionTemplateInfo, and jump to the
2435 // beginning of the code.
2436 __ mov(edx, FieldOperand(ebx, FunctionTemplateInfo::kCallCodeOffset));
2437 __ mov(edx, FieldOperand(edx, CallHandlerInfo::kFastHandlerOffset));
2438 __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
2439 __ jmp(edx);
2440
2441 // Compatible receiver check failed: pop return address, arguments and
2442 // receiver and throw an Illegal Invocation exception.
2443 __ bind(&receiver_check_failed);
2444 __ Pop(eax);
2445 __ PopReturnAddressTo(ebx);
2446 __ lea(eax, Operand(eax, times_pointer_size, 1 * kPointerSize));
2447 __ add(esp, eax);
2448 __ PushReturnAddressFrom(ebx);
2449 {
2450 FrameScope scope(masm, StackFrame::INTERNAL);
2451 __ TailCallRuntime(Runtime::kThrowIllegalInvocation);
2452 }
2453}
2454
2455
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002456void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
2457 // Lookup the function in the JavaScript frame.
2458 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
2459 {
2460 FrameScope scope(masm, StackFrame::INTERNAL);
2461 // Pass function as argument.
2462 __ push(eax);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002463 __ CallRuntime(Runtime::kCompileForOnStackReplacement);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002464 }
2465
2466 Label skip;
2467 // If the code object is null, just return to the unoptimized code.
2468 __ cmp(eax, Immediate(0));
2469 __ j(not_equal, &skip, Label::kNear);
2470 __ ret(0);
2471
2472 __ bind(&skip);
2473
2474 // Load deoptimization data from the code object.
2475 __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag));
2476
2477 // Load the OSR entrypoint offset from the deoptimization data.
2478 __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt(
2479 DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag));
2480 __ SmiUntag(ebx);
2481
2482 // Compute the target address = code_obj + header_size + osr_offset
2483 __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag));
2484
2485 // Overwrite the return address on the stack.
2486 __ mov(Operand(esp, 0), eax);
2487
2488 // And "return" to the OSR entry point of the function.
2489 __ ret(0);
2490}
2491
2492
2493void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
2494 // We check the stack limit as indicator that recompilation might be done.
2495 Label ok;
2496 ExternalReference stack_limit =
2497 ExternalReference::address_of_stack_limit(masm->isolate());
2498 __ cmp(esp, Operand::StaticVariable(stack_limit));
2499 __ j(above_equal, &ok, Label::kNear);
2500 {
2501 FrameScope scope(masm, StackFrame::INTERNAL);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002502 __ CallRuntime(Runtime::kStackGuard);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002503 }
2504 __ jmp(masm->isolate()->builtins()->OnStackReplacement(),
2505 RelocInfo::CODE_TARGET);
2506
2507 __ bind(&ok);
2508 __ ret(0);
2509}
2510
2511#undef __
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002512} // namespace internal
2513} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002514
2515#endif // V8_TARGET_ARCH_X87