1 // 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
5 #if V8_TARGET_ARCH_IA32
6
7 #include "src/code-factory.h"
8 #include "src/codegen.h"
9 #include "src/deoptimizer.h"
10 #include "src/full-codegen/full-codegen.h"
11 #include "src/ia32/frames-ia32.h"
12
13 namespace v8 {
14 namespace internal {
15
16
17 #define __ ACCESS_MASM(masm)
18
19
Generate_Adaptor(MacroAssembler * masm,CFunctionId id,BuiltinExtraArguments extra_args)20 void 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
25 // -- edi : target
26 // -- edx : new.target
27 // -- esp[0] : return address
28 // -- esp[4] : last argument
29 // -- ...
30 // -- esp[4 * argc] : first argument
31 // -- esp[4 * (argc +1)] : receiver
32 // -----------------------------------
33 __ 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));
40
41 // Insert extra arguments.
42 int num_extra_args = 0;
43 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);
54 }
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));
59
60 __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
61 }
62
63
CallRuntimePassFunction(MacroAssembler * masm,Runtime::FunctionId function_id)64 static void CallRuntimePassFunction(
65 MacroAssembler* masm, Runtime::FunctionId function_id) {
66 // ----------- S t a t e -------------
67 // -- edx : new target (preserved for callee)
68 // -- edi : target function (preserved for callee)
69 // -----------------------------------
70
71 FrameScope scope(masm, StackFrame::INTERNAL);
72 // Push a copy of the target function and the new target.
73 __ push(edi);
74 __ push(edx);
75 // Function is also the parameter to the runtime call.
76 __ push(edi);
77
78 __ CallRuntime(function_id, 1);
79 // Restore target function and new target.
80 __ pop(edx);
81 __ pop(edi);
82 }
83
84
GenerateTailCallToSharedCode(MacroAssembler * masm)85 static 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
GenerateTailCallToReturnedCode(MacroAssembler * masm)93 static void GenerateTailCallToReturnedCode(MacroAssembler* masm) {
94 __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
95 __ jmp(eax);
96 }
97
98
Generate_InOptimizationQueue(MacroAssembler * masm)99 void 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
Generate_JSConstructStubHelper(MacroAssembler * masm,bool is_api_function,bool create_implicit_receiver)119 static void Generate_JSConstructStubHelper(MacroAssembler* masm,
120 bool is_api_function,
121 bool create_implicit_receiver) {
122 // ----------- S t a t e -------------
123 // -- eax: number of arguments
124 // -- edi: constructor function
125 // -- ebx: allocation site or undefined
126 // -- edx: new target
127 // -----------------------------------
128
129 // Enter a construct frame.
130 {
131 FrameScope scope(masm, StackFrame::CONSTRUCT);
132
133 // Preserve the incoming parameters on the stack.
134 __ AssertUndefinedOrAllocationSite(ebx);
135 __ push(ebx);
136 __ SmiTag(eax);
137 __ push(eax);
138
139 if (create_implicit_receiver) {
140 __ push(edi);
141 __ 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));
285 }
286
287 __ SmiUntag(eax);
288
289 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 }
298
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);
320 __ InvokeFunction(edi, edx, actual, CALL_FUNCTION,
321 CheckDebugStepCallWrapper());
322 }
323
324 // Store offset of return address for deoptimizer.
325 if (create_implicit_receiver && !is_api_function) {
326 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
327 }
328
329 // Restore context from the frame.
330 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
331
332 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;
337
338 // If the result is a smi, it is *not* an object in the ECMA sense.
339 __ JumpIfSmi(eax, &use_receiver);
340
341 // 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);
345
346 // 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));
350
351 // 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 }
358
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);
367 if (create_implicit_receiver) {
368 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
369 }
370 __ ret(0);
371 }
372
373
Generate_JSConstructStubGeneric(MacroAssembler * masm)374 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
375 Generate_JSConstructStubHelper(masm, false, true);
376 }
377
378
Generate_JSConstructStubApi(MacroAssembler * masm)379 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
380 Generate_JSConstructStubHelper(masm, true, true);
381 }
382
383
Generate_JSBuiltinsConstructStub(MacroAssembler * masm)384 void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {
385 Generate_JSConstructStubHelper(masm, false, false);
386 }
387
388
Generate_ConstructedNonConstructable(MacroAssembler * masm)389 void Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) {
390 FrameScope scope(masm, StackFrame::INTERNAL);
391 __ push(edi);
392 __ CallRuntime(Runtime::kThrowConstructedNonConstructable);
393 }
394
395
396 enum IsTagged { kEaxIsSmiTagged, kEaxIsUntaggedInt };
397
398
399 // Clobbers ecx, edx, edi; preserves all other registers.
Generate_CheckStackOverflow(MacroAssembler * masm,IsTagged eax_is_tagged)400 static 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);
428 }
429
430
Generate_JSEntryTrampolineHelper(MacroAssembler * masm,bool is_construct)431 static 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
441 // 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
446 // Load the previous frame pointer (ebx) to access C arguments
447 __ mov(ebx, Operand(ebp, 0));
448
449 // Push the function and the receiver onto the stack.
450 __ push(Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
451 __ 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
457 // 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
461 // Copy arguments to the stack in a loop.
462 Label loop, entry;
463 __ Move(ecx, Immediate(0));
464 __ jmp(&entry, Label::kNear);
465 __ 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
473 // 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));
479
480 // Invoke the code.
481 Handle<Code> builtin = is_construct
482 ? masm->isolate()->builtins()->Construct()
483 : masm->isolate()->builtins()->Call();
484 __ Call(builtin, RelocInfo::CODE_TARGET);
485
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
Generate_JSEntryTrampoline(MacroAssembler * masm)494 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
495 Generate_JSEntryTrampolineHelper(masm, false);
496 }
497
498
Generate_JSConstructEntryTrampoline(MacroAssembler * masm)499 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
500 Generate_JSEntryTrampolineHelper(masm, true);
501 }
502
503
504 // 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.
Generate_InterpreterEntryTrampoline(MacroAssembler * masm)520 void 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
Generate_InterpreterExitTrampoline(MacroAssembler * masm)633 void 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
Generate_InterpreterPushArgs(MacroAssembler * masm,Register array_limit)655 static 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
Generate_InterpreterPushArgsAndCall(MacroAssembler * masm)674 void 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
Generate_InterpreterPushArgsAndConstruct(MacroAssembler * masm)702 void 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
Generate_InterpreterNotifyDeoptimizedHelper(MacroAssembler * masm,Deoptimizer::BailoutType type)742 static 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
Generate_InterpreterNotifyDeoptimized(MacroAssembler * masm)811 void Builtins::Generate_InterpreterNotifyDeoptimized(MacroAssembler* masm) {
812 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
813 }
814
815
Generate_InterpreterNotifySoftDeoptimized(MacroAssembler * masm)816 void Builtins::Generate_InterpreterNotifySoftDeoptimized(MacroAssembler* masm) {
817 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
818 }
819
820
Generate_InterpreterNotifyLazyDeoptimized(MacroAssembler * masm)821 void Builtins::Generate_InterpreterNotifyLazyDeoptimized(MacroAssembler* masm) {
822 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
823 }
824
825
Generate_CompileLazy(MacroAssembler * masm)826 void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
827 CallRuntimePassFunction(masm, Runtime::kCompileLazy);
828 GenerateTailCallToReturnedCode(masm);
829 }
830
831
Generate_CompileOptimized(MacroAssembler * masm)832 void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
833 CallRuntimePassFunction(masm, Runtime::kCompileOptimized_NotConcurrent);
834 GenerateTailCallToReturnedCode(masm);
835 }
836
837
Generate_CompileOptimizedConcurrent(MacroAssembler * masm)838 void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
839 CallRuntimePassFunction(masm, Runtime::kCompileOptimized_Concurrent);
840 GenerateTailCallToReturnedCode(masm);
841 }
842
843
GenerateMakeCodeYoungAgainCommon(MacroAssembler * masm)844 static 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) \
870 void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
871 MacroAssembler* masm) { \
872 GenerateMakeCodeYoungAgainCommon(masm); \
873 } \
874 void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
875 MacroAssembler* masm) { \
876 GenerateMakeCodeYoungAgainCommon(masm); \
877 }
CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)878 CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
879 #undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
880
881
882 void 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
Generate_MarkCodeAsExecutedTwice(MacroAssembler * masm)915 void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
916 GenerateMakeCodeYoungAgainCommon(masm);
917 }
918
919
Generate_MarkCodeAsToBeExecutedOnce(MacroAssembler * masm)920 void Builtins::Generate_MarkCodeAsToBeExecutedOnce(MacroAssembler* masm) {
921 Generate_MarkCodeAsExecutedOnce(masm);
922 }
923
924
Generate_NotifyStubFailureHelper(MacroAssembler * masm,SaveFPRegsMode save_doubles)925 static 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();
935 __ CallRuntime(Runtime::kNotifyStubFailure, save_doubles);
936 __ 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
Generate_NotifyStubFailure(MacroAssembler * masm)945 void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
946 Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
947 }
948
949
Generate_NotifyStubFailureSaveDoubles(MacroAssembler * masm)950 void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
951 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
952 }
953
954
Generate_NotifyDeoptimizedHelper(MacroAssembler * masm,Deoptimizer::BailoutType type)955 static 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))));
962 __ CallRuntime(Runtime::kNotifyDeoptimized);
963
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, ¬_no_registers, Label::kNear);
975 __ ret(1 * kPointerSize); // Remove state.
976
977 __ bind(¬_no_registers);
978 __ mov(eax, Operand(esp, 2 * kPointerSize));
979 __ cmp(ecx, FullCodeGenerator::TOS_REG);
980 __ j(not_equal, ¬_tos_eax, Label::kNear);
981 __ ret(2 * kPointerSize); // Remove state, eax.
982
983 __ bind(¬_tos_eax);
984 __ Abort(kNoCasesLeft);
985 }
986
987
Generate_NotifyDeoptimized(MacroAssembler * masm)988 void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
989 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
990 }
991
992
Generate_NotifySoftDeoptimized(MacroAssembler * masm)993 void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
994 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
995 }
996
997
Generate_NotifyLazyDeoptimized(MacroAssembler * masm)998 void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
999 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
1000 }
1001
1002
1003 // static
Generate_DatePrototype_GetField(MacroAssembler * masm,int field_index)1004 void 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 // -----------------------------------
1010
1011 // 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
Generate_FunctionPrototypeApply(MacroAssembler * masm)1056 void 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));
1073 __ test(eax, eax);
1074 __ 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
Generate_FunctionPrototypeCall(MacroAssembler * masm)1133 void 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);
1152 __ inc(eax);
1153 __ bind(&done);
1154 }
1155
1156 // 2. Get the callable to call (passed as receiver) from the stack.
1157 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
1158
1159 // 3. Shift arguments and return address one slot down on the stack
1160 // (overwriting the original receiver). Adjust argument count to make
1161 // the original first argument the new receiver.
1162 {
1163 Label loop;
1164 __ mov(ecx, eax);
1165 __ bind(&loop);
1166 __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0));
1167 __ mov(Operand(esp, ecx, times_pointer_size, kPointerSize), ebx);
1168 __ dec(ecx);
1169 __ j(not_sign, &loop); // While non-negative (to copy return address).
1170 __ pop(ebx); // Discard copy of return address.
1171 __ dec(eax); // One fewer argument (first argument is new receiver).
1172 }
1173
1174 // 4. Call the callable.
1175 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1176 }
1177
1178
Generate_ReflectApply(MacroAssembler * masm)1179 void 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.
1192 {
1193 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);
1211 }
1212
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
Generate_ReflectConstruct(MacroAssembler * masm)1241 void 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 }
1315 }
1316
1317
Generate_InternalArrayCode(MacroAssembler * masm)1318 void 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
Generate_ArrayCode(MacroAssembler * masm)1347 void 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);
1357 __ mov(edx, edi);
1358
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
1377 // static
Generate_NumberConstructor(MacroAssembler * masm)1378 void Builtins::Generate_NumberConstructor(MacroAssembler* masm) {
1379 // ----------- 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 // -----------------------------------
1386
1387 // 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);
1398 }
1399
1400 // 2a. Convert the first argument to a number.
1401 ToNumberStub stub(masm->isolate());
1402 __ TailCallStub(&stub);
1403
1404 // 2b. No arguments, return +0 (already in eax).
1405 __ bind(&no_arguments);
1406 __ ret(1 * kPointerSize);
1407 }
1408
1409
1410 // static
Generate_NumberConstructor_ConstructStub(MacroAssembler * masm)1411 void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) {
1412 // ----------- S t a t e -------------
1413 // -- 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
1419 // -----------------------------------
1420
1421 // 1. Make sure we operate in the context of the called function.
1422 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1423
1424 // 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);
1438 }
1439
1440 // 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 }
1460
1461 // 4. Check if new target and constructor differ.
1462 Label new_object;
1463 __ cmp(edx, edi);
1464 __ j(not_equal, &new_object);
1465
1466 // 5. Allocate a JSValue wrapper for the number.
1467 __ AllocateJSValue(eax, edi, ebx, ecx, &new_object);
1468 __ Ret();
1469
1470 // 6. Fallback to the runtime to create new object.
1471 __ bind(&new_object);
1472 {
1473 FrameScope scope(masm, StackFrame::INTERNAL);
1474 __ 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));
1479 }
1480 __ Ret();
1481 }
1482
1483
1484 // static
Generate_StringConstructor(MacroAssembler * masm)1485 void 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).
1520 __ bind(&no_arguments);
1521 {
1522 __ LoadRoot(eax, Heap::kempty_stringRootIndex);
1523 __ ret(1 * kPointerSize);
1524 }
1525
1526 // 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
Generate_StringConstructor_ConstructStub(MacroAssembler * masm)1545 void 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);
1606 {
1607 FrameScope scope(masm, StackFrame::INTERNAL);
1608 __ 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));
1613 }
1614 __ Ret();
1615 }
1616
1617
ArgumentsAdaptorStackCheck(MacroAssembler * masm,Label * stack_overflow)1618 static 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
1623 // -- edx : new target (passed through to callee)
1624 // -----------------------------------
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());
1630 __ mov(edi, Operand::StaticVariable(real_stack_limit));
1631 // 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);
1634 __ sub(ecx, edi);
1635 // Make edi the space we need for the array when it is unrolled onto the
1636 // stack.
1637 __ mov(edi, ebx);
1638 __ shl(edi, kPointerSizeLog2);
1639 // Check if the arguments will overflow the stack.
1640 __ cmp(ecx, edi);
1641 __ j(less_equal, stack_overflow); // Signed comparison.
1642 }
1643
1644
EnterArgumentsAdaptorFrame(MacroAssembler * masm)1645 static 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
LeaveArgumentsAdaptorFrame(MacroAssembler * masm)1664 static 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
1679 // static
Generate_Apply(MacroAssembler * masm)1680 void 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 __ movd(xmm0, edx);
1787 __ PopReturnAddressTo(edx);
1788 __ Move(ecx, Immediate(0));
1789 Label done, loop;
1790 __ bind(&loop);
1791 __ cmp(ecx, ebx);
1792 __ j(equal, &done, Label::kNear);
1793 __ Push(
1794 FieldOperand(eax, ecx, times_pointer_size, FixedArray::kHeaderSize));
1795 __ inc(ecx);
1796 __ jmp(&loop);
1797 __ bind(&done);
1798 __ PushReturnAddressFrom(edx);
1799 __ movd(edx, xmm0);
1800 __ Move(eax, ebx);
1801 }
1802
1803 // Dispatch to Call or Construct depending on whether new.target is undefined.
1804 {
1805 __ CompareRoot(edx, Heap::kUndefinedValueRootIndex);
1806 __ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
1807 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
1808 }
1809 }
1810
1811
1812 // static
Generate_CallFunction(MacroAssembler * masm,ConvertReceiverMode mode)1813 void Builtins::Generate_CallFunction(MacroAssembler* masm,
1814 ConvertReceiverMode mode) {
1815 // ----------- S t a t e -------------
1816 // -- eax : the number of arguments (not including the receiver)
1817 // -- edi : the function to call (checked to be a JSFunction)
1818 // -----------------------------------
1819 __ AssertFunction(edi);
1820
1821 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList)
1822 // Check that the function is not a "classConstructor".
1823 Label class_constructor;
1824 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1825 __ test_b(FieldOperand(edx, SharedFunctionInfo::kFunctionKindByteOffset),
1826 SharedFunctionInfo::kClassConstructorBitsWithinByte);
1827 __ j(not_zero, &class_constructor);
1828
1829 // Enter the context of the function; ToObject has to run in the function
1830 // context, and we also need to take the global proxy from the function
1831 // context in case of conversion.
1832 STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset ==
1833 SharedFunctionInfo::kStrictModeByteOffset);
1834 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1835 // We need to convert the receiver for non-native sloppy mode functions.
1836 Label done_convert;
1837 __ test_b(FieldOperand(edx, SharedFunctionInfo::kNativeByteOffset),
1838 (1 << SharedFunctionInfo::kNativeBitWithinByte) |
1839 (1 << SharedFunctionInfo::kStrictModeBitWithinByte));
1840 __ j(not_zero, &done_convert);
1841 {
1842 // ----------- S t a t e -------------
1843 // -- eax : the number of arguments (not including the receiver)
1844 // -- edx : the shared function info.
1845 // -- edi : the function to call (checked to be a JSFunction)
1846 // -- esi : the function context.
1847 // -----------------------------------
1848
1849 if (mode == ConvertReceiverMode::kNullOrUndefined) {
1850 // Patch receiver to global proxy.
1851 __ LoadGlobalProxy(ecx);
1852 } else {
1853 Label convert_to_object, convert_receiver;
1854 __ mov(ecx, Operand(esp, eax, times_pointer_size, kPointerSize));
1855 __ JumpIfSmi(ecx, &convert_to_object, Label::kNear);
1856 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
1857 __ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ebx);
1858 __ j(above_equal, &done_convert);
1859 if (mode != ConvertReceiverMode::kNotNullOrUndefined) {
1860 Label convert_global_proxy;
1861 __ JumpIfRoot(ecx, Heap::kUndefinedValueRootIndex,
1862 &convert_global_proxy, Label::kNear);
1863 __ JumpIfNotRoot(ecx, Heap::kNullValueRootIndex, &convert_to_object,
1864 Label::kNear);
1865 __ bind(&convert_global_proxy);
1866 {
1867 // Patch receiver to global proxy.
1868 __ LoadGlobalProxy(ecx);
1869 }
1870 __ jmp(&convert_receiver);
1871 }
1872 __ bind(&convert_to_object);
1873 {
1874 // Convert receiver using ToObject.
1875 // TODO(bmeurer): Inline the allocation here to avoid building the frame
1876 // in the fast case? (fall back to AllocateInNewSpace?)
1877 FrameScope scope(masm, StackFrame::INTERNAL);
1878 __ SmiTag(eax);
1879 __ Push(eax);
1880 __ Push(edi);
1881 __ mov(eax, ecx);
1882 ToObjectStub stub(masm->isolate());
1883 __ CallStub(&stub);
1884 __ mov(ecx, eax);
1885 __ Pop(edi);
1886 __ Pop(eax);
1887 __ SmiUntag(eax);
1888 }
1889 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1890 __ bind(&convert_receiver);
1891 }
1892 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ecx);
1893 }
1894 __ bind(&done_convert);
1895
1896 // ----------- S t a t e -------------
1897 // -- eax : the number of arguments (not including the receiver)
1898 // -- edx : the shared function info.
1899 // -- edi : the function to call (checked to be a JSFunction)
1900 // -- esi : the function context.
1901 // -----------------------------------
1902
1903 __ mov(ebx,
1904 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
1905 __ SmiUntag(ebx);
1906 ParameterCount actual(eax);
1907 ParameterCount expected(ebx);
1908 __ InvokeFunctionCode(edi, no_reg, expected, actual, JUMP_FUNCTION,
1909 CheckDebugStepCallWrapper());
1910 // The function is a "classConstructor", need to raise an exception.
1911 __ bind(&class_constructor);
1912 {
1913 FrameScope frame(masm, StackFrame::INTERNAL);
1914 __ push(edi);
1915 __ CallRuntime(Runtime::kThrowConstructorNonCallableError);
1916 }
1917 }
1918
1919
1920 namespace {
1921
Generate_PushBoundArguments(MacroAssembler * masm)1922 void Generate_PushBoundArguments(MacroAssembler* masm) {
1923 // ----------- S t a t e -------------
1924 // -- eax : the number of arguments (not including the receiver)
1925 // -- edx : new.target (only in case of [[Construct]])
1926 // -- edi : target (checked to be a JSBoundFunction)
1927 // -----------------------------------
1928
1929 // Load [[BoundArguments]] into ecx and length of that into ebx.
1930 Label no_bound_arguments;
1931 __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset));
1932 __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
1933 __ SmiUntag(ebx);
1934 __ test(ebx, ebx);
1935 __ j(zero, &no_bound_arguments);
1936 {
1937 // ----------- S t a t e -------------
1938 // -- eax : the number of arguments (not including the receiver)
1939 // -- edx : new.target (only in case of [[Construct]])
1940 // -- edi : target (checked to be a JSBoundFunction)
1941 // -- ecx : the [[BoundArguments]] (implemented as FixedArray)
1942 // -- ebx : the number of [[BoundArguments]]
1943 // -----------------------------------
1944
1945 // Reserve stack space for the [[BoundArguments]].
1946 {
1947 Label done;
1948 __ lea(ecx, Operand(ebx, times_pointer_size, 0));
1949 __ sub(esp, ecx);
1950 // Check the stack for overflow. We are not trying to catch interruptions
1951 // (i.e. debug break and preemption) here, so check the "real stack
1952 // limit".
1953 __ CompareRoot(esp, ecx, Heap::kRealStackLimitRootIndex);
1954 __ j(greater, &done, Label::kNear); // Signed comparison.
1955 // Restore the stack pointer.
1956 __ lea(esp, Operand(esp, ebx, times_pointer_size, 0));
1957 {
1958 FrameScope scope(masm, StackFrame::MANUAL);
1959 __ EnterFrame(StackFrame::INTERNAL);
1960 __ CallRuntime(Runtime::kThrowStackOverflow);
1961 }
1962 __ bind(&done);
1963 }
1964
1965 // Adjust effective number of arguments to include return address.
1966 __ inc(eax);
1967
1968 // Relocate arguments and return address down the stack.
1969 {
1970 Label loop;
1971 __ Set(ecx, 0);
1972 __ lea(ebx, Operand(esp, ebx, times_pointer_size, 0));
1973 __ bind(&loop);
1974 __ movd(xmm0, Operand(ebx, ecx, times_pointer_size, 0));
1975 __ movd(Operand(esp, ecx, times_pointer_size, 0), xmm0);
1976 __ inc(ecx);
1977 __ cmp(ecx, eax);
1978 __ j(less, &loop);
1979 }
1980
1981 // Copy [[BoundArguments]] to the stack (below the arguments).
1982 {
1983 Label loop;
1984 __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset));
1985 __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
1986 __ SmiUntag(ebx);
1987 __ bind(&loop);
1988 __ dec(ebx);
1989 __ movd(xmm0, FieldOperand(ecx, ebx, times_pointer_size,
1990 FixedArray::kHeaderSize));
1991 __ movd(Operand(esp, eax, times_pointer_size, 0), xmm0);
1992 __ lea(eax, Operand(eax, 1));
1993 __ j(greater, &loop);
1994 }
1995
1996 // Adjust effective number of arguments (eax contains the number of
1997 // arguments from the call plus return address plus the number of
1998 // [[BoundArguments]]), so we need to subtract one for the return address.
1999 __ dec(eax);
2000 }
2001 __ bind(&no_bound_arguments);
2002 }
2003
2004 } // namespace
2005
2006
2007 // static
Generate_CallBoundFunction(MacroAssembler * masm)2008 void Builtins::Generate_CallBoundFunction(MacroAssembler* masm) {
2009 // ----------- S t a t e -------------
2010 // -- eax : the number of arguments (not including the receiver)
2011 // -- edi : the function to call (checked to be a JSBoundFunction)
2012 // -----------------------------------
2013 __ AssertBoundFunction(edi);
2014
2015 // Patch the receiver to [[BoundThis]].
2016 __ mov(ebx, FieldOperand(edi, JSBoundFunction::kBoundThisOffset));
2017 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ebx);
2018
2019 // Push the [[BoundArguments]] onto the stack.
2020 Generate_PushBoundArguments(masm);
2021
2022 // Call the [[BoundTargetFunction]] via the Call builtin.
2023 __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2024 __ mov(ecx, Operand::StaticVariable(ExternalReference(
2025 Builtins::kCall_ReceiverIsAny, masm->isolate())));
2026 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2027 __ jmp(ecx);
2028 }
2029
2030
2031 // static
Generate_Call(MacroAssembler * masm,ConvertReceiverMode mode)2032 void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
2033 // ----------- S t a t e -------------
2034 // -- eax : the number of arguments (not including the receiver)
2035 // -- edi : the target to call (can be any Object).
2036 // -----------------------------------
2037
2038 Label non_callable, non_function, non_smi;
2039 __ JumpIfSmi(edi, &non_callable);
2040 __ bind(&non_smi);
2041 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
2042 __ j(equal, masm->isolate()->builtins()->CallFunction(mode),
2043 RelocInfo::CODE_TARGET);
2044 __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
2045 __ j(equal, masm->isolate()->builtins()->CallBoundFunction(),
2046 RelocInfo::CODE_TARGET);
2047 __ CmpInstanceType(ecx, JS_PROXY_TYPE);
2048 __ j(not_equal, &non_function);
2049
2050 // 1. Runtime fallback for Proxy [[Call]].
2051 __ PopReturnAddressTo(ecx);
2052 __ Push(edi);
2053 __ PushReturnAddressFrom(ecx);
2054 // Increase the arguments size to include the pushed function and the
2055 // existing receiver on the stack.
2056 __ add(eax, Immediate(2));
2057 // Tail-call to the runtime.
2058 __ JumpToExternalReference(
2059 ExternalReference(Runtime::kJSProxyCall, masm->isolate()));
2060
2061 // 2. Call to something else, which might have a [[Call]] internal method (if
2062 // not we raise an exception).
2063 __ bind(&non_function);
2064 // Check if target has a [[Call]] internal method.
2065 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable);
2066 __ j(zero, &non_callable, Label::kNear);
2067 // Overwrite the original receiver with the (original) target.
2068 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
2069 // Let the "call_as_function_delegate" take care of the rest.
2070 __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, edi);
2071 __ Jump(masm->isolate()->builtins()->CallFunction(
2072 ConvertReceiverMode::kNotNullOrUndefined),
2073 RelocInfo::CODE_TARGET);
2074
2075 // 3. Call to something that is not callable.
2076 __ bind(&non_callable);
2077 {
2078 FrameScope scope(masm, StackFrame::INTERNAL);
2079 __ Push(edi);
2080 __ CallRuntime(Runtime::kThrowCalledNonCallable);
2081 }
2082 }
2083
2084
2085 // static
Generate_ConstructFunction(MacroAssembler * masm)2086 void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
2087 // ----------- S t a t e -------------
2088 // -- eax : the number of arguments (not including the receiver)
2089 // -- edx : the new target (checked to be a constructor)
2090 // -- edi : the constructor to call (checked to be a JSFunction)
2091 // -----------------------------------
2092 __ AssertFunction(edi);
2093
2094 // Calling convention for function specific ConstructStubs require
2095 // ebx to contain either an AllocationSite or undefined.
2096 __ LoadRoot(ebx, Heap::kUndefinedValueRootIndex);
2097
2098 // Tail call to the function-specific construct stub (still in the caller
2099 // context at this point).
2100 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2101 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset));
2102 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2103 __ jmp(ecx);
2104 }
2105
2106
2107 // static
Generate_ConstructBoundFunction(MacroAssembler * masm)2108 void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
2109 // ----------- S t a t e -------------
2110 // -- eax : the number of arguments (not including the receiver)
2111 // -- edx : the new target (checked to be a constructor)
2112 // -- edi : the constructor to call (checked to be a JSBoundFunction)
2113 // -----------------------------------
2114 __ AssertBoundFunction(edi);
2115
2116 // Push the [[BoundArguments]] onto the stack.
2117 Generate_PushBoundArguments(masm);
2118
2119 // Patch new.target to [[BoundTargetFunction]] if new.target equals target.
2120 {
2121 Label done;
2122 __ cmp(edi, edx);
2123 __ j(not_equal, &done, Label::kNear);
2124 __ mov(edx, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2125 __ bind(&done);
2126 }
2127
2128 // Construct the [[BoundTargetFunction]] via the Construct builtin.
2129 __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset));
2130 __ mov(ecx, Operand::StaticVariable(
2131 ExternalReference(Builtins::kConstruct, masm->isolate())));
2132 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize));
2133 __ jmp(ecx);
2134 }
2135
2136
2137 // static
Generate_ConstructProxy(MacroAssembler * masm)2138 void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
2139 // ----------- S t a t e -------------
2140 // -- eax : the number of arguments (not including the receiver)
2141 // -- edi : the constructor to call (checked to be a JSProxy)
2142 // -- edx : the new target (either the same as the constructor or
2143 // the JSFunction on which new was invoked initially)
2144 // -----------------------------------
2145
2146 // Call into the Runtime for Proxy [[Construct]].
2147 __ PopReturnAddressTo(ecx);
2148 __ Push(edi);
2149 __ Push(edx);
2150 __ PushReturnAddressFrom(ecx);
2151 // Include the pushed new_target, constructor and the receiver.
2152 __ add(eax, Immediate(3));
2153 // Tail-call to the runtime.
2154 __ JumpToExternalReference(
2155 ExternalReference(Runtime::kJSProxyConstruct, masm->isolate()));
2156 }
2157
2158
2159 // static
Generate_Construct(MacroAssembler * masm)2160 void Builtins::Generate_Construct(MacroAssembler* masm) {
2161 // ----------- S t a t e -------------
2162 // -- eax : the number of arguments (not including the receiver)
2163 // -- edx : the new target (either the same as the constructor or
2164 // the JSFunction on which new was invoked initially)
2165 // -- edi : the constructor to call (can be any Object)
2166 // -----------------------------------
2167
2168 // Check if target is a Smi.
2169 Label non_constructor;
2170 __ JumpIfSmi(edi, &non_constructor, Label::kNear);
2171
2172 // Dispatch based on instance type.
2173 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
2174 __ j(equal, masm->isolate()->builtins()->ConstructFunction(),
2175 RelocInfo::CODE_TARGET);
2176
2177 // Check if target has a [[Construct]] internal method.
2178 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor);
2179 __ j(zero, &non_constructor, Label::kNear);
2180
2181 // Only dispatch to bound functions after checking whether they are
2182 // constructors.
2183 __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE);
2184 __ j(equal, masm->isolate()->builtins()->ConstructBoundFunction(),
2185 RelocInfo::CODE_TARGET);
2186
2187 // Only dispatch to proxies after checking whether they are constructors.
2188 __ CmpInstanceType(ecx, JS_PROXY_TYPE);
2189 __ j(equal, masm->isolate()->builtins()->ConstructProxy(),
2190 RelocInfo::CODE_TARGET);
2191
2192 // Called Construct on an exotic Object with a [[Construct]] internal method.
2193 {
2194 // Overwrite the original receiver with the (original) target.
2195 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi);
2196 // Let the "call_as_constructor_delegate" take care of the rest.
2197 __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, edi);
2198 __ Jump(masm->isolate()->builtins()->CallFunction(),
2199 RelocInfo::CODE_TARGET);
2200 }
2201
2202 // Called Construct on an Object that doesn't have a [[Construct]] internal
2203 // method.
2204 __ bind(&non_constructor);
2205 __ Jump(masm->isolate()->builtins()->ConstructedNonConstructable(),
2206 RelocInfo::CODE_TARGET);
2207 }
2208
2209
Generate_ArgumentsAdaptorTrampoline(MacroAssembler * masm)2210 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
2211 // ----------- S t a t e -------------
2212 // -- eax : actual number of arguments
2213 // -- ebx : expected number of arguments
2214 // -- edx : new target (passed through to callee)
2215 // -- edi : function (passed through to callee)
2216 // -----------------------------------
2217
2218 Label invoke, dont_adapt_arguments, stack_overflow;
2219 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
2220
2221 Label enough, too_few;
2222 __ cmp(eax, ebx);
2223 __ j(less, &too_few);
2224 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
2225 __ j(equal, &dont_adapt_arguments);
2226
2227 { // Enough parameters: Actual >= expected.
2228 __ bind(&enough);
2229 EnterArgumentsAdaptorFrame(masm);
2230 ArgumentsAdaptorStackCheck(masm, &stack_overflow);
2231
2232 // Copy receiver and all expected arguments.
2233 const int offset = StandardFrameConstants::kCallerSPOffset;
2234 __ lea(edi, Operand(ebp, eax, times_4, offset));
2235 __ mov(eax, -1); // account for receiver
2236
2237 Label copy;
2238 __ bind(©);
2239 __ inc(eax);
2240 __ push(Operand(edi, 0));
2241 __ sub(edi, Immediate(kPointerSize));
2242 __ cmp(eax, ebx);
2243 __ j(less, ©);
2244 // eax now contains the expected number of arguments.
2245 __ jmp(&invoke);
2246 }
2247
2248 { // Too few parameters: Actual < expected.
2249 __ bind(&too_few);
2250
2251 // If the function is strong we need to throw an error.
2252 Label no_strong_error;
2253 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2254 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrongModeByteOffset),
2255 1 << SharedFunctionInfo::kStrongModeBitWithinByte);
2256 __ j(equal, &no_strong_error, Label::kNear);
2257
2258 // What we really care about is the required number of arguments.
2259 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kLengthOffset));
2260 __ SmiUntag(ecx);
2261 __ cmp(eax, ecx);
2262 __ j(greater_equal, &no_strong_error, Label::kNear);
2263
2264 {
2265 FrameScope frame(masm, StackFrame::MANUAL);
2266 EnterArgumentsAdaptorFrame(masm);
2267 __ CallRuntime(Runtime::kThrowStrongModeTooFewArguments);
2268 }
2269
2270 __ bind(&no_strong_error);
2271 EnterArgumentsAdaptorFrame(masm);
2272 ArgumentsAdaptorStackCheck(masm, &stack_overflow);
2273
2274 // Remember expected arguments in ecx.
2275 __ mov(ecx, ebx);
2276
2277 // Copy receiver and all actual arguments.
2278 const int offset = StandardFrameConstants::kCallerSPOffset;
2279 __ lea(edi, Operand(ebp, eax, times_4, offset));
2280 // ebx = expected - actual.
2281 __ sub(ebx, eax);
2282 // eax = -actual - 1
2283 __ neg(eax);
2284 __ sub(eax, Immediate(1));
2285
2286 Label copy;
2287 __ bind(©);
2288 __ inc(eax);
2289 __ push(Operand(edi, 0));
2290 __ sub(edi, Immediate(kPointerSize));
2291 __ test(eax, eax);
2292 __ j(not_zero, ©);
2293
2294 // Fill remaining expected arguments with undefined values.
2295 Label fill;
2296 __ bind(&fill);
2297 __ inc(eax);
2298 __ push(Immediate(masm->isolate()->factory()->undefined_value()));
2299 __ cmp(eax, ebx);
2300 __ j(less, &fill);
2301
2302 // Restore expected arguments.
2303 __ mov(eax, ecx);
2304 }
2305
2306 // Call the entry point.
2307 __ bind(&invoke);
2308 // Restore function pointer.
2309 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
2310 // eax : expected number of arguments
2311 // edx : new target (passed through to callee)
2312 // edi : function (passed through to callee)
2313 __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2314 __ call(ecx);
2315
2316 // Store offset of return address for deoptimizer.
2317 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
2318
2319 // Leave frame and return.
2320 LeaveArgumentsAdaptorFrame(masm);
2321 __ ret(0);
2322
2323 // -------------------------------------------
2324 // Dont adapt arguments.
2325 // -------------------------------------------
2326 __ bind(&dont_adapt_arguments);
2327 __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2328 __ jmp(ecx);
2329
2330 __ bind(&stack_overflow);
2331 {
2332 FrameScope frame(masm, StackFrame::MANUAL);
2333 __ CallRuntime(Runtime::kThrowStackOverflow);
2334 __ int3();
2335 }
2336 }
2337
2338
CompatibleReceiverCheck(MacroAssembler * masm,Register receiver,Register function_template_info,Register scratch0,Register scratch1,Label * receiver_check_failed)2339 static void CompatibleReceiverCheck(MacroAssembler* masm, Register receiver,
2340 Register function_template_info,
2341 Register scratch0, Register scratch1,
2342 Label* receiver_check_failed) {
2343 // If there is no signature, return the holder.
2344 __ CompareRoot(FieldOperand(function_template_info,
2345 FunctionTemplateInfo::kSignatureOffset),
2346 Heap::kUndefinedValueRootIndex);
2347 Label receiver_check_passed;
2348 __ j(equal, &receiver_check_passed, Label::kNear);
2349
2350 // Walk the prototype chain.
2351 __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
2352 Label prototype_loop_start;
2353 __ bind(&prototype_loop_start);
2354
2355 // Get the constructor, if any.
2356 __ GetMapConstructor(scratch0, scratch0, scratch1);
2357 __ CmpInstanceType(scratch1, JS_FUNCTION_TYPE);
2358 Label next_prototype;
2359 __ j(not_equal, &next_prototype, Label::kNear);
2360
2361 // Get the constructor's signature.
2362 __ mov(scratch0,
2363 FieldOperand(scratch0, JSFunction::kSharedFunctionInfoOffset));
2364 __ mov(scratch0,
2365 FieldOperand(scratch0, SharedFunctionInfo::kFunctionDataOffset));
2366
2367 // Loop through the chain of inheriting function templates.
2368 Label function_template_loop;
2369 __ bind(&function_template_loop);
2370
2371 // If the signatures match, we have a compatible receiver.
2372 __ cmp(scratch0, FieldOperand(function_template_info,
2373 FunctionTemplateInfo::kSignatureOffset));
2374 __ j(equal, &receiver_check_passed, Label::kNear);
2375
2376 // If the current type is not a FunctionTemplateInfo, load the next prototype
2377 // in the chain.
2378 __ JumpIfSmi(scratch0, &next_prototype, Label::kNear);
2379 __ CmpObjectType(scratch0, FUNCTION_TEMPLATE_INFO_TYPE, scratch1);
2380 __ j(not_equal, &next_prototype, Label::kNear);
2381
2382 // Otherwise load the parent function template and iterate.
2383 __ mov(scratch0,
2384 FieldOperand(scratch0, FunctionTemplateInfo::kParentTemplateOffset));
2385 __ jmp(&function_template_loop, Label::kNear);
2386
2387 // Load the next prototype.
2388 __ bind(&next_prototype);
2389 __ mov(receiver, FieldOperand(receiver, HeapObject::kMapOffset));
2390 __ mov(receiver, FieldOperand(receiver, Map::kPrototypeOffset));
2391 // End if the prototype is null or not hidden.
2392 __ CompareRoot(receiver, Heap::kNullValueRootIndex);
2393 __ j(equal, receiver_check_failed);
2394 __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
2395 __ test(FieldOperand(scratch0, Map::kBitField3Offset),
2396 Immediate(Map::IsHiddenPrototype::kMask));
2397 __ j(zero, receiver_check_failed);
2398 // Iterate.
2399 __ jmp(&prototype_loop_start, Label::kNear);
2400
2401 __ bind(&receiver_check_passed);
2402 }
2403
2404
Generate_HandleFastApiCall(MacroAssembler * masm)2405 void Builtins::Generate_HandleFastApiCall(MacroAssembler* masm) {
2406 // ----------- S t a t e -------------
2407 // -- eax : number of arguments (not including the receiver)
2408 // -- edi : callee
2409 // -- esi : context
2410 // -- esp[0] : return address
2411 // -- esp[4] : last argument
2412 // -- ...
2413 // -- esp[eax * 4] : first argument
2414 // -- esp[(eax + 1) * 4] : receiver
2415 // -----------------------------------
2416
2417 // Load the FunctionTemplateInfo.
2418 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2419 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kFunctionDataOffset));
2420
2421 // Do the compatible receiver check.
2422 Label receiver_check_failed;
2423 __ mov(ecx, Operand(esp, eax, times_pointer_size, kPCOnStackSize));
2424 __ Push(eax);
2425 CompatibleReceiverCheck(masm, ecx, ebx, edx, eax, &receiver_check_failed);
2426 __ Pop(eax);
2427 // Get the callback offset from the FunctionTemplateInfo, and jump to the
2428 // beginning of the code.
2429 __ mov(edx, FieldOperand(ebx, FunctionTemplateInfo::kCallCodeOffset));
2430 __ mov(edx, FieldOperand(edx, CallHandlerInfo::kFastHandlerOffset));
2431 __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
2432 __ jmp(edx);
2433
2434 // Compatible receiver check failed: pop return address, arguments and
2435 // receiver and throw an Illegal Invocation exception.
2436 __ bind(&receiver_check_failed);
2437 __ Pop(eax);
2438 __ PopReturnAddressTo(ebx);
2439 __ lea(eax, Operand(eax, times_pointer_size, 1 * kPointerSize));
2440 __ add(esp, eax);
2441 __ PushReturnAddressFrom(ebx);
2442 {
2443 FrameScope scope(masm, StackFrame::INTERNAL);
2444 __ TailCallRuntime(Runtime::kThrowIllegalInvocation);
2445 }
2446 }
2447
2448
Generate_OnStackReplacement(MacroAssembler * masm)2449 void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
2450 // Lookup the function in the JavaScript frame.
2451 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
2452 {
2453 FrameScope scope(masm, StackFrame::INTERNAL);
2454 // Pass function as argument.
2455 __ push(eax);
2456 __ CallRuntime(Runtime::kCompileForOnStackReplacement);
2457 }
2458
2459 Label skip;
2460 // If the code object is null, just return to the unoptimized code.
2461 __ cmp(eax, Immediate(0));
2462 __ j(not_equal, &skip, Label::kNear);
2463 __ ret(0);
2464
2465 __ bind(&skip);
2466
2467 // Load deoptimization data from the code object.
2468 __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag));
2469
2470 // Load the OSR entrypoint offset from the deoptimization data.
2471 __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt(
2472 DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag));
2473 __ SmiUntag(ebx);
2474
2475 // Compute the target address = code_obj + header_size + osr_offset
2476 __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag));
2477
2478 // Overwrite the return address on the stack.
2479 __ mov(Operand(esp, 0), eax);
2480
2481 // And "return" to the OSR entry point of the function.
2482 __ ret(0);
2483 }
2484
2485
Generate_OsrAfterStackCheck(MacroAssembler * masm)2486 void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
2487 // We check the stack limit as indicator that recompilation might be done.
2488 Label ok;
2489 ExternalReference stack_limit =
2490 ExternalReference::address_of_stack_limit(masm->isolate());
2491 __ cmp(esp, Operand::StaticVariable(stack_limit));
2492 __ j(above_equal, &ok, Label::kNear);
2493 {
2494 FrameScope scope(masm, StackFrame::INTERNAL);
2495 __ CallRuntime(Runtime::kStackGuard);
2496 }
2497 __ jmp(masm->isolate()->builtins()->OnStackReplacement(),
2498 RelocInfo::CODE_TARGET);
2499
2500 __ bind(&ok);
2501 __ ret(0);
2502 }
2503
2504 #undef __
2505 } // namespace internal
2506 } // namespace v8
2507
2508 #endif // V8_TARGET_ARCH_IA32
2509