• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/codegen.h"
10 #include "src/deoptimizer.h"
11 #include "src/full-codegen.h"
12 #include "src/stub-cache.h"
13 
14 namespace v8 {
15 namespace internal {
16 
17 
18 #define __ ACCESS_MASM(masm)
19 
20 
Generate_Adaptor(MacroAssembler * masm,CFunctionId id,BuiltinExtraArguments extra_args)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     ASSERT(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 
CallRuntimePassFunction(MacroAssembler * masm,Runtime::FunctionId function_id)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 
GenerateTailCallToSharedCode(MacroAssembler * masm)69 static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
70   __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
71   __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kCodeOffset));
72   __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
73   __ jmp(eax);
74 }
75 
76 
GenerateTailCallToReturnedCode(MacroAssembler * masm)77 static void GenerateTailCallToReturnedCode(MacroAssembler* masm) {
78   __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
79   __ jmp(eax);
80 }
81 
82 
Generate_InOptimizationQueue(MacroAssembler * masm)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::kHiddenTryInstallOptimizedCode);
96   GenerateTailCallToReturnedCode(masm);
97 
98   __ bind(&ok);
99   GenerateTailCallToSharedCode(masm);
100 }
101 
102 
Generate_JSConstructStubHelper(MacroAssembler * masm,bool is_api_function,bool create_memento)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   ASSERT(!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
144       __ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
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.
163         STATIC_ASSERT(JSFunction::kNoSlackTracking == 0);
164         STATIC_ASSERT(Map::ConstructionCount::kShift +
165                       Map::ConstructionCount::kSize == 32);
166         // Check if slack tracking is enabled.
167         __ mov(esi, FieldOperand(eax, Map::kBitField3Offset));
168         __ shr(esi, Map::ConstructionCount::kShift);
169         __ j(zero, &allocate);  // JSFunction::kNoSlackTracking
170         // Decrease generous allocation count.
171         __ sub(FieldOperand(eax, Map::kBitField3Offset),
172                Immediate(1 << Map::ConstructionCount::kShift));
173 
174         __ cmp(esi, JSFunction::kFinishSlackTracking);
175         __ j(not_equal, &allocate);
176 
177         __ push(eax);
178         __ push(edi);
179 
180         __ push(edi);  // constructor
181         __ CallRuntime(Runtime::kHiddenFinalizeInstanceSize, 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
193       __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset));
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.
222         __ cmp(esi, JSFunction::kNoSlackTracking);
223         __ j(equal, &no_inobject_slack_tracking);
224 
225         // Allocate object with a slack.
226         __ movzx_b(esi,
227                    FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
228         __ lea(esi,
229                Operand(ebx, esi, times_pointer_size, JSObject::kHeaderSize));
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));
253         __ mov(Operand(esi, AllocationMemento::kAllocationSiteOffset),
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.
274       __ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
275       __ movzx_b(ecx,
276                  FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
277       __ add(edx, ecx);
278       // Calculate unused properties past the end of the in-object properties.
279       __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset));
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,
291                   times_pointer_size,
292                   edx,
293                   REGISTER_VALUE_IS_INT32,
294                   edi,
295                   ecx,
296                   no_reg,
297                   &undo_allocation,
298                   RESULT_CONTAINS_TOP);
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
331       __ mov(FieldOperand(ebx, JSObject::kPropertiesOffset), edi);
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.
357     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
358     __ mov(edi, Operand(esp, offset));
359     // edi: function (constructor)
360     __ push(edi);
361     if (create_memento) {
362       __ CallRuntime(Runtime::kHiddenNewObjectWithAllocationSite, 2);
363     } else {
364       __ CallRuntime(Runtime::kHiddenNewObject, 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.
386       __ add(FieldOperand(ecx, AllocationSite::kPretenureCreateCountOffset),
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.
405     __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
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) {
419       __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
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.
435     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
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 
Generate_JSConstructStubGeneric(MacroAssembler * masm)472 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
473   Generate_JSConstructStubHelper(masm, false, FLAG_pretenuring_call_new);
474 }
475 
476 
Generate_JSConstructStubApi(MacroAssembler * masm)477 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
478   Generate_JSConstructStubHelper(masm, true, false);
479 }
480 
481 
Generate_JSEntryTrampolineHelper(MacroAssembler * masm,bool is_construct)482 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
483                                              bool is_construct) {
484   ProfileEntryHookStub::MaybeCallEntryHook(masm);
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.
496     __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
497     __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset));
498 
499     // Push the function and the receiver onto the stack.
500     __ push(ecx);
501     __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
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 
Generate_JSEntryTrampoline(MacroAssembler * masm)543 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
544   Generate_JSEntryTrampolineHelper(masm, false);
545 }
546 
547 
Generate_JSConstructEntryTrampoline(MacroAssembler * masm)548 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
549   Generate_JSEntryTrampolineHelper(masm, true);
550 }
551 
552 
Generate_CompileUnoptimized(MacroAssembler * masm)553 void Builtins::Generate_CompileUnoptimized(MacroAssembler* masm) {
554   CallRuntimePassFunction(masm, Runtime::kHiddenCompileUnoptimized);
555   GenerateTailCallToReturnedCode(masm);
556 }
557 
558 
559 
CallCompileOptimized(MacroAssembler * masm,bool concurrent)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::kHiddenCompileOptimized, 2);
570   // Restore receiver.
571   __ pop(edi);
572 }
573 
574 
Generate_CompileOptimized(MacroAssembler * masm)575 void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
576   CallCompileOptimized(masm, false);
577   GenerateTailCallToReturnedCode(masm);
578 }
579 
580 
Generate_CompileOptimizedConcurrent(MacroAssembler * masm)581 void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
582   CallCompileOptimized(masm, true);
583   GenerateTailCallToReturnedCode(masm);
584 }
585 
586 
GenerateMakeCodeYoungAgainCommon(MacroAssembler * masm)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 }
CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)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 
Generate_MarkCodeAsExecutedTwice(MacroAssembler * masm)658 void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
659   GenerateMakeCodeYoungAgainCommon(masm);
660 }
661 
662 
Generate_NotifyStubFailureHelper(MacroAssembler * masm,SaveFPRegsMode save_doubles)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::kHiddenNotifyStubFailure, 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 
Generate_NotifyStubFailure(MacroAssembler * masm)683 void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
684   Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
685 }
686 
687 
Generate_NotifyStubFailureSaveDoubles(MacroAssembler * masm)688 void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
689   Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
690 }
691 
692 
Generate_NotifyDeoptimizedHelper(MacroAssembler * masm,Deoptimizer::BailoutType type)693 static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
694                                              Deoptimizer::BailoutType type) {
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::kHiddenNotifyDeoptimized, 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;
711   __ cmp(ecx, FullCodeGenerator::NO_REGISTERS);
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));
717   __ cmp(ecx, FullCodeGenerator::TOS_REG);
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 
Generate_NotifyDeoptimized(MacroAssembler * masm)726 void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
727   Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
728 }
729 
730 
Generate_NotifySoftDeoptimized(MacroAssembler * masm)731 void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
732   Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
733 }
734 
735 
Generate_NotifyLazyDeoptimized(MacroAssembler * masm)736 void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
737   Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
738 }
739 
740 
Generate_FunctionCall(MacroAssembler * masm)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_receiver, patch_receiver;
769     // Change context eagerly in case we need the global receiver.
770     __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
771 
772     // Do not transform the receiver for strict mode functions.
773     __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
774     __ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset),
775               1 << SharedFunctionInfo::kStrictModeBitWithinByte);
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),
780               1 << SharedFunctionInfo::kNativeBitWithinByte);
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_receiver);
791     __ cmp(ebx, factory->undefined_value());
792     __ j(equal, &use_global_receiver);
793     STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
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_receiver);
818     __ mov(ebx,
819            Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
820     __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
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(),
872            RelocInfo::CODE_TARGET);
873 
874     __ bind(&non_proxy);
875     __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
876     __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
877            RelocInfo::CODE_TARGET);
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.
884   __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
885   __ mov(ebx,
886          FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
887   __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
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 
Generate_FunctionApply(MacroAssembler * masm)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);
923     __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
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 =
937         StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
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_receiver;
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.
952     __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
953 
954     // Compute the receiver.
955     // Do not transform the receiver for strict mode functions.
956     Label call_to_object;
957     __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
958     __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
959               1 << SharedFunctionInfo::kStrictModeBitWithinByte);
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),
966               1 << SharedFunctionInfo::kNativeBitWithinByte);
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_receiver);
975     __ cmp(ebx, factory->undefined_value());
976     __ j(equal, &use_global_receiver);
977     STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
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_receiver);
988     __ mov(ebx,
989            Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
990     __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
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     __ mov(ecx, Operand(ebp, kIndexOffset));
999     __ jmp(&entry);
1000     __ bind(&loop);
1001     __ mov(edx, Operand(ebp, kArgumentsOffset));  // load arguments
1002 
1003     // Use inline caching to speed up access to arguments.
1004     Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize();
1005     __ call(ic, RelocInfo::CODE_TARGET);
1006     // It is important that we do not have a test instruction after the
1007     // call.  A test instruction after the call is used to indicate that
1008     // we have generated an inline version of the keyed load.  In this
1009     // case, we know that we are not generating a test instruction next.
1010 
1011     // Push the nth argument.
1012     __ push(eax);
1013 
1014     // Update the index on the stack and in register eax.
1015     __ mov(ecx, Operand(ebp, kIndexOffset));
1016     __ add(ecx, Immediate(1 << kSmiTagSize));
1017     __ mov(Operand(ebp, kIndexOffset), ecx);
1018 
1019     __ bind(&entry);
1020     __ cmp(ecx, Operand(ebp, kLimitOffset));
1021     __ j(not_equal, &loop);
1022 
1023     // Call the function.
1024     Label call_proxy;
1025     __ mov(eax, ecx);
1026     ParameterCount actual(eax);
1027     __ SmiUntag(eax);
1028     __ mov(edi, Operand(ebp, kFunctionOffset));
1029     __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
1030     __ j(not_equal, &call_proxy);
1031     __ InvokeFunction(edi, actual, CALL_FUNCTION, NullCallWrapper());
1032 
1033     frame_scope.GenerateLeaveFrame();
1034     __ ret(3 * kPointerSize);  // remove this, receiver, and arguments
1035 
1036     // Call the function proxy.
1037     __ bind(&call_proxy);
1038     __ push(edi);  // add function proxy as last argument
1039     __ inc(eax);
1040     __ Move(ebx, Immediate(0));
1041     __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
1042     __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1043             RelocInfo::CODE_TARGET);
1044 
1045     // Leave internal frame.
1046   }
1047   __ ret(3 * kPointerSize);  // remove this, receiver, and arguments
1048 }
1049 
1050 
Generate_InternalArrayCode(MacroAssembler * masm)1051 void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
1052   // ----------- S t a t e -------------
1053   //  -- eax : argc
1054   //  -- esp[0] : return address
1055   //  -- esp[4] : last argument
1056   // -----------------------------------
1057   Label generic_array_code;
1058 
1059   // Get the InternalArray function.
1060   __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi);
1061 
1062   if (FLAG_debug_code) {
1063     // Initial map for the builtin InternalArray function should be a map.
1064     __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1065     // Will both indicate a NULL and a Smi.
1066     __ test(ebx, Immediate(kSmiTagMask));
1067     __ Assert(not_zero, kUnexpectedInitialMapForInternalArrayFunction);
1068     __ CmpObjectType(ebx, MAP_TYPE, ecx);
1069     __ Assert(equal, kUnexpectedInitialMapForInternalArrayFunction);
1070   }
1071 
1072   // Run the native code for the InternalArray function called as a normal
1073   // function.
1074   // tail call a stub
1075   InternalArrayConstructorStub stub(masm->isolate());
1076   __ TailCallStub(&stub);
1077 }
1078 
1079 
Generate_ArrayCode(MacroAssembler * masm)1080 void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1081   // ----------- S t a t e -------------
1082   //  -- eax : argc
1083   //  -- esp[0] : return address
1084   //  -- esp[4] : last argument
1085   // -----------------------------------
1086   Label generic_array_code;
1087 
1088   // Get the Array function.
1089   __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
1090 
1091   if (FLAG_debug_code) {
1092     // Initial map for the builtin Array function should be a map.
1093     __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1094     // Will both indicate a NULL and a Smi.
1095     __ test(ebx, Immediate(kSmiTagMask));
1096     __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
1097     __ CmpObjectType(ebx, MAP_TYPE, ecx);
1098     __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
1099   }
1100 
1101   // Run the native code for the Array function called as a normal function.
1102   // tail call a stub
1103   __ mov(ebx, masm->isolate()->factory()->undefined_value());
1104   ArrayConstructorStub stub(masm->isolate());
1105   __ TailCallStub(&stub);
1106 }
1107 
1108 
Generate_StringConstructCode(MacroAssembler * masm)1109 void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
1110   // ----------- S t a t e -------------
1111   //  -- eax                 : number of arguments
1112   //  -- edi                 : constructor function
1113   //  -- esp[0]              : return address
1114   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1115   //  -- esp[(argc + 1) * 4] : receiver
1116   // -----------------------------------
1117   Counters* counters = masm->isolate()->counters();
1118   __ IncrementCounter(counters->string_ctor_calls(), 1);
1119 
1120   if (FLAG_debug_code) {
1121     __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx);
1122     __ cmp(edi, ecx);
1123     __ Assert(equal, kUnexpectedStringFunction);
1124   }
1125 
1126   // Load the first argument into eax and get rid of the rest
1127   // (including the receiver).
1128   Label no_arguments;
1129   __ test(eax, eax);
1130   __ j(zero, &no_arguments);
1131   __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1132   __ pop(ecx);
1133   __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1134   __ push(ecx);
1135   __ mov(eax, ebx);
1136 
1137   // Lookup the argument in the number to string cache.
1138   Label not_cached, argument_is_string;
1139   __ LookupNumberStringCache(eax,  // Input.
1140                              ebx,  // Result.
1141                              ecx,  // Scratch 1.
1142                              edx,  // Scratch 2.
1143                              &not_cached);
1144   __ IncrementCounter(counters->string_ctor_cached_number(), 1);
1145   __ bind(&argument_is_string);
1146   // ----------- S t a t e -------------
1147   //  -- ebx    : argument converted to string
1148   //  -- edi    : constructor function
1149   //  -- esp[0] : return address
1150   // -----------------------------------
1151 
1152   // Allocate a JSValue and put the tagged pointer into eax.
1153   Label gc_required;
1154   __ Allocate(JSValue::kSize,
1155               eax,  // Result.
1156               ecx,  // New allocation top (we ignore it).
1157               no_reg,
1158               &gc_required,
1159               TAG_OBJECT);
1160 
1161   // Set the map.
1162   __ LoadGlobalFunctionInitialMap(edi, ecx);
1163   if (FLAG_debug_code) {
1164     __ cmpb(FieldOperand(ecx, Map::kInstanceSizeOffset),
1165             JSValue::kSize >> kPointerSizeLog2);
1166     __ Assert(equal, kUnexpectedStringWrapperInstanceSize);
1167     __ cmpb(FieldOperand(ecx, Map::kUnusedPropertyFieldsOffset), 0);
1168     __ Assert(equal, kUnexpectedUnusedPropertiesOfStringWrapper);
1169   }
1170   __ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx);
1171 
1172   // Set properties and elements.
1173   Factory* factory = masm->isolate()->factory();
1174   __ Move(ecx, Immediate(factory->empty_fixed_array()));
1175   __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx);
1176   __ mov(FieldOperand(eax, JSObject::kElementsOffset), ecx);
1177 
1178   // Set the value.
1179   __ mov(FieldOperand(eax, JSValue::kValueOffset), ebx);
1180 
1181   // Ensure the object is fully initialized.
1182   STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
1183 
1184   // We're done. Return.
1185   __ ret(0);
1186 
1187   // The argument was not found in the number to string cache. Check
1188   // if it's a string already before calling the conversion builtin.
1189   Label convert_argument;
1190   __ bind(&not_cached);
1191   STATIC_ASSERT(kSmiTag == 0);
1192   __ JumpIfSmi(eax, &convert_argument);
1193   Condition is_string = masm->IsObjectStringType(eax, ebx, ecx);
1194   __ j(NegateCondition(is_string), &convert_argument);
1195   __ mov(ebx, eax);
1196   __ IncrementCounter(counters->string_ctor_string_value(), 1);
1197   __ jmp(&argument_is_string);
1198 
1199   // Invoke the conversion builtin and put the result into ebx.
1200   __ bind(&convert_argument);
1201   __ IncrementCounter(counters->string_ctor_conversions(), 1);
1202   {
1203     FrameScope scope(masm, StackFrame::INTERNAL);
1204     __ push(edi);  // Preserve the function.
1205     __ push(eax);
1206     __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
1207     __ pop(edi);
1208   }
1209   __ mov(ebx, eax);
1210   __ jmp(&argument_is_string);
1211 
1212   // Load the empty string into ebx, remove the receiver from the
1213   // stack, and jump back to the case where the argument is a string.
1214   __ bind(&no_arguments);
1215   __ Move(ebx, Immediate(factory->empty_string()));
1216   __ pop(ecx);
1217   __ lea(esp, Operand(esp, kPointerSize));
1218   __ push(ecx);
1219   __ jmp(&argument_is_string);
1220 
1221   // At this point the argument is already a string. Call runtime to
1222   // create a string wrapper.
1223   __ bind(&gc_required);
1224   __ IncrementCounter(counters->string_ctor_gc_required(), 1);
1225   {
1226     FrameScope scope(masm, StackFrame::INTERNAL);
1227     __ push(ebx);
1228     __ CallRuntime(Runtime::kNewStringWrapper, 1);
1229   }
1230   __ ret(0);
1231 }
1232 
1233 
ArgumentsAdaptorStackCheck(MacroAssembler * masm,Label * stack_overflow)1234 static void ArgumentsAdaptorStackCheck(MacroAssembler* masm,
1235                                        Label* stack_overflow) {
1236   // ----------- S t a t e -------------
1237   //  -- eax : actual number of arguments
1238   //  -- ebx : expected number of arguments
1239   //  -- edi : function (passed through to callee)
1240   // -----------------------------------
1241   // Check the stack for overflow. We are not trying to catch
1242   // interruptions (e.g. debug break and preemption) here, so the "real stack
1243   // limit" is checked.
1244   ExternalReference real_stack_limit =
1245       ExternalReference::address_of_real_stack_limit(masm->isolate());
1246   __ mov(edx, Operand::StaticVariable(real_stack_limit));
1247   // Make ecx the space we have left. The stack might already be overflowed
1248   // here which will cause ecx to become negative.
1249   __ mov(ecx, esp);
1250   __ sub(ecx, edx);
1251   // Make edx the space we need for the array when it is unrolled onto the
1252   // stack.
1253   __ mov(edx, ebx);
1254   __ shl(edx, kPointerSizeLog2);
1255   // Check if the arguments will overflow the stack.
1256   __ cmp(ecx, edx);
1257   __ j(less_equal, stack_overflow);  // Signed comparison.
1258 }
1259 
1260 
EnterArgumentsAdaptorFrame(MacroAssembler * masm)1261 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1262   __ push(ebp);
1263   __ mov(ebp, esp);
1264 
1265   // Store the arguments adaptor context sentinel.
1266   __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1267 
1268   // Push the function on the stack.
1269   __ push(edi);
1270 
1271   // Preserve the number of arguments on the stack. Must preserve eax,
1272   // ebx and ecx because these registers are used when copying the
1273   // arguments and the receiver.
1274   STATIC_ASSERT(kSmiTagSize == 1);
1275   __ lea(edi, Operand(eax, eax, times_1, kSmiTag));
1276   __ push(edi);
1277 }
1278 
1279 
LeaveArgumentsAdaptorFrame(MacroAssembler * masm)1280 static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1281   // Retrieve the number of arguments from the stack.
1282   __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1283 
1284   // Leave the frame.
1285   __ leave();
1286 
1287   // Remove caller arguments from the stack.
1288   STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
1289   __ pop(ecx);
1290   __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize));  // 1 ~ receiver
1291   __ push(ecx);
1292 }
1293 
1294 
Generate_ArgumentsAdaptorTrampoline(MacroAssembler * masm)1295 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1296   // ----------- S t a t e -------------
1297   //  -- eax : actual number of arguments
1298   //  -- ebx : expected number of arguments
1299   //  -- edi : function (passed through to callee)
1300   // -----------------------------------
1301 
1302   Label invoke, dont_adapt_arguments;
1303   __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
1304 
1305   Label stack_overflow;
1306   ArgumentsAdaptorStackCheck(masm, &stack_overflow);
1307 
1308   Label enough, too_few;
1309   __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
1310   __ cmp(eax, ebx);
1311   __ j(less, &too_few);
1312   __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1313   __ j(equal, &dont_adapt_arguments);
1314 
1315   {  // Enough parameters: Actual >= expected.
1316     __ bind(&enough);
1317     EnterArgumentsAdaptorFrame(masm);
1318 
1319     // Copy receiver and all expected arguments.
1320     const int offset = StandardFrameConstants::kCallerSPOffset;
1321     __ lea(eax, Operand(ebp, eax, times_4, offset));
1322     __ mov(edi, -1);  // account for receiver
1323 
1324     Label copy;
1325     __ bind(&copy);
1326     __ inc(edi);
1327     __ push(Operand(eax, 0));
1328     __ sub(eax, Immediate(kPointerSize));
1329     __ cmp(edi, ebx);
1330     __ j(less, &copy);
1331     __ jmp(&invoke);
1332   }
1333 
1334   {  // Too few parameters: Actual < expected.
1335     __ bind(&too_few);
1336     EnterArgumentsAdaptorFrame(masm);
1337 
1338     // Copy receiver and all actual arguments.
1339     const int offset = StandardFrameConstants::kCallerSPOffset;
1340     __ lea(edi, Operand(ebp, eax, times_4, offset));
1341     // ebx = expected - actual.
1342     __ sub(ebx, eax);
1343     // eax = -actual - 1
1344     __ neg(eax);
1345     __ sub(eax, Immediate(1));
1346 
1347     Label copy;
1348     __ bind(&copy);
1349     __ inc(eax);
1350     __ push(Operand(edi, 0));
1351     __ sub(edi, Immediate(kPointerSize));
1352     __ test(eax, eax);
1353     __ j(not_zero, &copy);
1354 
1355     // Fill remaining expected arguments with undefined values.
1356     Label fill;
1357     __ bind(&fill);
1358     __ inc(eax);
1359     __ push(Immediate(masm->isolate()->factory()->undefined_value()));
1360     __ cmp(eax, ebx);
1361     __ j(less, &fill);
1362   }
1363 
1364   // Call the entry point.
1365   __ bind(&invoke);
1366   // Restore function pointer.
1367   __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1368   __ call(edx);
1369 
1370   // Store offset of return address for deoptimizer.
1371   masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
1372 
1373   // Leave frame and return.
1374   LeaveArgumentsAdaptorFrame(masm);
1375   __ ret(0);
1376 
1377   // -------------------------------------------
1378   // Dont adapt arguments.
1379   // -------------------------------------------
1380   __ bind(&dont_adapt_arguments);
1381   __ jmp(edx);
1382 
1383   __ bind(&stack_overflow);
1384   {
1385     FrameScope frame(masm, StackFrame::MANUAL);
1386     EnterArgumentsAdaptorFrame(masm);
1387     __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
1388     __ int3();
1389   }
1390 }
1391 
1392 
Generate_OnStackReplacement(MacroAssembler * masm)1393 void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
1394   // Lookup the function in the JavaScript frame.
1395   __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1396   {
1397     FrameScope scope(masm, StackFrame::INTERNAL);
1398     // Pass function as argument.
1399     __ push(eax);
1400     __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
1401   }
1402 
1403   Label skip;
1404   // If the code object is null, just return to the unoptimized code.
1405   __ cmp(eax, Immediate(0));
1406   __ j(not_equal, &skip, Label::kNear);
1407   __ ret(0);
1408 
1409   __ bind(&skip);
1410 
1411   // Load deoptimization data from the code object.
1412   __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag));
1413 
1414   // Load the OSR entrypoint offset from the deoptimization data.
1415   __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt(
1416       DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag));
1417   __ SmiUntag(ebx);
1418 
1419   // Compute the target address = code_obj + header_size + osr_offset
1420   __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag));
1421 
1422   // Overwrite the return address on the stack.
1423   __ mov(Operand(esp, 0), eax);
1424 
1425   // And "return" to the OSR entry point of the function.
1426   __ ret(0);
1427 }
1428 
1429 
Generate_OsrAfterStackCheck(MacroAssembler * masm)1430 void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
1431   // We check the stack limit as indicator that recompilation might be done.
1432   Label ok;
1433   ExternalReference stack_limit =
1434       ExternalReference::address_of_stack_limit(masm->isolate());
1435   __ cmp(esp, Operand::StaticVariable(stack_limit));
1436   __ j(above_equal, &ok, Label::kNear);
1437   {
1438     FrameScope scope(masm, StackFrame::INTERNAL);
1439     __ CallRuntime(Runtime::kHiddenStackGuard, 0);
1440   }
1441   __ jmp(masm->isolate()->builtins()->OnStackReplacement(),
1442          RelocInfo::CODE_TARGET);
1443 
1444   __ bind(&ok);
1445   __ ret(0);
1446 }
1447 
1448 #undef __
1449 }
1450 }  // namespace v8::internal
1451 
1452 #endif  // V8_TARGET_ARCH_IA32
1453