V8 Project
builtins-ia32.cc
Go to the documentation of this file.
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 #include "src/v8.h"
6 
7 #if V8_TARGET_ARCH_IA32
8 
9 #include "src/code-factory.h"
10 #include "src/codegen.h"
11 #include "src/deoptimizer.h"
12 #include "src/full-codegen.h"
13 
14 namespace v8 {
15 namespace internal {
16 
17 
18 #define __ ACCESS_MASM(masm)
19 
20 
21 void Builtins::Generate_Adaptor(MacroAssembler* masm,
22  CFunctionId id,
23  BuiltinExtraArguments extra_args) {
24  // ----------- S t a t e -------------
25  // -- eax : number of arguments excluding receiver
26  // -- edi : called function (only guaranteed when
27  // extra_args requires it)
28  // -- esi : context
29  // -- esp[0] : return address
30  // -- esp[4] : last argument
31  // -- ...
32  // -- esp[4 * argc] : first argument (argc == eax)
33  // -- esp[4 * (argc +1)] : receiver
34  // -----------------------------------
35 
36  // Insert extra arguments.
37  int num_extra_args = 0;
38  if (extra_args == NEEDS_CALLED_FUNCTION) {
39  num_extra_args = 1;
40  Register scratch = ebx;
41  __ pop(scratch); // Save return address.
42  __ push(edi);
43  __ push(scratch); // Restore return address.
44  } else {
45  DCHECK(extra_args == NO_EXTRA_ARGUMENTS);
46  }
47 
48  // JumpToExternalReference expects eax to contain the number of arguments
49  // including the receiver and the extra arguments.
50  __ add(eax, Immediate(num_extra_args + 1));
51  __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
52 }
53 
54 
55 static void CallRuntimePassFunction(
56  MacroAssembler* masm, Runtime::FunctionId function_id) {
57  FrameScope scope(masm, StackFrame::INTERNAL);
58  // Push a copy of the function.
59  __ push(edi);
60  // Function is also the parameter to the runtime call.
61  __ push(edi);
62 
63  __ CallRuntime(function_id, 1);
64  // Restore receiver.
65  __ pop(edi);
66 }
67 
68 
69 static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
73  __ jmp(eax);
74 }
75 
76 
77 static void GenerateTailCallToReturnedCode(MacroAssembler* masm) {
79  __ jmp(eax);
80 }
81 
82 
83 void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
84  // Checking whether the queued function is ready for install is optional,
85  // since we come across interrupts and stack checks elsewhere. However,
86  // not checking may delay installing ready functions, and always checking
87  // would be quite expensive. A good compromise is to first check against
88  // stack limit as a cue for an interrupt signal.
89  Label ok;
90  ExternalReference stack_limit =
91  ExternalReference::address_of_stack_limit(masm->isolate());
92  __ cmp(esp, Operand::StaticVariable(stack_limit));
93  __ j(above_equal, &ok, Label::kNear);
94 
95  CallRuntimePassFunction(masm, Runtime::kTryInstallOptimizedCode);
96  GenerateTailCallToReturnedCode(masm);
97 
98  __ bind(&ok);
99  GenerateTailCallToSharedCode(masm);
100 }
101 
102 
103 static void Generate_JSConstructStubHelper(MacroAssembler* masm,
104  bool is_api_function,
105  bool create_memento) {
106  // ----------- S t a t e -------------
107  // -- eax: number of arguments
108  // -- edi: constructor function
109  // -- ebx: allocation site or undefined
110  // -----------------------------------
111 
112  // Should never create mementos for api functions.
113  DCHECK(!is_api_function || !create_memento);
114 
115  // Enter a construct frame.
116  {
117  FrameScope scope(masm, StackFrame::CONSTRUCT);
118 
119  if (create_memento) {
120  __ AssertUndefinedOrAllocationSite(ebx);
121  __ push(ebx);
122  }
123 
124  // Store a smi-tagged arguments count on the stack.
125  __ SmiTag(eax);
126  __ push(eax);
127 
128  // Push the function to invoke on the stack.
129  __ push(edi);
130 
131  // Try to allocate the object without transitioning into C code. If any of
132  // the preconditions is not met, the code bails out to the runtime call.
133  Label rt_call, allocated;
134  if (FLAG_inline_new) {
135  Label undo_allocation;
136  ExternalReference debug_step_in_fp =
137  ExternalReference::debug_step_in_fp_address(masm->isolate());
138  __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
139  __ j(not_equal, &rt_call);
140 
141  // Verified that the constructor is a JSFunction.
142  // Load the initial map and verify that it is in fact a map.
143  // edi: constructor
145  // Will both indicate a NULL and a Smi
146  __ JumpIfSmi(eax, &rt_call);
147  // edi: constructor
148  // eax: initial map (if proven valid below)
149  __ CmpObjectType(eax, MAP_TYPE, ebx);
150  __ j(not_equal, &rt_call);
151 
152  // Check that the constructor is not constructing a JSFunction (see
153  // comments in Runtime_NewObject in runtime.cc). In which case the
154  // initial map's instance type would be JS_FUNCTION_TYPE.
155  // edi: constructor
156  // eax: initial map
157  __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
158  __ j(equal, &rt_call);
159 
160  if (!is_api_function) {
161  Label allocate;
162  // The code below relies on these assumptions.
166  // Check if slack tracking is enabled.
169  __ j(zero, &allocate); // JSFunction::kNoSlackTracking
170  // Decrease generous allocation count.
172  Immediate(1 << Map::ConstructionCount::kShift));
173 
175  __ j(not_equal, &allocate);
176 
177  __ push(eax);
178  __ push(edi);
179 
180  __ push(edi); // constructor
181  __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
182 
183  __ pop(edi);
184  __ pop(eax);
185  __ xor_(esi, esi); // JSFunction::kNoSlackTracking
186 
187  __ bind(&allocate);
188  }
189 
190  // Now allocate the JSObject on the heap.
191  // edi: constructor
192  // eax: initial map
194  __ shl(edi, kPointerSizeLog2);
195  if (create_memento) {
196  __ add(edi, Immediate(AllocationMemento::kSize));
197  }
198 
199  __ Allocate(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS);
200 
201  Factory* factory = masm->isolate()->factory();
202 
203  // Allocated the JSObject, now initialize the fields.
204  // eax: initial map
205  // ebx: JSObject
206  // edi: start of next object (including memento if create_memento)
207  __ mov(Operand(ebx, JSObject::kMapOffset), eax);
208  __ mov(ecx, factory->empty_fixed_array());
209  __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
210  __ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
211  // Set extra fields in the newly allocated object.
212  // eax: initial map
213  // ebx: JSObject
214  // edi: start of next object (including memento if create_memento)
215  // esi: slack tracking counter (non-API function case)
216  __ mov(edx, factory->undefined_value());
217  __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
218  if (!is_api_function) {
219  Label no_inobject_slack_tracking;
220 
221  // Check if slack tracking is enabled.
223  __ j(equal, &no_inobject_slack_tracking);
224 
225  // Allocate object with a slack.
226  __ movzx_b(esi,
228  __ lea(esi,
230  // esi: offset of first field after pre-allocated fields
231  if (FLAG_debug_code) {
232  __ cmp(esi, edi);
233  __ Assert(less_equal,
234  kUnexpectedNumberOfPreAllocatedPropertyFields);
235  }
236  __ InitializeFieldsWithFiller(ecx, esi, edx);
237  __ mov(edx, factory->one_pointer_filler_map());
238  // Fill the remaining fields with one pointer filler map.
239 
240  __ bind(&no_inobject_slack_tracking);
241  }
242 
243  if (create_memento) {
244  __ lea(esi, Operand(edi, -AllocationMemento::kSize));
245  __ InitializeFieldsWithFiller(ecx, esi, edx);
246 
247  // Fill in memento fields if necessary.
248  // esi: points to the allocated but uninitialized memento.
249  __ mov(Operand(esi, AllocationMemento::kMapOffset),
250  factory->allocation_memento_map());
251  // Get the cell or undefined.
252  __ mov(edx, Operand(esp, kPointerSize*2));
254  edx);
255  } else {
256  __ InitializeFieldsWithFiller(ecx, edi, edx);
257  }
258 
259  // Add the object tag to make the JSObject real, so that we can continue
260  // and jump into the continuation code at any time from now on. Any
261  // failures need to undo the allocation, so that the heap is in a
262  // consistent state and verifiable.
263  // eax: initial map
264  // ebx: JSObject
265  // edi: start of next object
266  __ or_(ebx, Immediate(kHeapObjectTag));
267 
268  // Check if a non-empty properties array is needed.
269  // Allocate and initialize a FixedArray if it is.
270  // eax: initial map
271  // ebx: JSObject
272  // edi: start of next object
273  // Calculate the total number of properties described by the map.
275  __ movzx_b(ecx,
277  __ add(edx, ecx);
278  // Calculate unused properties past the end of the in-object properties.
280  __ sub(edx, ecx);
281  // Done if no extra properties are to be allocated.
282  __ j(zero, &allocated);
283  __ Assert(positive, kPropertyAllocationCountFailed);
284 
285  // Scale the number of elements by pointer size and add the header for
286  // FixedArrays to the start of the next object calculation from above.
287  // ebx: JSObject
288  // edi: start of next object (will be start of FixedArray)
289  // edx: number of elements in properties array
290  __ Allocate(FixedArray::kHeaderSize,
292  edx,
294  edi,
295  ecx,
296  no_reg,
297  &undo_allocation,
299 
300  // Initialize the FixedArray.
301  // ebx: JSObject
302  // edi: FixedArray
303  // edx: number of elements
304  // ecx: start of next object
305  __ mov(eax, factory->fixed_array_map());
306  __ mov(Operand(edi, FixedArray::kMapOffset), eax); // setup the map
307  __ SmiTag(edx);
308  __ mov(Operand(edi, FixedArray::kLengthOffset), edx); // and length
309 
310  // Initialize the fields to undefined.
311  // ebx: JSObject
312  // edi: FixedArray
313  // ecx: start of next object
314  { Label loop, entry;
315  __ mov(edx, factory->undefined_value());
316  __ lea(eax, Operand(edi, FixedArray::kHeaderSize));
317  __ jmp(&entry);
318  __ bind(&loop);
319  __ mov(Operand(eax, 0), edx);
320  __ add(eax, Immediate(kPointerSize));
321  __ bind(&entry);
322  __ cmp(eax, ecx);
323  __ j(below, &loop);
324  }
325 
326  // Store the initialized FixedArray into the properties field of
327  // the JSObject
328  // ebx: JSObject
329  // edi: FixedArray
330  __ or_(edi, Immediate(kHeapObjectTag)); // add the heap tag
332 
333 
334  // Continue with JSObject being successfully allocated
335  // ebx: JSObject
336  __ jmp(&allocated);
337 
338  // Undo the setting of the new top so that the heap is verifiable. For
339  // example, the map's unused properties potentially do not match the
340  // allocated objects unused properties.
341  // ebx: JSObject (previous new top)
342  __ bind(&undo_allocation);
343  __ UndoAllocationInNewSpace(ebx);
344  }
345 
346  // Allocate the new receiver object using the runtime call.
347  __ bind(&rt_call);
348  int offset = 0;
349  if (create_memento) {
350  // Get the cell or allocation site.
351  __ mov(edi, Operand(esp, kPointerSize * 2));
352  __ push(edi);
353  offset = kPointerSize;
354  }
355 
356  // Must restore esi (context) and edi (constructor) before calling runtime.
358  __ mov(edi, Operand(esp, offset));
359  // edi: function (constructor)
360  __ push(edi);
361  if (create_memento) {
362  __ CallRuntime(Runtime::kNewObjectWithAllocationSite, 2);
363  } else {
364  __ CallRuntime(Runtime::kNewObject, 1);
365  }
366  __ mov(ebx, eax); // store result in ebx
367 
368  // If we ended up using the runtime, and we want a memento, then the
369  // runtime call made it for us, and we shouldn't do create count
370  // increment.
371  Label count_incremented;
372  if (create_memento) {
373  __ jmp(&count_incremented);
374  }
375 
376  // New object allocated.
377  // ebx: newly allocated object
378  __ bind(&allocated);
379 
380  if (create_memento) {
381  __ mov(ecx, Operand(esp, kPointerSize * 2));
382  __ cmp(ecx, masm->isolate()->factory()->undefined_value());
383  __ j(equal, &count_incremented);
384  // ecx is an AllocationSite. We are creating a memento from it, so we
385  // need to increment the memento create count.
387  Immediate(Smi::FromInt(1)));
388  __ bind(&count_incremented);
389  }
390 
391  // Retrieve the function from the stack.
392  __ pop(edi);
393 
394  // Retrieve smi-tagged arguments count from the stack.
395  __ mov(eax, Operand(esp, 0));
396  __ SmiUntag(eax);
397 
398  // Push the allocated receiver to the stack. We need two copies
399  // because we may have to return the original one and the calling
400  // conventions dictate that the called function pops the receiver.
401  __ push(ebx);
402  __ push(ebx);
403 
404  // Set up pointer to last argument.
406 
407  // Copy arguments and receiver to the expression stack.
408  Label loop, entry;
409  __ mov(ecx, eax);
410  __ jmp(&entry);
411  __ bind(&loop);
412  __ push(Operand(ebx, ecx, times_4, 0));
413  __ bind(&entry);
414  __ dec(ecx);
415  __ j(greater_equal, &loop);
416 
417  // Call the function.
418  if (is_api_function) {
420  Handle<Code> code =
421  masm->isolate()->builtins()->HandleApiCallConstruct();
422  __ call(code, RelocInfo::CODE_TARGET);
423  } else {
424  ParameterCount actual(eax);
425  __ InvokeFunction(edi, actual, CALL_FUNCTION,
426  NullCallWrapper());
427  }
428 
429  // Store offset of return address for deoptimizer.
430  if (!is_api_function) {
431  masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
432  }
433 
434  // Restore context from the frame.
436 
437  // If the result is an object (in the ECMA sense), we should get rid
438  // of the receiver and use the result; see ECMA-262 section 13.2.2-7
439  // on page 74.
440  Label use_receiver, exit;
441 
442  // If the result is a smi, it is *not* an object in the ECMA sense.
443  __ JumpIfSmi(eax, &use_receiver);
444 
445  // If the type of the result (stored in its map) is less than
446  // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
447  __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
448  __ j(above_equal, &exit);
449 
450  // Throw away the result of the constructor invocation and use the
451  // on-stack receiver as the result.
452  __ bind(&use_receiver);
453  __ mov(eax, Operand(esp, 0));
454 
455  // Restore the arguments count and leave the construct frame.
456  __ bind(&exit);
457  __ mov(ebx, Operand(esp, kPointerSize)); // Get arguments count.
458 
459  // Leave construct frame.
460  }
461 
462  // Remove caller arguments from the stack and return.
463  STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
464  __ pop(ecx);
465  __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
466  __ push(ecx);
467  __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
468  __ ret(0);
469 }
470 
471 
472 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
473  Generate_JSConstructStubHelper(masm, false, FLAG_pretenuring_call_new);
474 }
475 
476 
477 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
478  Generate_JSConstructStubHelper(masm, true, false);
479 }
480 
481 
482 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
483  bool is_construct) {
485 
486  // Clear the context before we push it when entering the internal frame.
487  __ Move(esi, Immediate(0));
488 
489  {
490  FrameScope scope(masm, StackFrame::INTERNAL);
491 
492  // Load the previous frame pointer (ebx) to access C arguments
493  __ mov(ebx, Operand(ebp, 0));
494 
495  // Get the function from the frame and setup the context.
498 
499  // Push the function and the receiver onto the stack.
500  __ push(ecx);
502 
503  // Load the number of arguments and setup pointer to the arguments.
504  __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
505  __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
506 
507  // Copy arguments to the stack in a loop.
508  Label loop, entry;
509  __ Move(ecx, Immediate(0));
510  __ jmp(&entry);
511  __ bind(&loop);
512  __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv
513  __ push(Operand(edx, 0)); // dereference handle
514  __ inc(ecx);
515  __ bind(&entry);
516  __ cmp(ecx, eax);
517  __ j(not_equal, &loop);
518 
519  // Get the function from the stack and call it.
520  // kPointerSize for the receiver.
521  __ mov(edi, Operand(esp, eax, times_4, kPointerSize));
522 
523  // Invoke the code.
524  if (is_construct) {
525  // No type feedback cell is available
526  __ mov(ebx, masm->isolate()->factory()->undefined_value());
527  CallConstructStub stub(masm->isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
528  __ CallStub(&stub);
529  } else {
530  ParameterCount actual(eax);
531  __ InvokeFunction(edi, actual, CALL_FUNCTION,
532  NullCallWrapper());
533  }
534 
535  // Exit the internal frame. Notice that this also removes the empty.
536  // context and the function left on the stack by the code
537  // invocation.
538  }
539  __ ret(kPointerSize); // Remove receiver.
540 }
541 
542 
543 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
544  Generate_JSEntryTrampolineHelper(masm, false);
545 }
546 
547 
548 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
549  Generate_JSEntryTrampolineHelper(masm, true);
550 }
551 
552 
553 void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
554  CallRuntimePassFunction(masm, Runtime::kCompileLazy);
555  GenerateTailCallToReturnedCode(masm);
556 }
557 
558 
559 
560 static void CallCompileOptimized(MacroAssembler* masm, bool concurrent) {
561  FrameScope scope(masm, StackFrame::INTERNAL);
562  // Push a copy of the function.
563  __ push(edi);
564  // Function is also the parameter to the runtime call.
565  __ push(edi);
566  // Whether to compile in a background thread.
567  __ Push(masm->isolate()->factory()->ToBoolean(concurrent));
568 
569  __ CallRuntime(Runtime::kCompileOptimized, 2);
570  // Restore receiver.
571  __ pop(edi);
572 }
573 
574 
575 void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
576  CallCompileOptimized(masm, false);
577  GenerateTailCallToReturnedCode(masm);
578 }
579 
580 
581 void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
582  CallCompileOptimized(masm, true);
583  GenerateTailCallToReturnedCode(masm);
584 }
585 
586 
587 static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
588  // For now, we are relying on the fact that make_code_young doesn't do any
589  // garbage collection which allows us to save/restore the registers without
590  // worrying about which of them contain pointers. We also don't build an
591  // internal frame to make the code faster, since we shouldn't have to do stack
592  // crawls in MakeCodeYoung. This seems a bit fragile.
593 
594  // Re-execute the code that was patched back to the young age when
595  // the stub returns.
596  __ sub(Operand(esp, 0), Immediate(5));
597  __ pushad();
598  __ mov(eax, Operand(esp, 8 * kPointerSize));
599  {
600  FrameScope scope(masm, StackFrame::MANUAL);
601  __ PrepareCallCFunction(2, ebx);
602  __ mov(Operand(esp, 1 * kPointerSize),
603  Immediate(ExternalReference::isolate_address(masm->isolate())));
604  __ mov(Operand(esp, 0), eax);
605  __ CallCFunction(
606  ExternalReference::get_make_code_young_function(masm->isolate()), 2);
607  }
608  __ popad();
609  __ ret(0);
610 }
611 
612 #define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
613 void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
614  MacroAssembler* masm) { \
615  GenerateMakeCodeYoungAgainCommon(masm); \
616 } \
617 void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
618  MacroAssembler* masm) { \
619  GenerateMakeCodeYoungAgainCommon(masm); \
620 }
621 CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
622 #undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
623 
624 
625 void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
626  // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
627  // that make_code_young doesn't do any garbage collection which allows us to
628  // save/restore the registers without worrying about which of them contain
629  // pointers.
630  __ pushad();
631  __ mov(eax, Operand(esp, 8 * kPointerSize));
632  __ sub(eax, Immediate(Assembler::kCallInstructionLength));
633  { // NOLINT
634  FrameScope scope(masm, StackFrame::MANUAL);
635  __ PrepareCallCFunction(2, ebx);
636  __ mov(Operand(esp, 1 * kPointerSize),
637  Immediate(ExternalReference::isolate_address(masm->isolate())));
638  __ mov(Operand(esp, 0), eax);
639  __ CallCFunction(
640  ExternalReference::get_mark_code_as_executed_function(masm->isolate()),
641  2);
642  }
643  __ popad();
644 
645  // Perform prologue operations usually performed by the young code stub.
646  __ pop(eax); // Pop return address into scratch register.
647  __ push(ebp); // Caller's frame pointer.
648  __ mov(ebp, esp);
649  __ push(esi); // Callee's context.
650  __ push(edi); // Callee's JS Function.
651  __ push(eax); // Push return address after frame prologue.
652 
653  // Jump to point after the code-age stub.
654  __ ret(0);
655 }
656 
657 
658 void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
659  GenerateMakeCodeYoungAgainCommon(masm);
660 }
661 
662 
663 static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
664  SaveFPRegsMode save_doubles) {
665  // Enter an internal frame.
666  {
667  FrameScope scope(masm, StackFrame::INTERNAL);
668 
669  // Preserve registers across notification, this is important for compiled
670  // stubs that tail call the runtime on deopts passing their parameters in
671  // registers.
672  __ pushad();
673  __ CallRuntime(Runtime::kNotifyStubFailure, 0, save_doubles);
674  __ popad();
675  // Tear down internal frame.
676  }
677 
678  __ pop(MemOperand(esp, 0)); // Ignore state offset
679  __ ret(0); // Return to IC Miss stub, continuation still on stack.
680 }
681 
682 
683 void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
684  Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
685 }
686 
687 
688 void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
689  Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
690 }
691 
692 
693 static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
695  {
696  FrameScope scope(masm, StackFrame::INTERNAL);
697 
698  // Pass deoptimization type to the runtime system.
699  __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
700  __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
701 
702  // Tear down internal frame.
703  }
704 
705  // Get the full codegen state from the stack and untag it.
706  __ mov(ecx, Operand(esp, 1 * kPointerSize));
707  __ SmiUntag(ecx);
708 
709  // Switch on the state.
710  Label not_no_registers, not_tos_eax;
712  __ j(not_equal, &not_no_registers, Label::kNear);
713  __ ret(1 * kPointerSize); // Remove state.
714 
715  __ bind(&not_no_registers);
716  __ mov(eax, Operand(esp, 2 * kPointerSize));
718  __ j(not_equal, &not_tos_eax, Label::kNear);
719  __ ret(2 * kPointerSize); // Remove state, eax.
720 
721  __ bind(&not_tos_eax);
722  __ Abort(kNoCasesLeft);
723 }
724 
725 
726 void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
727  Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
728 }
729 
730 
731 void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
732  Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
733 }
734 
735 
736 void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
737  Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
738 }
739 
740 
741 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
742  Factory* factory = masm->isolate()->factory();
743 
744  // 1. Make sure we have at least one argument.
745  { Label done;
746  __ test(eax, eax);
747  __ j(not_zero, &done);
748  __ pop(ebx);
749  __ push(Immediate(factory->undefined_value()));
750  __ push(ebx);
751  __ inc(eax);
752  __ bind(&done);
753  }
754 
755  // 2. Get the function to call (passed as receiver) from the stack, check
756  // if it is a function.
757  Label slow, non_function;
758  // 1 ~ return address.
759  __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
760  __ JumpIfSmi(edi, &non_function);
761  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
762  __ j(not_equal, &slow);
763 
764 
765  // 3a. Patch the first argument if necessary when calling a function.
766  Label shift_arguments;
767  __ Move(edx, Immediate(0)); // indicate regular JS_FUNCTION
768  { Label convert_to_object, use_global_proxy, patch_receiver;
769  // Change context eagerly in case we need the global receiver.
771 
772  // Do not transform the receiver for strict mode functions.
774  __ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset),
776  __ j(not_equal, &shift_arguments);
777 
778  // Do not transform the receiver for natives (shared already in ebx).
779  __ test_b(FieldOperand(ebx, SharedFunctionInfo::kNativeByteOffset),
781  __ j(not_equal, &shift_arguments);
782 
783  // Compute the receiver in sloppy mode.
784  __ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument.
785 
786  // Call ToObject on the receiver if it is not an object, or use the
787  // global object if it is null or undefined.
788  __ JumpIfSmi(ebx, &convert_to_object);
789  __ cmp(ebx, factory->null_value());
790  __ j(equal, &use_global_proxy);
791  __ cmp(ebx, factory->undefined_value());
792  __ j(equal, &use_global_proxy);
794  __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
795  __ j(above_equal, &shift_arguments);
796 
797  __ bind(&convert_to_object);
798 
799  { // In order to preserve argument count.
800  FrameScope scope(masm, StackFrame::INTERNAL);
801  __ SmiTag(eax);
802  __ push(eax);
803 
804  __ push(ebx);
805  __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
806  __ mov(ebx, eax);
807  __ Move(edx, Immediate(0)); // restore
808 
809  __ pop(eax);
810  __ SmiUntag(eax);
811  }
812 
813  // Restore the function to edi.
814  __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
815  __ jmp(&patch_receiver);
816 
817  __ bind(&use_global_proxy);
818  __ mov(ebx,
821 
822  __ bind(&patch_receiver);
823  __ mov(Operand(esp, eax, times_4, 0), ebx);
824 
825  __ jmp(&shift_arguments);
826  }
827 
828  // 3b. Check for function proxy.
829  __ bind(&slow);
830  __ Move(edx, Immediate(1)); // indicate function proxy
831  __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
832  __ j(equal, &shift_arguments);
833  __ bind(&non_function);
834  __ Move(edx, Immediate(2)); // indicate non-function
835 
836  // 3c. Patch the first argument when calling a non-function. The
837  // CALL_NON_FUNCTION builtin expects the non-function callee as
838  // receiver, so overwrite the first argument which will ultimately
839  // become the receiver.
840  __ mov(Operand(esp, eax, times_4, 0), edi);
841 
842  // 4. Shift arguments and return address one slot down on the stack
843  // (overwriting the original receiver). Adjust argument count to make
844  // the original first argument the new receiver.
845  __ bind(&shift_arguments);
846  { Label loop;
847  __ mov(ecx, eax);
848  __ bind(&loop);
849  __ mov(ebx, Operand(esp, ecx, times_4, 0));
850  __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
851  __ dec(ecx);
852  __ j(not_sign, &loop); // While non-negative (to copy return address).
853  __ pop(ebx); // Discard copy of return address.
854  __ dec(eax); // One fewer argument (first argument is new receiver).
855  }
856 
857  // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
858  // or a function proxy via CALL_FUNCTION_PROXY.
859  { Label function, non_proxy;
860  __ test(edx, edx);
861  __ j(zero, &function);
862  __ Move(ebx, Immediate(0));
863  __ cmp(edx, Immediate(1));
864  __ j(not_equal, &non_proxy);
865 
866  __ pop(edx); // return address
867  __ push(edi); // re-add proxy object as additional argument
868  __ push(edx);
869  __ inc(eax);
870  __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
871  __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
873 
874  __ bind(&non_proxy);
875  __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
876  __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
878  __ bind(&function);
879  }
880 
881  // 5b. Get the code to call from the function and check that the number of
882  // expected arguments matches what we're providing. If so, jump
883  // (tail-call) to the code in register edx without checking arguments.
885  __ mov(ebx,
888  __ SmiUntag(ebx);
889  __ cmp(eax, ebx);
890  __ j(not_equal,
891  masm->isolate()->builtins()->ArgumentsAdaptorTrampoline());
892 
893  ParameterCount expected(0);
894  __ InvokeCode(edx, expected, expected, JUMP_FUNCTION, NullCallWrapper());
895 }
896 
897 
898 void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
899  static const int kArgumentsOffset = 2 * kPointerSize;
900  static const int kReceiverOffset = 3 * kPointerSize;
901  static const int kFunctionOffset = 4 * kPointerSize;
902  {
903  FrameScope frame_scope(masm, StackFrame::INTERNAL);
904 
905  __ push(Operand(ebp, kFunctionOffset)); // push this
906  __ push(Operand(ebp, kArgumentsOffset)); // push arguments
907  __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
908 
909  // Check the stack for overflow. We are not trying to catch
910  // interruptions (e.g. debug break and preemption) here, so the "real stack
911  // limit" is checked.
912  Label okay;
913  ExternalReference real_stack_limit =
914  ExternalReference::address_of_real_stack_limit(masm->isolate());
915  __ mov(edi, Operand::StaticVariable(real_stack_limit));
916  // Make ecx the space we have left. The stack might already be overflowed
917  // here which will cause ecx to become negative.
918  __ mov(ecx, esp);
919  __ sub(ecx, edi);
920  // Make edx the space we need for the array when it is unrolled onto the
921  // stack.
922  __ mov(edx, eax);
924  // Check if the arguments will overflow the stack.
925  __ cmp(ecx, edx);
926  __ j(greater, &okay); // Signed comparison.
927 
928  // Out of stack space.
929  __ push(Operand(ebp, 4 * kPointerSize)); // push this
930  __ push(eax);
931  __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
932  __ bind(&okay);
933  // End of stack check.
934 
935  // Push current index and limit.
936  const int kLimitOffset =
938  const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
939  __ push(eax); // limit
940  __ push(Immediate(0)); // index
941 
942  // Get the receiver.
943  __ mov(ebx, Operand(ebp, kReceiverOffset));
944 
945  // Check that the function is a JS function (otherwise it must be a proxy).
946  Label push_receiver, use_global_proxy;
947  __ mov(edi, Operand(ebp, kFunctionOffset));
948  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
949  __ j(not_equal, &push_receiver);
950 
951  // Change context eagerly to get the right global object if necessary.
953 
954  // Compute the receiver.
955  // Do not transform the receiver for strict mode functions.
956  Label call_to_object;
958  __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
960  __ j(not_equal, &push_receiver);
961 
962  Factory* factory = masm->isolate()->factory();
963 
964  // Do not transform the receiver for natives (shared already in ecx).
965  __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset),
967  __ j(not_equal, &push_receiver);
968 
969  // Compute the receiver in sloppy mode.
970  // Call ToObject on the receiver if it is not an object, or use the
971  // global object if it is null or undefined.
972  __ JumpIfSmi(ebx, &call_to_object);
973  __ cmp(ebx, factory->null_value());
974  __ j(equal, &use_global_proxy);
975  __ cmp(ebx, factory->undefined_value());
976  __ j(equal, &use_global_proxy);
978  __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
979  __ j(above_equal, &push_receiver);
980 
981  __ bind(&call_to_object);
982  __ push(ebx);
983  __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
984  __ mov(ebx, eax);
985  __ jmp(&push_receiver);
986 
987  __ bind(&use_global_proxy);
988  __ mov(ebx,
991 
992  // Push the receiver.
993  __ bind(&push_receiver);
994  __ push(ebx);
995 
996  // Copy all arguments from the array to the stack.
997  Label entry, loop;
998  Register receiver = LoadDescriptor::ReceiverRegister();
999  Register key = LoadDescriptor::NameRegister();
1000  __ mov(key, Operand(ebp, kIndexOffset));
1001  __ jmp(&entry);
1002  __ bind(&loop);
1003  __ mov(receiver, Operand(ebp, kArgumentsOffset)); // load arguments
1004 
1005  // Use inline caching to speed up access to arguments.
1006  if (FLAG_vector_ics) {
1008  Immediate(Smi::FromInt(0)));
1009  }
1010  Handle<Code> ic = CodeFactory::KeyedLoadIC(masm->isolate()).code();
1011  __ call(ic, RelocInfo::CODE_TARGET);
1012  // It is important that we do not have a test instruction after the
1013  // call. A test instruction after the call is used to indicate that
1014  // we have generated an inline version of the keyed load. In this
1015  // case, we know that we are not generating a test instruction next.
1016 
1017  // Push the nth argument.
1018  __ push(eax);
1019 
1020  // Update the index on the stack and in register key.
1021  __ mov(key, Operand(ebp, kIndexOffset));
1022  __ add(key, Immediate(1 << kSmiTagSize));
1023  __ mov(Operand(ebp, kIndexOffset), key);
1024 
1025  __ bind(&entry);
1026  __ cmp(key, Operand(ebp, kLimitOffset));
1027  __ j(not_equal, &loop);
1028 
1029  // Call the function.
1030  Label call_proxy;
1031  ParameterCount actual(eax);
1032  __ Move(eax, key);
1033  __ SmiUntag(eax);
1034  __ mov(edi, Operand(ebp, kFunctionOffset));
1035  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
1036  __ j(not_equal, &call_proxy);
1037  __ InvokeFunction(edi, actual, CALL_FUNCTION, NullCallWrapper());
1038 
1039  frame_scope.GenerateLeaveFrame();
1040  __ ret(3 * kPointerSize); // remove this, receiver, and arguments
1041 
1042  // Call the function proxy.
1043  __ bind(&call_proxy);
1044  __ push(edi); // add function proxy as last argument
1045  __ inc(eax);
1046  __ Move(ebx, Immediate(0));
1047  __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
1048  __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1050 
1051  // Leave internal frame.
1052  }
1053  __ ret(3 * kPointerSize); // remove this, receiver, and arguments
1054 }
1055 
1056 
1057 void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
1058  // ----------- S t a t e -------------
1059  // -- eax : argc
1060  // -- esp[0] : return address
1061  // -- esp[4] : last argument
1062  // -----------------------------------
1063  Label generic_array_code;
1064 
1065  // Get the InternalArray function.
1066  __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi);
1067 
1068  if (FLAG_debug_code) {
1069  // Initial map for the builtin InternalArray function should be a map.
1071  // Will both indicate a NULL and a Smi.
1072  __ test(ebx, Immediate(kSmiTagMask));
1073  __ Assert(not_zero, kUnexpectedInitialMapForInternalArrayFunction);
1074  __ CmpObjectType(ebx, MAP_TYPE, ecx);
1075  __ Assert(equal, kUnexpectedInitialMapForInternalArrayFunction);
1076  }
1077 
1078  // Run the native code for the InternalArray function called as a normal
1079  // function.
1080  // tail call a stub
1081  InternalArrayConstructorStub stub(masm->isolate());
1082  __ TailCallStub(&stub);
1083 }
1084 
1085 
1086 void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1087  // ----------- S t a t e -------------
1088  // -- eax : argc
1089  // -- esp[0] : return address
1090  // -- esp[4] : last argument
1091  // -----------------------------------
1092  Label generic_array_code;
1093 
1094  // Get the Array function.
1095  __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
1096 
1097  if (FLAG_debug_code) {
1098  // Initial map for the builtin Array function should be a map.
1100  // Will both indicate a NULL and a Smi.
1101  __ test(ebx, Immediate(kSmiTagMask));
1102  __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
1103  __ CmpObjectType(ebx, MAP_TYPE, ecx);
1104  __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
1105  }
1106 
1107  // Run the native code for the Array function called as a normal function.
1108  // tail call a stub
1109  __ mov(ebx, masm->isolate()->factory()->undefined_value());
1110  ArrayConstructorStub stub(masm->isolate());
1111  __ TailCallStub(&stub);
1112 }
1113 
1114 
1115 void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
1116  // ----------- S t a t e -------------
1117  // -- eax : number of arguments
1118  // -- edi : constructor function
1119  // -- esp[0] : return address
1120  // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1121  // -- esp[(argc + 1) * 4] : receiver
1122  // -----------------------------------
1123  Counters* counters = masm->isolate()->counters();
1124  __ IncrementCounter(counters->string_ctor_calls(), 1);
1125 
1126  if (FLAG_debug_code) {
1127  __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx);
1128  __ cmp(edi, ecx);
1129  __ Assert(equal, kUnexpectedStringFunction);
1130  }
1131 
1132  // Load the first argument into eax and get rid of the rest
1133  // (including the receiver).
1134  Label no_arguments;
1135  __ test(eax, eax);
1136  __ j(zero, &no_arguments);
1137  __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1138  __ pop(ecx);
1139  __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1140  __ push(ecx);
1141  __ mov(eax, ebx);
1142 
1143  // Lookup the argument in the number to string cache.
1144  Label not_cached, argument_is_string;
1145  __ LookupNumberStringCache(eax, // Input.
1146  ebx, // Result.
1147  ecx, // Scratch 1.
1148  edx, // Scratch 2.
1149  &not_cached);
1150  __ IncrementCounter(counters->string_ctor_cached_number(), 1);
1151  __ bind(&argument_is_string);
1152  // ----------- S t a t e -------------
1153  // -- ebx : argument converted to string
1154  // -- edi : constructor function
1155  // -- esp[0] : return address
1156  // -----------------------------------
1157 
1158  // Allocate a JSValue and put the tagged pointer into eax.
1159  Label gc_required;
1160  __ Allocate(JSValue::kSize,
1161  eax, // Result.
1162  ecx, // New allocation top (we ignore it).
1163  no_reg,
1164  &gc_required,
1165  TAG_OBJECT);
1166 
1167  // Set the map.
1168  __ LoadGlobalFunctionInitialMap(edi, ecx);
1169  if (FLAG_debug_code) {
1172  __ Assert(equal, kUnexpectedStringWrapperInstanceSize);
1174  __ Assert(equal, kUnexpectedUnusedPropertiesOfStringWrapper);
1175  }
1177 
1178  // Set properties and elements.
1179  Factory* factory = masm->isolate()->factory();
1180  __ Move(ecx, Immediate(factory->empty_fixed_array()));
1183 
1184  // Set the value.
1186 
1187  // Ensure the object is fully initialized.
1189 
1190  // We're done. Return.
1191  __ ret(0);
1192 
1193  // The argument was not found in the number to string cache. Check
1194  // if it's a string already before calling the conversion builtin.
1195  Label convert_argument;
1196  __ bind(&not_cached);
1197  STATIC_ASSERT(kSmiTag == 0);
1198  __ JumpIfSmi(eax, &convert_argument);
1199  Condition is_string = masm->IsObjectStringType(eax, ebx, ecx);
1200  __ j(NegateCondition(is_string), &convert_argument);
1201  __ mov(ebx, eax);
1202  __ IncrementCounter(counters->string_ctor_string_value(), 1);
1203  __ jmp(&argument_is_string);
1204 
1205  // Invoke the conversion builtin and put the result into ebx.
1206  __ bind(&convert_argument);
1207  __ IncrementCounter(counters->string_ctor_conversions(), 1);
1208  {
1209  FrameScope scope(masm, StackFrame::INTERNAL);
1210  __ push(edi); // Preserve the function.
1211  __ push(eax);
1212  __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
1213  __ pop(edi);
1214  }
1215  __ mov(ebx, eax);
1216  __ jmp(&argument_is_string);
1217 
1218  // Load the empty string into ebx, remove the receiver from the
1219  // stack, and jump back to the case where the argument is a string.
1220  __ bind(&no_arguments);
1221  __ Move(ebx, Immediate(factory->empty_string()));
1222  __ pop(ecx);
1223  __ lea(esp, Operand(esp, kPointerSize));
1224  __ push(ecx);
1225  __ jmp(&argument_is_string);
1226 
1227  // At this point the argument is already a string. Call runtime to
1228  // create a string wrapper.
1229  __ bind(&gc_required);
1230  __ IncrementCounter(counters->string_ctor_gc_required(), 1);
1231  {
1232  FrameScope scope(masm, StackFrame::INTERNAL);
1233  __ push(ebx);
1234  __ CallRuntime(Runtime::kNewStringWrapper, 1);
1235  }
1236  __ ret(0);
1237 }
1238 
1239 
1240 static void ArgumentsAdaptorStackCheck(MacroAssembler* masm,
1241  Label* stack_overflow) {
1242  // ----------- S t a t e -------------
1243  // -- eax : actual number of arguments
1244  // -- ebx : expected number of arguments
1245  // -- edi : function (passed through to callee)
1246  // -----------------------------------
1247  // Check the stack for overflow. We are not trying to catch
1248  // interruptions (e.g. debug break and preemption) here, so the "real stack
1249  // limit" is checked.
1250  ExternalReference real_stack_limit =
1251  ExternalReference::address_of_real_stack_limit(masm->isolate());
1252  __ mov(edx, Operand::StaticVariable(real_stack_limit));
1253  // Make ecx the space we have left. The stack might already be overflowed
1254  // here which will cause ecx to become negative.
1255  __ mov(ecx, esp);
1256  __ sub(ecx, edx);
1257  // Make edx the space we need for the array when it is unrolled onto the
1258  // stack.
1259  __ mov(edx, ebx);
1260  __ shl(edx, kPointerSizeLog2);
1261  // Check if the arguments will overflow the stack.
1262  __ cmp(ecx, edx);
1263  __ j(less_equal, stack_overflow); // Signed comparison.
1264 }
1265 
1266 
1267 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1268  __ push(ebp);
1269  __ mov(ebp, esp);
1270 
1271  // Store the arguments adaptor context sentinel.
1272  __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1273 
1274  // Push the function on the stack.
1275  __ push(edi);
1276 
1277  // Preserve the number of arguments on the stack. Must preserve eax,
1278  // ebx and ecx because these registers are used when copying the
1279  // arguments and the receiver.
1280  STATIC_ASSERT(kSmiTagSize == 1);
1281  __ lea(edi, Operand(eax, eax, times_1, kSmiTag));
1282  __ push(edi);
1283 }
1284 
1285 
1286 static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1287  // Retrieve the number of arguments from the stack.
1289 
1290  // Leave the frame.
1291  __ leave();
1292 
1293  // Remove caller arguments from the stack.
1294  STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
1295  __ pop(ecx);
1296  __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
1297  __ push(ecx);
1298 }
1299 
1300 
1301 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1302  // ----------- S t a t e -------------
1303  // -- eax : actual number of arguments
1304  // -- ebx : expected number of arguments
1305  // -- edi : function (passed through to callee)
1306  // -----------------------------------
1307 
1308  Label invoke, dont_adapt_arguments;
1309  __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
1310 
1311  Label stack_overflow;
1312  ArgumentsAdaptorStackCheck(masm, &stack_overflow);
1313 
1314  Label enough, too_few;
1316  __ cmp(eax, ebx);
1317  __ j(less, &too_few);
1319  __ j(equal, &dont_adapt_arguments);
1320 
1321  { // Enough parameters: Actual >= expected.
1322  __ bind(&enough);
1323  EnterArgumentsAdaptorFrame(masm);
1324 
1325  // Copy receiver and all expected arguments.
1326  const int offset = StandardFrameConstants::kCallerSPOffset;
1327  __ lea(eax, Operand(ebp, eax, times_4, offset));
1328  __ mov(edi, -1); // account for receiver
1329 
1330  Label copy;
1331  __ bind(&copy);
1332  __ inc(edi);
1333  __ push(Operand(eax, 0));
1334  __ sub(eax, Immediate(kPointerSize));
1335  __ cmp(edi, ebx);
1336  __ j(less, &copy);
1337  __ jmp(&invoke);
1338  }
1339 
1340  { // Too few parameters: Actual < expected.
1341  __ bind(&too_few);
1342  EnterArgumentsAdaptorFrame(masm);
1343 
1344  // Copy receiver and all actual arguments.
1345  const int offset = StandardFrameConstants::kCallerSPOffset;
1346  __ lea(edi, Operand(ebp, eax, times_4, offset));
1347  // ebx = expected - actual.
1348  __ sub(ebx, eax);
1349  // eax = -actual - 1
1350  __ neg(eax);
1351  __ sub(eax, Immediate(1));
1352 
1353  Label copy;
1354  __ bind(&copy);
1355  __ inc(eax);
1356  __ push(Operand(edi, 0));
1357  __ sub(edi, Immediate(kPointerSize));
1358  __ test(eax, eax);
1359  __ j(not_zero, &copy);
1360 
1361  // Fill remaining expected arguments with undefined values.
1362  Label fill;
1363  __ bind(&fill);
1364  __ inc(eax);
1365  __ push(Immediate(masm->isolate()->factory()->undefined_value()));
1366  __ cmp(eax, ebx);
1367  __ j(less, &fill);
1368  }
1369 
1370  // Call the entry point.
1371  __ bind(&invoke);
1372  // Restore function pointer.
1374  __ call(edx);
1375 
1376  // Store offset of return address for deoptimizer.
1377  masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
1378 
1379  // Leave frame and return.
1380  LeaveArgumentsAdaptorFrame(masm);
1381  __ ret(0);
1382 
1383  // -------------------------------------------
1384  // Dont adapt arguments.
1385  // -------------------------------------------
1386  __ bind(&dont_adapt_arguments);
1387  __ jmp(edx);
1388 
1389  __ bind(&stack_overflow);
1390  {
1391  FrameScope frame(masm, StackFrame::MANUAL);
1392  EnterArgumentsAdaptorFrame(masm);
1393  __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
1394  __ int3();
1395  }
1396 }
1397 
1398 
1399 void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
1400  // Lookup the function in the JavaScript frame.
1402  {
1403  FrameScope scope(masm, StackFrame::INTERNAL);
1404  // Pass function as argument.
1405  __ push(eax);
1406  __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
1407  }
1408 
1409  Label skip;
1410  // If the code object is null, just return to the unoptimized code.
1411  __ cmp(eax, Immediate(0));
1412  __ j(not_equal, &skip, Label::kNear);
1413  __ ret(0);
1414 
1415  __ bind(&skip);
1416 
1417  // Load deoptimization data from the code object.
1419 
1420  // Load the OSR entrypoint offset from the deoptimization data.
1421  __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt(
1423  __ SmiUntag(ebx);
1424 
1425  // Compute the target address = code_obj + header_size + osr_offset
1426  __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag));
1427 
1428  // Overwrite the return address on the stack.
1429  __ mov(Operand(esp, 0), eax);
1430 
1431  // And "return" to the OSR entry point of the function.
1432  __ ret(0);
1433 }
1434 
1435 
1436 void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
1437  // We check the stack limit as indicator that recompilation might be done.
1438  Label ok;
1439  ExternalReference stack_limit =
1440  ExternalReference::address_of_stack_limit(masm->isolate());
1441  __ cmp(esp, Operand::StaticVariable(stack_limit));
1442  __ j(above_equal, &ok, Label::kNear);
1443  {
1444  FrameScope scope(masm, StackFrame::INTERNAL);
1445  __ CallRuntime(Runtime::kStackGuard, 0);
1446  }
1447  __ jmp(masm->isolate()->builtins()->OnStackReplacement(),
1449 
1450  __ bind(&ok);
1451  __ ret(0);
1452 }
1453 
1454 #undef __
1455 }
1456 } // namespace v8::internal
1457 
1458 #endif // V8_TARGET_ARCH_IA32
#define CODE_AGE_LIST(V)
Definition: builtins.h:27
static const int kAllocationSiteOffset
Definition: objects.h:8286
static const int kPretenureCreateCountOffset
Definition: objects.h:8257
static const int kCallInstructionLength
static const U kShift
Definition: utils.h:204
static const U kSize
Definition: utils.h:205
static void Generate_InternalArrayCode(MacroAssembler *masm)
static void Generate_FunctionApply(MacroAssembler *masm)
static void Generate_Adaptor(MacroAssembler *masm, CFunctionId id, BuiltinExtraArguments extra_args)
static void Generate_NotifyDeoptimized(MacroAssembler *masm)
static void Generate_JSConstructEntryTrampoline(MacroAssembler *masm)
static void Generate_CompileLazy(MacroAssembler *masm)
static void Generate_JSEntryTrampoline(MacroAssembler *masm)
static void Generate_OnStackReplacement(MacroAssembler *masm)
static void Generate_MarkCodeAsExecutedTwice(MacroAssembler *masm)
static void Generate_NotifyLazyDeoptimized(MacroAssembler *masm)
static void Generate_ArgumentsAdaptorTrampoline(MacroAssembler *masm)
static void Generate_JSConstructStubApi(MacroAssembler *masm)
static void Generate_FunctionCall(MacroAssembler *masm)
static void Generate_MarkCodeAsExecutedOnce(MacroAssembler *masm)
static void Generate_NotifyStubFailureSaveDoubles(MacroAssembler *masm)
static void Generate_NotifySoftDeoptimized(MacroAssembler *masm)
static void Generate_ArrayCode(MacroAssembler *masm)
static void Generate_StringConstructCode(MacroAssembler *masm)
static void Generate_NotifyStubFailure(MacroAssembler *masm)
static void Generate_CompileOptimized(MacroAssembler *masm)
static void Generate_OsrAfterStackCheck(MacroAssembler *masm)
static void Generate_InOptimizationQueue(MacroAssembler *masm)
static void Generate_CompileOptimizedConcurrent(MacroAssembler *masm)
static void Generate_JSConstructStubGeneric(MacroAssembler *masm)
static const int kHeaderSize
Definition: objects.h:5373
static const int kDeoptimizationDataOffset
Definition: objects.h:5352
static int SlotOffset(int index)
Definition: contexts.h:552
static const int kFunctionArgOffset
Definition: frames-ia32.h:42
static const int kReceiverArgOffset
Definition: frames-ia32.h:43
static const int kLengthOffset
Definition: objects.h:2392
static const int kHeaderSize
Definition: objects.h:2393
static int OffsetOfElementAt(int index)
Definition: objects.h:2455
static const int kGlobalProxyOffset
Definition: objects.h:7461
static const int kMapOffset
Definition: objects.h:1427
static const int kSharedFunctionInfoOffset
Definition: objects.h:7379
static const int kNoSlackTracking
Definition: objects.h:7263
static const int kContextOffset
Definition: objects.h:7381
static const int kFinishSlackTracking
Definition: objects.h:7262
static const int kCodeEntryOffset
Definition: objects.h:7376
static const int kPrototypeOrInitialMapOffset
Definition: objects.h:7377
static const int kHeaderSize
Definition: objects.h:2195
static const int kPropertiesOffset
Definition: objects.h:2193
static const int kElementsOffset
Definition: objects.h:2194
static const int kValueOffset
Definition: objects.h:7546
static const int kSize
Definition: objects.h:7547
static const Register ReceiverRegister()
static const Register NameRegister()
static const int kBitField3Offset
Definition: objects.h:6189
static const int kInstanceSizeOffset
Definition: objects.h:6210
static const int kPreAllocatedPropertyFieldsOffset
Definition: objects.h:6215
static const int kInObjectPropertiesOffset
Definition: objects.h:6212
static const int kUnusedPropertyFieldsOffset
Definition: objects.h:6234
static void MaybeCallEntryHook(MacroAssembler *masm)
static const int kFormalParameterCountOffset
Definition: objects.h:6946
static const int kDontAdaptArgumentsSentinel
Definition: objects.h:6888
static const int kNativeBitWithinByte
Definition: objects.h:7046
static const int kStrictModeBitWithinByte
Definition: objects.h:7043
static const int kCodeOffset
Definition: objects.h:6893
static Smi * FromInt(int value)
Definition: objects-inl.h:1321
static const int kContextOffset
Definition: frames.h:162
static const int kExpressionsOffset
Definition: frames.h:160
static const int kCallerSPOffset
Definition: frames.h:167
#define __
#define DCHECK(condition)
Definition: logging.h:205
@ JUMP_FUNCTION
@ CALL_FUNCTION
@ RESULT_CONTAINS_TOP
@ NO_ALLOCATION_FLAGS
@ TAG_OBJECT
static int Push(SpecialRPOStackFrame *stack, int depth, BasicBlock *child, int unvisited)
Definition: scheduler.cc:773
const int kPointerSize
Definition: globals.h:129
const Register edx
const Register edi
const Register esp
const int kSmiTagSize
Definition: v8.h:5743
Operand FieldOperand(Register object, int offset)
const int kPointerSizeLog2
Definition: globals.h:147
@ FIRST_SPEC_OBJECT_TYPE
Definition: objects.h:781
@ LAST_SPEC_OBJECT_TYPE
Definition: objects.h:782
@ JS_FUNCTION_TYPE
Definition: objects.h:749
@ JS_FUNCTION_PROXY_TYPE
Definition: objects.h:726
const Register esi
const Register eax
const Register ebx
Condition NegateCondition(Condition cond)
Definition: constants-arm.h:86
OStream & dec(OStream &os)
Definition: ostreams.cc:122
const int kHeapObjectTag
Definition: v8.h:5737
BuiltinExtraArguments
Definition: builtins.h:12
@ NEEDS_CALLED_FUNCTION
Definition: builtins.h:14
@ NO_EXTRA_ARGUMENTS
Definition: builtins.h:13
const Register no_reg
STATIC_ASSERT(sizeof(CPURegister)==sizeof(Register))
const intptr_t kSmiTagMask
Definition: v8.h:5744
const Register ebp
@ NO_CALL_CONSTRUCTOR_FLAGS
Definition: globals.h:478
const int kSmiTag
Definition: v8.h:5742
const Register ecx
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20