[runtime] Store constructor function index on primitive maps.
[platform/upstream/v8.git] / src / ia32 / builtins-ia32.cc
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/v8.h"
6
7 #if V8_TARGET_ARCH_IA32
8
9 #include "src/code-factory.h"
10 #include "src/codegen.h"
11 #include "src/deoptimizer.h"
12 #include "src/full-codegen/full-codegen.h"
13
14 namespace v8 {
15 namespace internal {
16
17
18 #define __ ACCESS_MASM(masm)
19
20
21 void Builtins::Generate_Adaptor(MacroAssembler* masm,
22                                 CFunctionId id,
23                                 BuiltinExtraArguments extra_args) {
24   // ----------- S t a t e -------------
25   //  -- eax                : number of arguments excluding receiver
26   //  -- edi                : called function (only guaranteed when
27   //                          extra_args requires it)
28   //  -- esi                : context
29   //  -- esp[0]             : return address
30   //  -- esp[4]             : last argument
31   //  -- ...
32   //  -- esp[4 * argc]      : first argument (argc == eax)
33   //  -- esp[4 * (argc +1)] : receiver
34   // -----------------------------------
35
36   // Insert extra arguments.
37   int num_extra_args = 0;
38   if (extra_args == NEEDS_CALLED_FUNCTION) {
39     num_extra_args = 1;
40     Register scratch = ebx;
41     __ pop(scratch);  // Save return address.
42     __ push(edi);
43     __ push(scratch);  // Restore return address.
44   } else {
45     DCHECK(extra_args == NO_EXTRA_ARGUMENTS);
46   }
47
48   // JumpToExternalReference expects eax to contain the number of arguments
49   // including the receiver and the extra arguments.
50   __ add(eax, Immediate(num_extra_args + 1));
51   __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
52 }
53
54
55 static void CallRuntimePassFunction(
56     MacroAssembler* masm, Runtime::FunctionId function_id) {
57   FrameScope scope(masm, StackFrame::INTERNAL);
58   // Push a copy of the function.
59   __ push(edi);
60   // Function is also the parameter to the runtime call.
61   __ push(edi);
62
63   __ CallRuntime(function_id, 1);
64   // Restore receiver.
65   __ pop(edi);
66 }
67
68
69 static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
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
77 static void GenerateTailCallToReturnedCode(MacroAssembler* masm) {
78   __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
79   __ jmp(eax);
80 }
81
82
83 void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
84   // Checking whether the queued function is ready for install is optional,
85   // since we come across interrupts and stack checks elsewhere.  However,
86   // not checking may delay installing ready functions, and always checking
87   // would be quite expensive.  A good compromise is to first check against
88   // stack limit as a cue for an interrupt signal.
89   Label ok;
90   ExternalReference stack_limit =
91       ExternalReference::address_of_stack_limit(masm->isolate());
92   __ cmp(esp, Operand::StaticVariable(stack_limit));
93   __ j(above_equal, &ok, Label::kNear);
94
95   CallRuntimePassFunction(masm, Runtime::kTryInstallOptimizedCode);
96   GenerateTailCallToReturnedCode(masm);
97
98   __ bind(&ok);
99   GenerateTailCallToSharedCode(masm);
100 }
101
102
103 static void Generate_JSConstructStubHelper(MacroAssembler* masm,
104                                            bool is_api_function,
105                                            bool create_memento) {
106   // ----------- S t a t e -------------
107   //  -- eax: number of arguments
108   //  -- edi: constructor function
109   //  -- ebx: allocation site or undefined
110   //  -- edx: original constructor
111   // -----------------------------------
112
113   // Should never create mementos for api functions.
114   DCHECK(!is_api_function || !create_memento);
115
116   // Enter a construct frame.
117   {
118     FrameScope scope(masm, StackFrame::CONSTRUCT);
119
120     // Preserve the incoming parameters on the stack.
121     __ AssertUndefinedOrAllocationSite(ebx);
122     __ push(ebx);
123     __ SmiTag(eax);
124     __ push(eax);
125     __ push(edi);
126     __ push(edx);
127
128     // Try to allocate the object without transitioning into C code. If any of
129     // the preconditions is not met, the code bails out to the runtime call.
130     Label rt_call, allocated;
131     if (FLAG_inline_new) {
132       ExternalReference debug_step_in_fp =
133           ExternalReference::debug_step_in_fp_address(masm->isolate());
134       __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
135       __ j(not_equal, &rt_call);
136
137       // Fall back to runtime if the original constructor and function differ.
138       __ cmp(edx, edi);
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(Map::Counter::kShift + Map::Counter::kSize == 32);
164         // Check if slack tracking is enabled.
165         __ mov(esi, FieldOperand(eax, Map::kBitField3Offset));
166         __ shr(esi, Map::Counter::kShift);
167         __ cmp(esi, Map::kSlackTrackingCounterEnd);
168         __ j(less, &allocate);
169         // Decrease generous allocation count.
170         __ sub(FieldOperand(eax, Map::kBitField3Offset),
171                Immediate(1 << Map::Counter::kShift));
172
173         __ cmp(esi, Map::kSlackTrackingCounterEnd);
174         __ j(not_equal, &allocate);
175
176         __ push(eax);
177         __ push(edx);
178         __ push(edi);
179
180         __ push(edi);  // constructor
181         __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
182
183         __ pop(edi);
184         __ pop(edx);
185         __ pop(eax);
186         __ mov(esi, Map::kSlackTrackingCounterEnd - 1);
187
188         __ bind(&allocate);
189       }
190
191       // Now allocate the JSObject on the heap.
192       // edi: constructor
193       // eax: initial map
194       __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset));
195       __ shl(edi, kPointerSizeLog2);
196       if (create_memento) {
197         __ add(edi, Immediate(AllocationMemento::kSize));
198       }
199
200       __ Allocate(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS);
201
202       Factory* factory = masm->isolate()->factory();
203
204       // Allocated the JSObject, now initialize the fields.
205       // eax: initial map
206       // ebx: JSObject
207       // edi: start of next object (including memento if create_memento)
208       __ mov(Operand(ebx, JSObject::kMapOffset), eax);
209       __ mov(ecx, factory->empty_fixed_array());
210       __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
211       __ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
212       // Set extra fields in the newly allocated object.
213       // eax: initial map
214       // ebx: JSObject
215       // edi: start of next object (including memento if create_memento)
216       // esi: slack tracking counter (non-API function case)
217       __ mov(edx, factory->undefined_value());
218       __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
219       if (!is_api_function) {
220         Label no_inobject_slack_tracking;
221
222         // Check if slack tracking is enabled.
223         __ cmp(esi, Map::kSlackTrackingCounterEnd);
224         __ j(less, &no_inobject_slack_tracking);
225
226         // Allocate object with a slack.
227         __ movzx_b(
228             esi,
229             FieldOperand(
230                 eax, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset));
231         __ movzx_b(eax, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
232         __ sub(esi, eax);
233         __ lea(esi,
234                Operand(ebx, esi, times_pointer_size, JSObject::kHeaderSize));
235         // esi: offset of first field after pre-allocated fields
236         if (FLAG_debug_code) {
237           __ cmp(esi, edi);
238           __ Assert(less_equal,
239                     kUnexpectedNumberOfPreAllocatedPropertyFields);
240         }
241         __ InitializeFieldsWithFiller(ecx, esi, edx);
242         __ mov(edx, factory->one_pointer_filler_map());
243         // Fill the remaining fields with one pointer filler map.
244
245         __ bind(&no_inobject_slack_tracking);
246       }
247
248       if (create_memento) {
249         __ lea(esi, Operand(edi, -AllocationMemento::kSize));
250         __ InitializeFieldsWithFiller(ecx, esi, edx);
251
252         // Fill in memento fields if necessary.
253         // esi: points to the allocated but uninitialized memento.
254         __ mov(Operand(esi, AllocationMemento::kMapOffset),
255                factory->allocation_memento_map());
256         // Get the cell or undefined.
257         __ mov(edx, Operand(esp, 3 * kPointerSize));
258         __ AssertUndefinedOrAllocationSite(edx);
259         __ mov(Operand(esi, AllocationMemento::kAllocationSiteOffset),
260                edx);
261       } else {
262         __ InitializeFieldsWithFiller(ecx, edi, edx);
263       }
264
265       // Add the object tag to make the JSObject real, so that we can continue
266       // and jump into the continuation code at any time from now on.
267       // ebx: JSObject (untagged)
268       __ or_(ebx, Immediate(kHeapObjectTag));
269
270       // Continue with JSObject being successfully allocated
271       // ebx: JSObject (tagged)
272       __ jmp(&allocated);
273     }
274
275     // Allocate the new receiver object using the runtime call.
276     // edx: original constructor
277     __ bind(&rt_call);
278     int offset = kPointerSize;
279     if (create_memento) {
280       // Get the cell or allocation site.
281       __ mov(edi, Operand(esp, kPointerSize * 3));
282       __ push(edi);  // argument 1: allocation site
283       offset += kPointerSize;
284     }
285
286     // Must restore esi (context) and edi (constructor) before calling
287     // runtime.
288     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
289     __ mov(edi, Operand(esp, offset));
290     __ push(edi);  // argument 2/1: constructor function
291     __ push(edx);  // argument 3/2: original constructor
292     if (create_memento) {
293       __ CallRuntime(Runtime::kNewObjectWithAllocationSite, 3);
294     } else {
295       __ CallRuntime(Runtime::kNewObject, 2);
296     }
297     __ mov(ebx, eax);  // store result in ebx
298
299     // Runtime_NewObjectWithAllocationSite increments allocation count.
300     // Skip the increment.
301     Label count_incremented;
302     if (create_memento) {
303       __ jmp(&count_incremented);
304     }
305
306     // New object allocated.
307     // ebx: newly allocated object
308     __ bind(&allocated);
309
310     if (create_memento) {
311       __ mov(ecx, Operand(esp, 3 * kPointerSize));
312       __ cmp(ecx, masm->isolate()->factory()->undefined_value());
313       __ j(equal, &count_incremented);
314       // ecx is an AllocationSite. We are creating a memento from it, so we
315       // need to increment the memento create count.
316       __ add(FieldOperand(ecx, AllocationSite::kPretenureCreateCountOffset),
317              Immediate(Smi::FromInt(1)));
318       __ bind(&count_incremented);
319     }
320
321     // Restore the parameters.
322     __ pop(edx);  // new.target
323     __ pop(edi);  // Constructor function.
324
325     // Retrieve smi-tagged arguments count from the stack.
326     __ mov(eax, Operand(esp, 0));
327     __ SmiUntag(eax);
328
329     // Push new.target onto the construct frame. This is stored just below the
330     // receiver on the stack.
331     __ push(edx);
332
333     // Push the allocated receiver to the stack. We need two copies
334     // because we may have to return the original one and the calling
335     // conventions dictate that the called function pops the receiver.
336     __ push(ebx);
337     __ push(ebx);
338
339     // Set up pointer to last argument.
340     __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
341
342     // Copy arguments and receiver to the expression stack.
343     Label loop, entry;
344     __ mov(ecx, eax);
345     __ jmp(&entry);
346     __ bind(&loop);
347     __ push(Operand(ebx, ecx, times_4, 0));
348     __ bind(&entry);
349     __ dec(ecx);
350     __ j(greater_equal, &loop);
351
352     // Call the function.
353     if (is_api_function) {
354       __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
355       Handle<Code> code =
356           masm->isolate()->builtins()->HandleApiCallConstruct();
357       __ call(code, RelocInfo::CODE_TARGET);
358     } else {
359       ParameterCount actual(eax);
360       __ InvokeFunction(edi, actual, CALL_FUNCTION,
361                         NullCallWrapper());
362     }
363
364     // Store offset of return address for deoptimizer.
365     if (!is_api_function) {
366       masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
367     }
368
369     // Restore context from the frame.
370     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
371
372     // If the result is an object (in the ECMA sense), we should get rid
373     // of the receiver and use the result; see ECMA-262 section 13.2.2-7
374     // on page 74.
375     Label use_receiver, exit;
376
377     // If the result is a smi, it is *not* an object in the ECMA sense.
378     __ JumpIfSmi(eax, &use_receiver);
379
380     // If the type of the result (stored in its map) is less than
381     // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
382     __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
383     __ j(above_equal, &exit);
384
385     // Throw away the result of the constructor invocation and use the
386     // on-stack receiver as the result.
387     __ bind(&use_receiver);
388     __ mov(eax, Operand(esp, 0));
389
390     // Restore the arguments count and leave the construct frame. The arguments
391     // count is stored below the reciever and the new.target.
392     __ bind(&exit);
393     __ mov(ebx, Operand(esp, 2 * kPointerSize));
394
395     // Leave construct frame.
396   }
397
398   // Remove caller arguments from the stack and return.
399   STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
400   __ pop(ecx);
401   __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize));  // 1 ~ receiver
402   __ push(ecx);
403   __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
404   __ ret(0);
405 }
406
407
408 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
409   Generate_JSConstructStubHelper(masm, false, FLAG_pretenuring_call_new);
410 }
411
412
413 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
414   Generate_JSConstructStubHelper(masm, true, false);
415 }
416
417
418 void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
419   // ----------- S t a t e -------------
420   //  -- eax: number of arguments
421   //  -- edi: constructor function
422   //  -- ebx: allocation site or undefined
423   //  -- edx: original constructor
424   // -----------------------------------
425
426   {
427     FrameScope frame_scope(masm, StackFrame::CONSTRUCT);
428
429     // Preserve allocation site.
430     __ AssertUndefinedOrAllocationSite(ebx);
431     __ push(ebx);
432
433     // Preserve actual arguments count.
434     __ SmiTag(eax);
435     __ push(eax);
436     __ SmiUntag(eax);
437
438     // Push new.target.
439     __ push(edx);
440
441     // receiver is the hole.
442     __ push(Immediate(masm->isolate()->factory()->the_hole_value()));
443
444     // Set up pointer to last argument.
445     __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
446
447     // Copy arguments and receiver to the expression stack.
448     Label loop, entry;
449     __ mov(ecx, eax);
450     __ jmp(&entry);
451     __ bind(&loop);
452     __ push(Operand(ebx, ecx, times_4, 0));
453     __ bind(&entry);
454     __ dec(ecx);
455     __ j(greater_equal, &loop);
456
457     // Handle step in.
458     Label skip_step_in;
459     ExternalReference debug_step_in_fp =
460         ExternalReference::debug_step_in_fp_address(masm->isolate());
461     __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
462     __ j(equal, &skip_step_in);
463
464     __ push(eax);
465     __ push(edi);
466     __ push(edi);
467     __ CallRuntime(Runtime::kHandleStepInForDerivedConstructors, 1);
468     __ pop(edi);
469     __ pop(eax);
470
471     __ bind(&skip_step_in);
472
473     // Invoke function.
474     ParameterCount actual(eax);
475     __ InvokeFunction(edi, actual, CALL_FUNCTION, NullCallWrapper());
476
477     // Restore context from the frame.
478     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
479
480     // Get arguments count, skipping over new.target.
481     __ mov(ebx, Operand(esp, kPointerSize));
482   }
483
484   __ pop(ecx);  // Return address.
485   __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize));
486   __ push(ecx);
487   __ ret(0);
488 }
489
490
491 enum IsTagged { kEaxIsSmiTagged, kEaxIsUntaggedInt };
492
493
494 // Clobbers ecx, edx, edi; preserves all other registers.
495 static void Generate_CheckStackOverflow(MacroAssembler* masm,
496                                         const int calleeOffset,
497                                         IsTagged eax_is_tagged) {
498   // eax   : the number of items to be pushed to the stack
499   //
500   // Check the stack for overflow. We are not trying to catch
501   // interruptions (e.g. debug break and preemption) here, so the "real stack
502   // limit" is checked.
503   Label okay;
504   ExternalReference real_stack_limit =
505       ExternalReference::address_of_real_stack_limit(masm->isolate());
506   __ mov(edi, Operand::StaticVariable(real_stack_limit));
507   // Make ecx the space we have left. The stack might already be overflowed
508   // here which will cause ecx to become negative.
509   __ mov(ecx, esp);
510   __ sub(ecx, edi);
511   // Make edx the space we need for the array when it is unrolled onto the
512   // stack.
513   __ mov(edx, eax);
514   int smi_tag = eax_is_tagged == kEaxIsSmiTagged ? kSmiTagSize : 0;
515   __ shl(edx, kPointerSizeLog2 - smi_tag);
516   // Check if the arguments will overflow the stack.
517   __ cmp(ecx, edx);
518   __ j(greater, &okay);  // Signed comparison.
519
520   // Out of stack space.
521   __ push(Operand(ebp, calleeOffset));  // push this
522   if (eax_is_tagged == kEaxIsUntaggedInt) {
523     __ SmiTag(eax);
524   }
525   __ push(eax);
526   __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
527
528   __ bind(&okay);
529 }
530
531
532 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
533                                              bool is_construct) {
534   ProfileEntryHookStub::MaybeCallEntryHook(masm);
535
536   // Clear the context before we push it when entering the internal frame.
537   __ Move(esi, Immediate(0));
538
539   {
540     FrameScope scope(masm, StackFrame::INTERNAL);
541
542     // Load the previous frame pointer (ebx) to access C arguments
543     __ mov(ebx, Operand(ebp, 0));
544
545     // Get the function from the frame and setup the context.
546     __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
547     __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset));
548
549     // Push the function and the receiver onto the stack.
550     __ push(ecx);
551     __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
552
553     // Load the number of arguments and setup pointer to the arguments.
554     __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
555     __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
556
557     // Check if we have enough stack space to push all arguments.
558     // The function is the first thing that was pushed above after entering
559     // the internal frame.
560     const int kFunctionOffset =
561         InternalFrameConstants::kCodeOffset - kPointerSize;
562     // Expects argument count in eax. Clobbers ecx, edx, edi.
563     Generate_CheckStackOverflow(masm, kFunctionOffset, kEaxIsUntaggedInt);
564
565     // Copy arguments to the stack in a loop.
566     Label loop, entry;
567     __ Move(ecx, Immediate(0));
568     __ jmp(&entry);
569     __ bind(&loop);
570     __ mov(edx, Operand(ebx, ecx, times_4, 0));  // push parameter from argv
571     __ push(Operand(edx, 0));  // dereference handle
572     __ inc(ecx);
573     __ bind(&entry);
574     __ cmp(ecx, eax);
575     __ j(not_equal, &loop);
576
577     // Get the function from the stack and call it.
578     // kPointerSize for the receiver.
579     __ mov(edi, Operand(esp, eax, times_4, kPointerSize));
580
581     // Invoke the code.
582     if (is_construct) {
583       // No type feedback cell is available
584       __ mov(ebx, masm->isolate()->factory()->undefined_value());
585       CallConstructStub stub(masm->isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
586       __ CallStub(&stub);
587     } else {
588       ParameterCount actual(eax);
589       __ InvokeFunction(edi, actual, CALL_FUNCTION,
590                         NullCallWrapper());
591     }
592
593     // Exit the internal frame. Notice that this also removes the empty.
594     // context and the function left on the stack by the code
595     // invocation.
596   }
597   __ ret(kPointerSize);  // Remove receiver.
598 }
599
600
601 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
602   Generate_JSEntryTrampolineHelper(masm, false);
603 }
604
605
606 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
607   Generate_JSEntryTrampolineHelper(masm, true);
608 }
609
610
611 // Generate code for entering a JS function with the interpreter.
612 // On entry to the function the receiver and arguments have been pushed on the
613 // stack left to right.  The actual argument count matches the formal parameter
614 // count expected by the function.
615 //
616 // The live registers are:
617 //   o edi: the JS function object being called
618 //   o esi: our context
619 //   o ebp: the caller's frame pointer
620 //   o esp: stack pointer (pointing to return address)
621 //
622 // The function builds a JS frame.  Please see JavaScriptFrameConstants in
623 // frames-ia32.h for its layout.
624 // TODO(rmcilroy): We will need to include the current bytecode pointer in the
625 // frame.
626 void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
627   // Open a frame scope to indicate that there is a frame on the stack.  The
628   // MANUAL indicates that the scope shouldn't actually generate code to set up
629   // the frame (that is done below).
630   FrameScope frame_scope(masm, StackFrame::MANUAL);
631   __ push(ebp);  // Caller's frame pointer.
632   __ mov(ebp, esp);
633   __ push(esi);  // Callee's context.
634   __ push(edi);  // Callee's JS function.
635
636   // Get the bytecode array from the function object and load the pointer to the
637   // first entry into edi (InterpreterBytecodeRegister).
638   __ mov(edi, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
639   __ mov(edi, FieldOperand(edi, SharedFunctionInfo::kFunctionDataOffset));
640
641   if (FLAG_debug_code) {
642     // Check function data field is actually a BytecodeArray object.
643     __ AssertNotSmi(edi);
644     __ CmpObjectType(edi, BYTECODE_ARRAY_TYPE, eax);
645     __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry);
646   }
647
648   // Allocate the local and temporary register file on the stack.
649   {
650     // Load frame size from the BytecodeArray object.
651     __ mov(ebx, FieldOperand(edi, BytecodeArray::kFrameSizeOffset));
652
653     // Do a stack check to ensure we don't go over the limit.
654     Label ok;
655     __ mov(ecx, esp);
656     __ sub(ecx, ebx);
657     ExternalReference stack_limit =
658         ExternalReference::address_of_real_stack_limit(masm->isolate());
659     __ cmp(ecx, Operand::StaticVariable(stack_limit));
660     __ j(above_equal, &ok, Label::kNear);
661     __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
662     __ bind(&ok);
663
664     // If ok, push undefined as the initial value for all register file entries.
665     // Note: there should always be at least one stack slot for the return
666     // register in the register file.
667     Label loop_header;
668     __ mov(eax, Immediate(masm->isolate()->factory()->undefined_value()));
669     __ bind(&loop_header);
670     // TODO(rmcilroy): Consider doing more than one push per loop iteration.
671     __ push(eax);
672     // Continue loop if not done.
673     __ sub(ebx, Immediate(kPointerSize));
674     __ j(not_equal, &loop_header, Label::kNear);
675   }
676
677   // TODO(rmcilroy): List of things not currently dealt with here but done in
678   // fullcodegen's prologue:
679   //  - Support profiler (specifically profiling_counter).
680   //  - Call ProfileEntryHookStub when isolate has a function_entry_hook.
681   //  - Allow simulator stop operations if FLAG_stop_at is set.
682   //  - Deal with sloppy mode functions which need to replace the
683   //    receiver with the global proxy when called as functions (without an
684   //    explicit receiver object).
685   //  - Code aging of the BytecodeArray object.
686   //  - Supporting FLAG_trace.
687   //
688   // The following items are also not done here, and will probably be done using
689   // explicit bytecodes instead:
690   //  - Allocating a new local context if applicable.
691   //  - Setting up a local binding to the this function, which is used in
692   //    derived constructors with super calls.
693   //  - Setting new.target if required.
694   //  - Dealing with REST parameters (only if
695   //    https://codereview.chromium.org/1235153006 doesn't land by then).
696   //  - Dealing with argument objects.
697
698   // Perform stack guard check.
699   {
700     Label ok;
701     ExternalReference stack_limit =
702         ExternalReference::address_of_stack_limit(masm->isolate());
703     __ cmp(esp, Operand::StaticVariable(stack_limit));
704     __ j(above_equal, &ok, Label::kNear);
705     __ CallRuntime(Runtime::kStackGuard, 0);
706     __ bind(&ok);
707   }
708
709   // Load bytecode offset and dispatch table into registers.
710   __ mov(ecx, Immediate(BytecodeArray::kHeaderSize - kHeapObjectTag));
711   // Since the dispatch table root might be set after builtins are generated,
712   // load directly from the roots table.
713   __ LoadRoot(ebx, Heap::kInterpreterTableRootIndex);
714   __ add(ebx, Immediate(FixedArray::kHeaderSize - kHeapObjectTag));
715
716   // Dispatch to the first bytecode handler for the function.
717   __ movzx_b(eax, Operand(edi, ecx, times_1, 0));
718   __ mov(eax, Operand(ebx, eax, times_pointer_size, 0));
719   // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging
720   // and header removal.
721   __ add(eax, Immediate(Code::kHeaderSize - kHeapObjectTag));
722   __ jmp(eax);
723 }
724
725
726 void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) {
727   // TODO(rmcilroy): List of things not currently dealt with here but done in
728   // fullcodegen's EmitReturnSequence.
729   //  - Supporting FLAG_trace for Runtime::TraceExit.
730   //  - Support profiler (specifically decrementing profiling_counter
731   //    appropriately and calling out to HandleInterrupts if necessary).
732
733   // Load return value into r0.
734   __ mov(eax, Operand(ebp, -kPointerSize -
735                                StandardFrameConstants::kFixedFrameSizeFromFp));
736   // Leave the frame (also dropping the register file).
737   __ leave();
738   // Return droping receiver + arguments.
739   // TODO(rmcilroy): Get number of arguments from BytecodeArray.
740   __ Ret(1 * kPointerSize, ecx);
741 }
742
743
744 void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
745   CallRuntimePassFunction(masm, Runtime::kCompileLazy);
746   GenerateTailCallToReturnedCode(masm);
747 }
748
749
750
751 static void CallCompileOptimized(MacroAssembler* masm, bool concurrent) {
752   FrameScope scope(masm, StackFrame::INTERNAL);
753   // Push a copy of the function.
754   __ push(edi);
755   // Function is also the parameter to the runtime call.
756   __ push(edi);
757   // Whether to compile in a background thread.
758   __ Push(masm->isolate()->factory()->ToBoolean(concurrent));
759
760   __ CallRuntime(Runtime::kCompileOptimized, 2);
761   // Restore receiver.
762   __ pop(edi);
763 }
764
765
766 void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
767   CallCompileOptimized(masm, false);
768   GenerateTailCallToReturnedCode(masm);
769 }
770
771
772 void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
773   CallCompileOptimized(masm, true);
774   GenerateTailCallToReturnedCode(masm);
775 }
776
777
778 static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
779   // For now, we are relying on the fact that make_code_young doesn't do any
780   // garbage collection which allows us to save/restore the registers without
781   // worrying about which of them contain pointers. We also don't build an
782   // internal frame to make the code faster, since we shouldn't have to do stack
783   // crawls in MakeCodeYoung. This seems a bit fragile.
784
785   // Re-execute the code that was patched back to the young age when
786   // the stub returns.
787   __ sub(Operand(esp, 0), Immediate(5));
788   __ pushad();
789   __ mov(eax, Operand(esp, 8 * kPointerSize));
790   {
791     FrameScope scope(masm, StackFrame::MANUAL);
792     __ PrepareCallCFunction(2, ebx);
793     __ mov(Operand(esp, 1 * kPointerSize),
794            Immediate(ExternalReference::isolate_address(masm->isolate())));
795     __ mov(Operand(esp, 0), eax);
796     __ CallCFunction(
797         ExternalReference::get_make_code_young_function(masm->isolate()), 2);
798   }
799   __ popad();
800   __ ret(0);
801 }
802
803 #define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C)                 \
804 void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking(  \
805     MacroAssembler* masm) {                                  \
806   GenerateMakeCodeYoungAgainCommon(masm);                    \
807 }                                                            \
808 void Builtins::Generate_Make##C##CodeYoungAgainOddMarking(   \
809     MacroAssembler* masm) {                                  \
810   GenerateMakeCodeYoungAgainCommon(masm);                    \
811 }
812 CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
813 #undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
814
815
816 void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
817   // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
818   // that make_code_young doesn't do any garbage collection which allows us to
819   // save/restore the registers without worrying about which of them contain
820   // pointers.
821   __ pushad();
822   __ mov(eax, Operand(esp, 8 * kPointerSize));
823   __ sub(eax, Immediate(Assembler::kCallInstructionLength));
824   {  // NOLINT
825     FrameScope scope(masm, StackFrame::MANUAL);
826     __ PrepareCallCFunction(2, ebx);
827     __ mov(Operand(esp, 1 * kPointerSize),
828            Immediate(ExternalReference::isolate_address(masm->isolate())));
829     __ mov(Operand(esp, 0), eax);
830     __ CallCFunction(
831         ExternalReference::get_mark_code_as_executed_function(masm->isolate()),
832         2);
833   }
834   __ popad();
835
836   // Perform prologue operations usually performed by the young code stub.
837   __ pop(eax);   // Pop return address into scratch register.
838   __ push(ebp);  // Caller's frame pointer.
839   __ mov(ebp, esp);
840   __ push(esi);  // Callee's context.
841   __ push(edi);  // Callee's JS Function.
842   __ push(eax);  // Push return address after frame prologue.
843
844   // Jump to point after the code-age stub.
845   __ ret(0);
846 }
847
848
849 void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
850   GenerateMakeCodeYoungAgainCommon(masm);
851 }
852
853
854 void Builtins::Generate_MarkCodeAsToBeExecutedOnce(MacroAssembler* masm) {
855   Generate_MarkCodeAsExecutedOnce(masm);
856 }
857
858
859 static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
860                                              SaveFPRegsMode save_doubles) {
861   // Enter an internal frame.
862   {
863     FrameScope scope(masm, StackFrame::INTERNAL);
864
865     // Preserve registers across notification, this is important for compiled
866     // stubs that tail call the runtime on deopts passing their parameters in
867     // registers.
868     __ pushad();
869     __ CallRuntime(Runtime::kNotifyStubFailure, 0, save_doubles);
870     __ popad();
871     // Tear down internal frame.
872   }
873
874   __ pop(MemOperand(esp, 0));  // Ignore state offset
875   __ ret(0);  // Return to IC Miss stub, continuation still on stack.
876 }
877
878
879 void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
880   Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
881 }
882
883
884 void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
885   Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
886 }
887
888
889 static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
890                                              Deoptimizer::BailoutType type) {
891   {
892     FrameScope scope(masm, StackFrame::INTERNAL);
893
894     // Pass deoptimization type to the runtime system.
895     __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
896     __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
897
898     // Tear down internal frame.
899   }
900
901   // Get the full codegen state from the stack and untag it.
902   __ mov(ecx, Operand(esp, 1 * kPointerSize));
903   __ SmiUntag(ecx);
904
905   // Switch on the state.
906   Label not_no_registers, not_tos_eax;
907   __ cmp(ecx, FullCodeGenerator::NO_REGISTERS);
908   __ j(not_equal, &not_no_registers, Label::kNear);
909   __ ret(1 * kPointerSize);  // Remove state.
910
911   __ bind(&not_no_registers);
912   __ mov(eax, Operand(esp, 2 * kPointerSize));
913   __ cmp(ecx, FullCodeGenerator::TOS_REG);
914   __ j(not_equal, &not_tos_eax, Label::kNear);
915   __ ret(2 * kPointerSize);  // Remove state, eax.
916
917   __ bind(&not_tos_eax);
918   __ Abort(kNoCasesLeft);
919 }
920
921
922 void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
923   Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
924 }
925
926
927 void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
928   Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
929 }
930
931
932 void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
933   Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
934 }
935
936
937 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
938   Factory* factory = masm->isolate()->factory();
939
940   // 1. Make sure we have at least one argument.
941   { Label done;
942     __ test(eax, eax);
943     __ j(not_zero, &done);
944     __ pop(ebx);
945     __ push(Immediate(factory->undefined_value()));
946     __ push(ebx);
947     __ inc(eax);
948     __ bind(&done);
949   }
950
951   // 2. Get the function to call (passed as receiver) from the stack, check
952   //    if it is a function.
953   Label slow, non_function;
954   // 1 ~ return address.
955   __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
956   __ JumpIfSmi(edi, &non_function);
957   __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
958   __ j(not_equal, &slow);
959
960
961   // 3a. Patch the first argument if necessary when calling a function.
962   Label shift_arguments;
963   __ Move(edx, Immediate(0));  // indicate regular JS_FUNCTION
964   { Label convert_to_object, use_global_proxy, patch_receiver;
965     // Change context eagerly in case we need the global receiver.
966     __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
967
968     // Do not transform the receiver for strict mode functions.
969     __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
970     __ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset),
971               1 << SharedFunctionInfo::kStrictModeBitWithinByte);
972     __ j(not_equal, &shift_arguments);
973
974     // Do not transform the receiver for natives (shared already in ebx).
975     __ test_b(FieldOperand(ebx, SharedFunctionInfo::kNativeByteOffset),
976               1 << SharedFunctionInfo::kNativeBitWithinByte);
977     __ j(not_equal, &shift_arguments);
978
979     // Compute the receiver in sloppy mode.
980     __ mov(ebx, Operand(esp, eax, times_4, 0));  // First argument.
981
982     // Call ToObject on the receiver if it is not an object, or use the
983     // global object if it is null or undefined.
984     __ JumpIfSmi(ebx, &convert_to_object);
985     __ cmp(ebx, factory->null_value());
986     __ j(equal, &use_global_proxy);
987     __ cmp(ebx, factory->undefined_value());
988     __ j(equal, &use_global_proxy);
989     STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
990     __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
991     __ j(above_equal, &shift_arguments);
992
993     __ bind(&convert_to_object);
994
995     { // In order to preserve argument count.
996       FrameScope scope(masm, StackFrame::INTERNAL);
997       __ SmiTag(eax);
998       __ push(eax);
999
1000       __ mov(eax, ebx);
1001       ToObjectStub stub(masm->isolate());
1002       __ CallStub(&stub);
1003       __ mov(ebx, eax);
1004       __ Move(edx, Immediate(0));  // restore
1005
1006       __ pop(eax);
1007       __ SmiUntag(eax);
1008     }
1009
1010     // Restore the function to edi.
1011     __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
1012     __ jmp(&patch_receiver);
1013
1014     __ bind(&use_global_proxy);
1015     __ mov(ebx,
1016            Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
1017     __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalProxyOffset));
1018
1019     __ bind(&patch_receiver);
1020     __ mov(Operand(esp, eax, times_4, 0), ebx);
1021
1022     __ jmp(&shift_arguments);
1023   }
1024
1025   // 3b. Check for function proxy.
1026   __ bind(&slow);
1027   __ Move(edx, Immediate(1));  // indicate function proxy
1028   __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
1029   __ j(equal, &shift_arguments);
1030   __ bind(&non_function);
1031   __ Move(edx, Immediate(2));  // indicate non-function
1032
1033   // 3c. Patch the first argument when calling a non-function.  The
1034   //     CALL_NON_FUNCTION builtin expects the non-function callee as
1035   //     receiver, so overwrite the first argument which will ultimately
1036   //     become the receiver.
1037   __ mov(Operand(esp, eax, times_4, 0), edi);
1038
1039   // 4. Shift arguments and return address one slot down on the stack
1040   //    (overwriting the original receiver).  Adjust argument count to make
1041   //    the original first argument the new receiver.
1042   __ bind(&shift_arguments);
1043   { Label loop;
1044     __ mov(ecx, eax);
1045     __ bind(&loop);
1046     __ mov(ebx, Operand(esp, ecx, times_4, 0));
1047     __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
1048     __ dec(ecx);
1049     __ j(not_sign, &loop);  // While non-negative (to copy return address).
1050     __ pop(ebx);  // Discard copy of return address.
1051     __ dec(eax);  // One fewer argument (first argument is new receiver).
1052   }
1053
1054   // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
1055   //     or a function proxy via CALL_FUNCTION_PROXY.
1056   { Label function, non_proxy;
1057     __ test(edx, edx);
1058     __ j(zero, &function);
1059     __ Move(ebx, Immediate(0));
1060     __ cmp(edx, Immediate(1));
1061     __ j(not_equal, &non_proxy);
1062
1063     __ pop(edx);   // return address
1064     __ push(edi);  // re-add proxy object as additional argument
1065     __ push(edx);
1066     __ inc(eax);
1067     __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
1068     __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1069            RelocInfo::CODE_TARGET);
1070
1071     __ bind(&non_proxy);
1072     __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
1073     __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1074            RelocInfo::CODE_TARGET);
1075     __ bind(&function);
1076   }
1077
1078   // 5b. Get the code to call from the function and check that the number of
1079   //     expected arguments matches what we're providing.  If so, jump
1080   //     (tail-call) to the code in register edx without checking arguments.
1081   __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1082   __ mov(ebx,
1083          FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
1084   __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
1085   __ SmiUntag(ebx);
1086   __ cmp(eax, ebx);
1087   __ j(not_equal,
1088        masm->isolate()->builtins()->ArgumentsAdaptorTrampoline());
1089
1090   ParameterCount expected(0);
1091   __ InvokeCode(edx, expected, expected, JUMP_FUNCTION, NullCallWrapper());
1092 }
1093
1094
1095 static void Generate_PushAppliedArguments(MacroAssembler* masm,
1096                                           const int argumentsOffset,
1097                                           const int indexOffset,
1098                                           const int limitOffset) {
1099   // Copy all arguments from the array to the stack.
1100   Label entry, loop;
1101   Register receiver = LoadDescriptor::ReceiverRegister();
1102   Register key = LoadDescriptor::NameRegister();
1103   Register slot = LoadDescriptor::SlotRegister();
1104   Register vector = LoadWithVectorDescriptor::VectorRegister();
1105   __ mov(key, Operand(ebp, indexOffset));
1106   __ jmp(&entry);
1107   __ bind(&loop);
1108   __ mov(receiver, Operand(ebp, argumentsOffset));  // load arguments
1109
1110   // Use inline caching to speed up access to arguments.
1111   Code::Kind kinds[] = {Code::KEYED_LOAD_IC};
1112   FeedbackVectorSpec spec(0, 1, kinds);
1113   Handle<TypeFeedbackVector> feedback_vector =
1114       masm->isolate()->factory()->NewTypeFeedbackVector(&spec);
1115   int index = feedback_vector->GetIndex(FeedbackVectorICSlot(0));
1116   __ mov(slot, Immediate(Smi::FromInt(index)));
1117   __ mov(vector, Immediate(feedback_vector));
1118   Handle<Code> ic =
1119       KeyedLoadICStub(masm->isolate(), LoadICState(kNoExtraICState)).GetCode();
1120   __ call(ic, RelocInfo::CODE_TARGET);
1121   // It is important that we do not have a test instruction after the
1122   // call.  A test instruction after the call is used to indicate that
1123   // we have generated an inline version of the keyed load.  In this
1124   // case, we know that we are not generating a test instruction next.
1125
1126   // Push the nth argument.
1127   __ push(eax);
1128
1129   // Update the index on the stack and in register key.
1130   __ mov(key, Operand(ebp, indexOffset));
1131   __ add(key, Immediate(1 << kSmiTagSize));
1132   __ mov(Operand(ebp, indexOffset), key);
1133
1134   __ bind(&entry);
1135   __ cmp(key, Operand(ebp, limitOffset));
1136   __ j(not_equal, &loop);
1137
1138   // On exit, the pushed arguments count is in eax, untagged
1139   __ Move(eax, key);
1140   __ SmiUntag(eax);
1141 }
1142
1143
1144 // Used by FunctionApply and ReflectApply
1145 static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) {
1146   const int kFormalParameters = targetIsArgument ? 3 : 2;
1147   const int kStackSize = kFormalParameters + 1;
1148
1149   // Stack at entry:
1150   // esp     : return address
1151   // esp[4]  : arguments
1152   // esp[8]  : receiver ("this")
1153   // esp[12] : function
1154   {
1155     FrameScope frame_scope(masm, StackFrame::INTERNAL);
1156     // Stack frame:
1157     // ebp     : Old base pointer
1158     // ebp[4]  : return address
1159     // ebp[8]  : function arguments
1160     // ebp[12] : receiver
1161     // ebp[16] : function
1162     static const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize;
1163     static const int kReceiverOffset = kArgumentsOffset + kPointerSize;
1164     static const int kFunctionOffset = kReceiverOffset + kPointerSize;
1165
1166     __ push(Operand(ebp, kFunctionOffset));  // push this
1167     __ push(Operand(ebp, kArgumentsOffset));  // push arguments
1168     if (targetIsArgument) {
1169       __ InvokeBuiltin(Builtins::REFLECT_APPLY_PREPARE, CALL_FUNCTION);
1170     } else {
1171       __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
1172     }
1173
1174     Generate_CheckStackOverflow(masm, kFunctionOffset, kEaxIsSmiTagged);
1175
1176     // Push current index and limit.
1177     const int kLimitOffset =
1178         StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
1179     const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
1180     __ push(eax);  // limit
1181     __ push(Immediate(0));  // index
1182
1183     // Get the receiver.
1184     __ mov(ebx, Operand(ebp, kReceiverOffset));
1185
1186     // Check that the function is a JS function (otherwise it must be a proxy).
1187     Label push_receiver, use_global_proxy;
1188     __ mov(edi, Operand(ebp, kFunctionOffset));
1189     __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
1190     __ j(not_equal, &push_receiver);
1191
1192     // Change context eagerly to get the right global object if necessary.
1193     __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1194
1195     // Compute the receiver.
1196     // Do not transform the receiver for strict mode functions.
1197     Label call_to_object;
1198     __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1199     __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
1200               1 << SharedFunctionInfo::kStrictModeBitWithinByte);
1201     __ j(not_equal, &push_receiver);
1202
1203     Factory* factory = masm->isolate()->factory();
1204
1205     // Do not transform the receiver for natives (shared already in ecx).
1206     __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset),
1207               1 << SharedFunctionInfo::kNativeBitWithinByte);
1208     __ j(not_equal, &push_receiver);
1209
1210     // Compute the receiver in sloppy mode.
1211     // Call ToObject on the receiver if it is not an object, or use the
1212     // global object if it is null or undefined.
1213     __ JumpIfSmi(ebx, &call_to_object);
1214     __ cmp(ebx, factory->null_value());
1215     __ j(equal, &use_global_proxy);
1216     __ cmp(ebx, factory->undefined_value());
1217     __ j(equal, &use_global_proxy);
1218     STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
1219     __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
1220     __ j(above_equal, &push_receiver);
1221
1222     __ bind(&call_to_object);
1223     __ mov(eax, ebx);
1224     ToObjectStub stub(masm->isolate());
1225     __ CallStub(&stub);
1226     __ mov(ebx, eax);
1227     __ jmp(&push_receiver);
1228
1229     __ bind(&use_global_proxy);
1230     __ mov(ebx,
1231            Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
1232     __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalProxyOffset));
1233
1234     // Push the receiver.
1235     __ bind(&push_receiver);
1236     __ push(ebx);
1237
1238     // Loop over the arguments array, pushing each value to the stack
1239     Generate_PushAppliedArguments(
1240         masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
1241
1242     // Call the function.
1243     Label call_proxy;
1244     ParameterCount actual(eax);
1245     __ mov(edi, Operand(ebp, kFunctionOffset));
1246     __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
1247     __ j(not_equal, &call_proxy);
1248     __ InvokeFunction(edi, actual, CALL_FUNCTION, NullCallWrapper());
1249
1250     frame_scope.GenerateLeaveFrame();
1251     __ ret(kStackSize * kPointerSize);  // remove this, receiver, and arguments
1252
1253     // Call the function proxy.
1254     __ bind(&call_proxy);
1255     __ push(edi);  // add function proxy as last argument
1256     __ inc(eax);
1257     __ Move(ebx, Immediate(0));
1258     __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
1259     __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
1260             RelocInfo::CODE_TARGET);
1261
1262     // Leave internal frame.
1263   }
1264   __ ret(kStackSize * kPointerSize);  // remove this, receiver, and arguments
1265 }
1266
1267
1268 // Used by ReflectConstruct
1269 static void Generate_ConstructHelper(MacroAssembler* masm) {
1270   const int kFormalParameters = 3;
1271   const int kStackSize = kFormalParameters + 1;
1272
1273   // Stack at entry:
1274   // esp     : return address
1275   // esp[4]  : original constructor (new.target)
1276   // esp[8]  : arguments
1277   // esp[16] : constructor
1278   {
1279     FrameScope frame_scope(masm, StackFrame::INTERNAL);
1280     // Stack frame:
1281     // ebp     : Old base pointer
1282     // ebp[4]  : return address
1283     // ebp[8]  : original constructor (new.target)
1284     // ebp[12] : arguments
1285     // ebp[16] : constructor
1286     static const int kNewTargetOffset = kFPOnStackSize + kPCOnStackSize;
1287     static const int kArgumentsOffset = kNewTargetOffset + kPointerSize;
1288     static const int kFunctionOffset = kArgumentsOffset + kPointerSize;
1289
1290     // If newTarget is not supplied, set it to constructor
1291     Label validate_arguments;
1292     __ mov(eax, Operand(ebp, kNewTargetOffset));
1293     __ CompareRoot(eax, Heap::kUndefinedValueRootIndex);
1294     __ j(not_equal, &validate_arguments, Label::kNear);
1295     __ mov(eax, Operand(ebp, kFunctionOffset));
1296     __ mov(Operand(ebp, kNewTargetOffset), eax);
1297
1298     // Validate arguments
1299     __ bind(&validate_arguments);
1300     __ push(Operand(ebp, kFunctionOffset));
1301     __ push(Operand(ebp, kArgumentsOffset));
1302     __ push(Operand(ebp, kNewTargetOffset));
1303     __ InvokeBuiltin(Builtins::REFLECT_CONSTRUCT_PREPARE, CALL_FUNCTION);
1304
1305     Generate_CheckStackOverflow(masm, kFunctionOffset, kEaxIsSmiTagged);
1306
1307     // Push current index and limit.
1308     const int kLimitOffset =
1309         StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
1310     const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
1311     __ Push(eax);  // limit
1312     __ push(Immediate(0));  // index
1313     // Push the constructor function as callee.
1314     __ push(Operand(ebp, kFunctionOffset));
1315
1316     // Loop over the arguments array, pushing each value to the stack
1317     Generate_PushAppliedArguments(
1318         masm, kArgumentsOffset, kIndexOffset, kLimitOffset);
1319
1320     // Use undefined feedback vector
1321     __ LoadRoot(ebx, Heap::kUndefinedValueRootIndex);
1322     __ mov(edi, Operand(ebp, kFunctionOffset));
1323     __ mov(ecx, Operand(ebp, kNewTargetOffset));
1324
1325     // Call the function.
1326     CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL);
1327     __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
1328
1329     // Leave internal frame.
1330   }
1331   // remove this, target, arguments, and newTarget
1332   __ ret(kStackSize * kPointerSize);
1333 }
1334
1335
1336 void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
1337   Generate_ApplyHelper(masm, false);
1338 }
1339
1340
1341 void Builtins::Generate_ReflectApply(MacroAssembler* masm) {
1342   Generate_ApplyHelper(masm, true);
1343 }
1344
1345
1346 void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) {
1347   Generate_ConstructHelper(masm);
1348 }
1349
1350
1351 void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
1352   // ----------- S t a t e -------------
1353   //  -- eax : argc
1354   //  -- esp[0] : return address
1355   //  -- esp[4] : last argument
1356   // -----------------------------------
1357   Label generic_array_code;
1358
1359   // Get the InternalArray function.
1360   __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi);
1361
1362   if (FLAG_debug_code) {
1363     // Initial map for the builtin InternalArray function should be a map.
1364     __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1365     // Will both indicate a NULL and a Smi.
1366     __ test(ebx, Immediate(kSmiTagMask));
1367     __ Assert(not_zero, kUnexpectedInitialMapForInternalArrayFunction);
1368     __ CmpObjectType(ebx, MAP_TYPE, ecx);
1369     __ Assert(equal, kUnexpectedInitialMapForInternalArrayFunction);
1370   }
1371
1372   // Run the native code for the InternalArray function called as a normal
1373   // function.
1374   // tail call a stub
1375   InternalArrayConstructorStub stub(masm->isolate());
1376   __ TailCallStub(&stub);
1377 }
1378
1379
1380 void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
1381   // ----------- S t a t e -------------
1382   //  -- eax : argc
1383   //  -- esp[0] : return address
1384   //  -- esp[4] : last argument
1385   // -----------------------------------
1386   Label generic_array_code;
1387
1388   // Get the Array function.
1389   __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
1390   __ mov(edx, edi);
1391
1392   if (FLAG_debug_code) {
1393     // Initial map for the builtin Array function should be a map.
1394     __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
1395     // Will both indicate a NULL and a Smi.
1396     __ test(ebx, Immediate(kSmiTagMask));
1397     __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
1398     __ CmpObjectType(ebx, MAP_TYPE, ecx);
1399     __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
1400   }
1401
1402   // Run the native code for the Array function called as a normal function.
1403   // tail call a stub
1404   __ mov(ebx, masm->isolate()->factory()->undefined_value());
1405   ArrayConstructorStub stub(masm->isolate());
1406   __ TailCallStub(&stub);
1407 }
1408
1409
1410 void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
1411   // ----------- S t a t e -------------
1412   //  -- eax                 : number of arguments
1413   //  -- edi                 : constructor function
1414   //  -- esp[0]              : return address
1415   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1416   //  -- esp[(argc + 1) * 4] : receiver
1417   // -----------------------------------
1418   Counters* counters = masm->isolate()->counters();
1419   __ IncrementCounter(counters->string_ctor_calls(), 1);
1420
1421   if (FLAG_debug_code) {
1422     __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx);
1423     __ cmp(edi, ecx);
1424     __ Assert(equal, kUnexpectedStringFunction);
1425   }
1426
1427   // Load the first argument into eax and get rid of the rest
1428   // (including the receiver).
1429   Label no_arguments;
1430   __ test(eax, eax);
1431   __ j(zero, &no_arguments);
1432   __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
1433   __ pop(ecx);
1434   __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
1435   __ push(ecx);
1436   __ mov(eax, ebx);
1437
1438   // Lookup the argument in the number to string cache.
1439   Label not_cached, argument_is_string;
1440   __ LookupNumberStringCache(eax,  // Input.
1441                              ebx,  // Result.
1442                              ecx,  // Scratch 1.
1443                              edx,  // Scratch 2.
1444                              &not_cached);
1445   __ IncrementCounter(counters->string_ctor_cached_number(), 1);
1446   __ bind(&argument_is_string);
1447   // ----------- S t a t e -------------
1448   //  -- ebx    : argument converted to string
1449   //  -- edi    : constructor function
1450   //  -- esp[0] : return address
1451   // -----------------------------------
1452
1453   // Allocate a JSValue and put the tagged pointer into eax.
1454   Label gc_required;
1455   __ Allocate(JSValue::kSize,
1456               eax,  // Result.
1457               ecx,  // New allocation top (we ignore it).
1458               no_reg,
1459               &gc_required,
1460               TAG_OBJECT);
1461
1462   // Set the map.
1463   __ LoadGlobalFunctionInitialMap(edi, ecx);
1464   if (FLAG_debug_code) {
1465     __ cmpb(FieldOperand(ecx, Map::kInstanceSizeOffset),
1466             JSValue::kSize >> kPointerSizeLog2);
1467     __ Assert(equal, kUnexpectedStringWrapperInstanceSize);
1468     __ cmpb(FieldOperand(ecx, Map::kUnusedPropertyFieldsOffset), 0);
1469     __ Assert(equal, kUnexpectedUnusedPropertiesOfStringWrapper);
1470   }
1471   __ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx);
1472
1473   // Set properties and elements.
1474   Factory* factory = masm->isolate()->factory();
1475   __ Move(ecx, Immediate(factory->empty_fixed_array()));
1476   __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx);
1477   __ mov(FieldOperand(eax, JSObject::kElementsOffset), ecx);
1478
1479   // Set the value.
1480   __ mov(FieldOperand(eax, JSValue::kValueOffset), ebx);
1481
1482   // Ensure the object is fully initialized.
1483   STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
1484
1485   // We're done. Return.
1486   __ ret(0);
1487
1488   // The argument was not found in the number to string cache. Check
1489   // if it's a string already before calling the conversion builtin.
1490   Label convert_argument;
1491   __ bind(&not_cached);
1492   STATIC_ASSERT(kSmiTag == 0);
1493   __ JumpIfSmi(eax, &convert_argument);
1494   Condition is_string = masm->IsObjectStringType(eax, ebx, ecx);
1495   __ j(NegateCondition(is_string), &convert_argument);
1496   __ mov(ebx, eax);
1497   __ IncrementCounter(counters->string_ctor_string_value(), 1);
1498   __ jmp(&argument_is_string);
1499
1500   // Invoke the conversion builtin and put the result into ebx.
1501   __ bind(&convert_argument);
1502   __ IncrementCounter(counters->string_ctor_conversions(), 1);
1503   {
1504     FrameScope scope(masm, StackFrame::INTERNAL);
1505     __ push(edi);  // Preserve the function.
1506     __ push(eax);
1507     __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
1508     __ pop(edi);
1509   }
1510   __ mov(ebx, eax);
1511   __ jmp(&argument_is_string);
1512
1513   // Load the empty string into ebx, remove the receiver from the
1514   // stack, and jump back to the case where the argument is a string.
1515   __ bind(&no_arguments);
1516   __ Move(ebx, Immediate(factory->empty_string()));
1517   __ pop(ecx);
1518   __ lea(esp, Operand(esp, kPointerSize));
1519   __ push(ecx);
1520   __ jmp(&argument_is_string);
1521
1522   // At this point the argument is already a string. Call runtime to
1523   // create a string wrapper.
1524   __ bind(&gc_required);
1525   __ IncrementCounter(counters->string_ctor_gc_required(), 1);
1526   {
1527     FrameScope scope(masm, StackFrame::INTERNAL);
1528     __ push(ebx);
1529     __ CallRuntime(Runtime::kNewStringWrapper, 1);
1530   }
1531   __ ret(0);
1532 }
1533
1534
1535 static void ArgumentsAdaptorStackCheck(MacroAssembler* masm,
1536                                        Label* stack_overflow) {
1537   // ----------- S t a t e -------------
1538   //  -- eax : actual number of arguments
1539   //  -- ebx : expected number of arguments
1540   //  -- edi : function (passed through to callee)
1541   // -----------------------------------
1542   // Check the stack for overflow. We are not trying to catch
1543   // interruptions (e.g. debug break and preemption) here, so the "real stack
1544   // limit" is checked.
1545   ExternalReference real_stack_limit =
1546       ExternalReference::address_of_real_stack_limit(masm->isolate());
1547   __ mov(edx, Operand::StaticVariable(real_stack_limit));
1548   // Make ecx the space we have left. The stack might already be overflowed
1549   // here which will cause ecx to become negative.
1550   __ mov(ecx, esp);
1551   __ sub(ecx, edx);
1552   // Make edx the space we need for the array when it is unrolled onto the
1553   // stack.
1554   __ mov(edx, ebx);
1555   __ shl(edx, kPointerSizeLog2);
1556   // Check if the arguments will overflow the stack.
1557   __ cmp(ecx, edx);
1558   __ j(less_equal, stack_overflow);  // Signed comparison.
1559 }
1560
1561
1562 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
1563   __ push(ebp);
1564   __ mov(ebp, esp);
1565
1566   // Store the arguments adaptor context sentinel.
1567   __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
1568
1569   // Push the function on the stack.
1570   __ push(edi);
1571
1572   // Preserve the number of arguments on the stack. Must preserve eax,
1573   // ebx and ecx because these registers are used when copying the
1574   // arguments and the receiver.
1575   STATIC_ASSERT(kSmiTagSize == 1);
1576   __ lea(edi, Operand(eax, eax, times_1, kSmiTag));
1577   __ push(edi);
1578 }
1579
1580
1581 static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
1582   // Retrieve the number of arguments from the stack.
1583   __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1584
1585   // Leave the frame.
1586   __ leave();
1587
1588   // Remove caller arguments from the stack.
1589   STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
1590   __ pop(ecx);
1591   __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize));  // 1 ~ receiver
1592   __ push(ecx);
1593 }
1594
1595
1596 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
1597   // ----------- S t a t e -------------
1598   //  -- eax : actual number of arguments
1599   //  -- ebx : expected number of arguments
1600   //  -- edi : function (passed through to callee)
1601   // -----------------------------------
1602
1603   Label invoke, dont_adapt_arguments;
1604   __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
1605
1606   Label stack_overflow;
1607   ArgumentsAdaptorStackCheck(masm, &stack_overflow);
1608
1609   Label enough, too_few;
1610   __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
1611   __ cmp(eax, ebx);
1612   __ j(less, &too_few);
1613   __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
1614   __ j(equal, &dont_adapt_arguments);
1615
1616   {  // Enough parameters: Actual >= expected.
1617     __ bind(&enough);
1618     EnterArgumentsAdaptorFrame(masm);
1619
1620     // Copy receiver and all expected arguments.
1621     const int offset = StandardFrameConstants::kCallerSPOffset;
1622     __ lea(eax, Operand(ebp, eax, times_4, offset));
1623     __ mov(edi, -1);  // account for receiver
1624
1625     Label copy;
1626     __ bind(&copy);
1627     __ inc(edi);
1628     __ push(Operand(eax, 0));
1629     __ sub(eax, Immediate(kPointerSize));
1630     __ cmp(edi, ebx);
1631     __ j(less, &copy);
1632     __ jmp(&invoke);
1633   }
1634
1635   {  // Too few parameters: Actual < expected.
1636     __ bind(&too_few);
1637
1638     // If the function is strong we need to throw an error.
1639     Label no_strong_error;
1640     __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1641     __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrongModeByteOffset),
1642               1 << SharedFunctionInfo::kStrongModeBitWithinByte);
1643     __ j(equal, &no_strong_error, Label::kNear);
1644
1645     // What we really care about is the required number of arguments.
1646     __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kLengthOffset));
1647     __ SmiUntag(ecx);
1648     __ cmp(eax, ecx);
1649     __ j(greater_equal, &no_strong_error, Label::kNear);
1650
1651     {
1652       FrameScope frame(masm, StackFrame::MANUAL);
1653       EnterArgumentsAdaptorFrame(masm);
1654       __ CallRuntime(Runtime::kThrowStrongModeTooFewArguments, 0);
1655     }
1656
1657     __ bind(&no_strong_error);
1658     EnterArgumentsAdaptorFrame(masm);
1659
1660     // Copy receiver and all actual arguments.
1661     const int offset = StandardFrameConstants::kCallerSPOffset;
1662     __ lea(edi, Operand(ebp, eax, times_4, offset));
1663     // ebx = expected - actual.
1664     __ sub(ebx, eax);
1665     // eax = -actual - 1
1666     __ neg(eax);
1667     __ sub(eax, Immediate(1));
1668
1669     Label copy;
1670     __ bind(&copy);
1671     __ inc(eax);
1672     __ push(Operand(edi, 0));
1673     __ sub(edi, Immediate(kPointerSize));
1674     __ test(eax, eax);
1675     __ j(not_zero, &copy);
1676
1677     // Fill remaining expected arguments with undefined values.
1678     Label fill;
1679     __ bind(&fill);
1680     __ inc(eax);
1681     __ push(Immediate(masm->isolate()->factory()->undefined_value()));
1682     __ cmp(eax, ebx);
1683     __ j(less, &fill);
1684   }
1685
1686   // Call the entry point.
1687   __ bind(&invoke);
1688   // Restore function pointer.
1689   __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1690   __ call(edx);
1691
1692   // Store offset of return address for deoptimizer.
1693   masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
1694
1695   // Leave frame and return.
1696   LeaveArgumentsAdaptorFrame(masm);
1697   __ ret(0);
1698
1699   // -------------------------------------------
1700   // Dont adapt arguments.
1701   // -------------------------------------------
1702   __ bind(&dont_adapt_arguments);
1703   __ jmp(edx);
1704
1705   __ bind(&stack_overflow);
1706   {
1707     FrameScope frame(masm, StackFrame::MANUAL);
1708     EnterArgumentsAdaptorFrame(masm);
1709     __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
1710     __ int3();
1711   }
1712 }
1713
1714
1715 void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
1716   // Lookup the function in the JavaScript frame.
1717   __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1718   {
1719     FrameScope scope(masm, StackFrame::INTERNAL);
1720     // Pass function as argument.
1721     __ push(eax);
1722     __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
1723   }
1724
1725   Label skip;
1726   // If the code object is null, just return to the unoptimized code.
1727   __ cmp(eax, Immediate(0));
1728   __ j(not_equal, &skip, Label::kNear);
1729   __ ret(0);
1730
1731   __ bind(&skip);
1732
1733   // Load deoptimization data from the code object.
1734   __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag));
1735
1736   // Load the OSR entrypoint offset from the deoptimization data.
1737   __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt(
1738       DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag));
1739   __ SmiUntag(ebx);
1740
1741   // Compute the target address = code_obj + header_size + osr_offset
1742   __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag));
1743
1744   // Overwrite the return address on the stack.
1745   __ mov(Operand(esp, 0), eax);
1746
1747   // And "return" to the OSR entry point of the function.
1748   __ ret(0);
1749 }
1750
1751
1752 void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
1753   // We check the stack limit as indicator that recompilation might be done.
1754   Label ok;
1755   ExternalReference stack_limit =
1756       ExternalReference::address_of_stack_limit(masm->isolate());
1757   __ cmp(esp, Operand::StaticVariable(stack_limit));
1758   __ j(above_equal, &ok, Label::kNear);
1759   {
1760     FrameScope scope(masm, StackFrame::INTERNAL);
1761     __ CallRuntime(Runtime::kStackGuard, 0);
1762   }
1763   __ jmp(masm->isolate()->builtins()->OnStackReplacement(),
1764          RelocInfo::CODE_TARGET);
1765
1766   __ bind(&ok);
1767   __ ret(0);
1768 }
1769
1770 #undef __
1771 }  // namespace internal
1772 }  // namespace v8
1773
1774 #endif  // V8_TARGET_ARCH_IA32