• Home
  • History
  • Annotate
  • 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_X87
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  
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      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  
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::kTryInstallOptimizedCode);
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    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
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::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
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::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.
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_CompileLazy(MacroAssembler * masm)553  void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
554    CallRuntimePassFunction(masm, Runtime::kCompileLazy);
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::kCompileOptimized, 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::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  
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::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;
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_proxy, 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_proxy);
791      __ cmp(ebx, factory->undefined_value());
792      __ j(equal, &use_global_proxy);
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_proxy);
818      __ mov(ebx,
819             Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
820      __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalProxyOffset));
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_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.
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_proxy);
975      __ cmp(ebx, factory->undefined_value());
976      __ j(equal, &use_global_proxy);
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_proxy);
988      __ mov(ebx,
989             Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
990      __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalProxyOffset));
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) {
1007        __ mov(VectorLoadICDescriptor::SlotRegister(),
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(),
1049              RelocInfo::CODE_TARGET);
1050  
1051      // Leave internal frame.
1052    }
1053    __ ret(3 * kPointerSize);  // remove this, receiver, and arguments
1054  }
1055  
1056  
Generate_InternalArrayCode(MacroAssembler * masm)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.
1070      __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
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  
Generate_ArrayCode(MacroAssembler * masm)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.
1099      __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
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  
Generate_StringConstructCode(MacroAssembler * masm)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) {
1170      __ cmpb(FieldOperand(ecx, Map::kInstanceSizeOffset),
1171              JSValue::kSize >> kPointerSizeLog2);
1172      __ Assert(equal, kUnexpectedStringWrapperInstanceSize);
1173      __ cmpb(FieldOperand(ecx, Map::kUnusedPropertyFieldsOffset), 0);
1174      __ Assert(equal, kUnexpectedUnusedPropertiesOfStringWrapper);
1175    }
1176    __ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx);
1177  
1178    // Set properties and elements.
1179    Factory* factory = masm->isolate()->factory();
1180    __ Move(ecx, Immediate(factory->empty_fixed_array()));
1181    __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx);
1182    __ mov(FieldOperand(eax, JSObject::kElementsOffset), ecx);
1183  
1184    // Set the value.
1185    __ mov(FieldOperand(eax, JSValue::kValueOffset), ebx);
1186  
1187    // Ensure the object is fully initialized.
1188    STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
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  
ArgumentsAdaptorStackCheck(MacroAssembler * masm,Label * stack_overflow)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  
EnterArgumentsAdaptorFrame(MacroAssembler * masm)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  
LeaveArgumentsAdaptorFrame(MacroAssembler * masm)1286  static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1287    // Retrieve the number of arguments from the stack.
1288    __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
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  
Generate_ArgumentsAdaptorTrampoline(MacroAssembler * masm)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;
1315    __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
1316    __ cmp(eax, ebx);
1317    __ j(less, &too_few);
1318    __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
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.
1373    __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
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  
Generate_OnStackReplacement(MacroAssembler * masm)1399  void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
1400    // Lookup the function in the JavaScript frame.
1401    __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
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.
1418    __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag));
1419  
1420    // Load the OSR entrypoint offset from the deoptimization data.
1421    __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt(
1422        DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag));
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  
Generate_OsrAfterStackCheck(MacroAssembler * masm)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(),
1448           RelocInfo::CODE_TARGET);
1449  
1450    __ bind(&ok);
1451    __ ret(0);
1452  }
1453  
1454  #undef __
1455  }
1456  }  // namespace v8::internal
1457  
1458  #endif  // V8_TARGET_ARCH_X87
1459