e0c8f3d7b5a1f9961391fb3ee5bfef6ff93a7e89
[platform/upstream/v8.git] / src / x87 / code-stubs-x87.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_X87
8
9 #include "src/base/bits.h"
10 #include "src/bootstrapper.h"
11 #include "src/code-stubs.h"
12 #include "src/codegen.h"
13 #include "src/ic/handler-compiler.h"
14 #include "src/ic/ic.h"
15 #include "src/ic/stub-cache.h"
16 #include "src/isolate.h"
17 #include "src/jsregexp.h"
18 #include "src/regexp-macro-assembler.h"
19 #include "src/runtime/runtime.h"
20
21 namespace v8 {
22 namespace internal {
23
24
25 static void InitializeArrayConstructorDescriptor(
26     Isolate* isolate, CodeStubDescriptor* descriptor,
27     int constant_stack_parameter_count) {
28   // register state
29   // eax -- number of arguments
30   // edi -- function
31   // ebx -- allocation site with elements kind
32   Address deopt_handler = Runtime::FunctionForId(
33       Runtime::kArrayConstructor)->entry;
34
35   if (constant_stack_parameter_count == 0) {
36     descriptor->Initialize(deopt_handler, constant_stack_parameter_count,
37                            JS_FUNCTION_STUB_MODE);
38   } else {
39     descriptor->Initialize(eax, deopt_handler, constant_stack_parameter_count,
40                            JS_FUNCTION_STUB_MODE, PASS_ARGUMENTS);
41   }
42 }
43
44
45 static void InitializeInternalArrayConstructorDescriptor(
46     Isolate* isolate, CodeStubDescriptor* descriptor,
47     int constant_stack_parameter_count) {
48   // register state
49   // eax -- number of arguments
50   // edi -- constructor function
51   Address deopt_handler = Runtime::FunctionForId(
52       Runtime::kInternalArrayConstructor)->entry;
53
54   if (constant_stack_parameter_count == 0) {
55     descriptor->Initialize(deopt_handler, constant_stack_parameter_count,
56                            JS_FUNCTION_STUB_MODE);
57   } else {
58     descriptor->Initialize(eax, deopt_handler, constant_stack_parameter_count,
59                            JS_FUNCTION_STUB_MODE, PASS_ARGUMENTS);
60   }
61 }
62
63
64 void ArrayNoArgumentConstructorStub::InitializeDescriptor(
65     CodeStubDescriptor* descriptor) {
66   InitializeArrayConstructorDescriptor(isolate(), descriptor, 0);
67 }
68
69
70 void ArraySingleArgumentConstructorStub::InitializeDescriptor(
71     CodeStubDescriptor* descriptor) {
72   InitializeArrayConstructorDescriptor(isolate(), descriptor, 1);
73 }
74
75
76 void ArrayNArgumentsConstructorStub::InitializeDescriptor(
77     CodeStubDescriptor* descriptor) {
78   InitializeArrayConstructorDescriptor(isolate(), descriptor, -1);
79 }
80
81
82 void InternalArrayNoArgumentConstructorStub::InitializeDescriptor(
83     CodeStubDescriptor* descriptor) {
84   InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, 0);
85 }
86
87
88 void InternalArraySingleArgumentConstructorStub::InitializeDescriptor(
89     CodeStubDescriptor* descriptor) {
90   InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, 1);
91 }
92
93
94 void InternalArrayNArgumentsConstructorStub::InitializeDescriptor(
95     CodeStubDescriptor* descriptor) {
96   InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, -1);
97 }
98
99
100 #define __ ACCESS_MASM(masm)
101
102
103 void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm,
104                                                ExternalReference miss) {
105   // Update the static counter each time a new code stub is generated.
106   isolate()->counters()->code_stubs()->Increment();
107
108   CallInterfaceDescriptor descriptor = GetCallInterfaceDescriptor();
109   int param_count = descriptor.GetEnvironmentParameterCount();
110   {
111     // Call the runtime system in a fresh internal frame.
112     FrameScope scope(masm, StackFrame::INTERNAL);
113     DCHECK(param_count == 0 ||
114            eax.is(descriptor.GetEnvironmentParameterRegister(param_count - 1)));
115     // Push arguments
116     for (int i = 0; i < param_count; ++i) {
117       __ push(descriptor.GetEnvironmentParameterRegister(i));
118     }
119     __ CallExternalReference(miss, param_count);
120   }
121
122   __ ret(0);
123 }
124
125
126 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
127   // We don't allow a GC during a store buffer overflow so there is no need to
128   // store the registers in any particular way, but we do have to store and
129   // restore them.
130   __ pushad();
131   if (save_doubles()) {
132     // Save FPU stat in m108byte.
133     __ sub(esp, Immediate(108));
134     __ fnsave(Operand(esp, 0));
135   }
136   const int argument_count = 1;
137
138   AllowExternalCallThatCantCauseGC scope(masm);
139   __ PrepareCallCFunction(argument_count, ecx);
140   __ mov(Operand(esp, 0 * kPointerSize),
141          Immediate(ExternalReference::isolate_address(isolate())));
142   __ CallCFunction(
143       ExternalReference::store_buffer_overflow_function(isolate()),
144       argument_count);
145   if (save_doubles()) {
146     // Restore FPU stat in m108byte.
147     __ frstor(Operand(esp, 0));
148     __ add(esp, Immediate(108));
149   }
150   __ popad();
151   __ ret(0);
152 }
153
154
155 class FloatingPointHelper : public AllStatic {
156  public:
157   enum ArgLocation {
158     ARGS_ON_STACK,
159     ARGS_IN_REGISTERS
160   };
161
162   // Code pattern for loading a floating point value. Input value must
163   // be either a smi or a heap number object (fp value). Requirements:
164   // operand in register number. Returns operand as floating point number
165   // on FPU stack.
166   static void LoadFloatOperand(MacroAssembler* masm, Register number);
167
168   // Test if operands are smi or number objects (fp). Requirements:
169   // operand_1 in eax, operand_2 in edx; falls through on float
170   // operands, jumps to the non_float label otherwise.
171   static void CheckFloatOperands(MacroAssembler* masm,
172                                  Label* non_float,
173                                  Register scratch);
174 };
175
176
177 void DoubleToIStub::Generate(MacroAssembler* masm) {
178   Register input_reg = this->source();
179   Register final_result_reg = this->destination();
180   DCHECK(is_truncating());
181
182   Label check_negative, process_64_bits, done, done_no_stash;
183
184   int double_offset = offset();
185
186   // Account for return address and saved regs if input is esp.
187   if (input_reg.is(esp)) double_offset += 3 * kPointerSize;
188
189   MemOperand mantissa_operand(MemOperand(input_reg, double_offset));
190   MemOperand exponent_operand(MemOperand(input_reg,
191                                          double_offset + kDoubleSize / 2));
192
193   Register scratch1;
194   {
195     Register scratch_candidates[3] = { ebx, edx, edi };
196     for (int i = 0; i < 3; i++) {
197       scratch1 = scratch_candidates[i];
198       if (!final_result_reg.is(scratch1) && !input_reg.is(scratch1)) break;
199     }
200   }
201   // Since we must use ecx for shifts below, use some other register (eax)
202   // to calculate the result if ecx is the requested return register.
203   Register result_reg = final_result_reg.is(ecx) ? eax : final_result_reg;
204   // Save ecx if it isn't the return register and therefore volatile, or if it
205   // is the return register, then save the temp register we use in its stead for
206   // the result.
207   Register save_reg = final_result_reg.is(ecx) ? eax : ecx;
208   __ push(scratch1);
209   __ push(save_reg);
210
211   bool stash_exponent_copy = !input_reg.is(esp);
212   __ mov(scratch1, mantissa_operand);
213   __ mov(ecx, exponent_operand);
214   if (stash_exponent_copy) __ push(ecx);
215
216   __ and_(ecx, HeapNumber::kExponentMask);
217   __ shr(ecx, HeapNumber::kExponentShift);
218   __ lea(result_reg, MemOperand(ecx, -HeapNumber::kExponentBias));
219   __ cmp(result_reg, Immediate(HeapNumber::kMantissaBits));
220   __ j(below, &process_64_bits);
221
222   // Result is entirely in lower 32-bits of mantissa
223   int delta = HeapNumber::kExponentBias + Double::kPhysicalSignificandSize;
224   __ sub(ecx, Immediate(delta));
225   __ xor_(result_reg, result_reg);
226   __ cmp(ecx, Immediate(31));
227   __ j(above, &done);
228   __ shl_cl(scratch1);
229   __ jmp(&check_negative);
230
231   __ bind(&process_64_bits);
232   // Result must be extracted from shifted 32-bit mantissa
233   __ sub(ecx, Immediate(delta));
234   __ neg(ecx);
235   if (stash_exponent_copy) {
236     __ mov(result_reg, MemOperand(esp, 0));
237   } else {
238     __ mov(result_reg, exponent_operand);
239   }
240   __ and_(result_reg,
241           Immediate(static_cast<uint32_t>(Double::kSignificandMask >> 32)));
242   __ add(result_reg,
243          Immediate(static_cast<uint32_t>(Double::kHiddenBit >> 32)));
244   __ shrd(result_reg, scratch1);
245   __ shr_cl(result_reg);
246   __ test(ecx, Immediate(32));
247   {
248     Label skip_mov;
249     __ j(equal, &skip_mov, Label::kNear);
250     __ mov(scratch1, result_reg);
251     __ bind(&skip_mov);
252   }
253
254   // If the double was negative, negate the integer result.
255   __ bind(&check_negative);
256   __ mov(result_reg, scratch1);
257   __ neg(result_reg);
258   if (stash_exponent_copy) {
259     __ cmp(MemOperand(esp, 0), Immediate(0));
260   } else {
261     __ cmp(exponent_operand, Immediate(0));
262   }
263   {
264     Label skip_mov;
265     __ j(less_equal, &skip_mov, Label::kNear);
266     __ mov(result_reg, scratch1);
267     __ bind(&skip_mov);
268   }
269
270   // Restore registers
271   __ bind(&done);
272   if (stash_exponent_copy) {
273     __ add(esp, Immediate(kDoubleSize / 2));
274   }
275   __ bind(&done_no_stash);
276   if (!final_result_reg.is(result_reg)) {
277     DCHECK(final_result_reg.is(ecx));
278     __ mov(final_result_reg, result_reg);
279   }
280   __ pop(save_reg);
281   __ pop(scratch1);
282   __ ret(0);
283 }
284
285
286 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
287                                            Register number) {
288   Label load_smi, done;
289
290   __ JumpIfSmi(number, &load_smi, Label::kNear);
291   __ fld_d(FieldOperand(number, HeapNumber::kValueOffset));
292   __ jmp(&done, Label::kNear);
293
294   __ bind(&load_smi);
295   __ SmiUntag(number);
296   __ push(number);
297   __ fild_s(Operand(esp, 0));
298   __ pop(number);
299
300   __ bind(&done);
301 }
302
303
304 void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm,
305                                              Label* non_float,
306                                              Register scratch) {
307   Label test_other, done;
308   // Test if both operands are floats or smi -> scratch=k_is_float;
309   // Otherwise scratch = k_not_float.
310   __ JumpIfSmi(edx, &test_other, Label::kNear);
311   __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset));
312   Factory* factory = masm->isolate()->factory();
313   __ cmp(scratch, factory->heap_number_map());
314   __ j(not_equal, non_float);  // argument in edx is not a number -> NaN
315
316   __ bind(&test_other);
317   __ JumpIfSmi(eax, &done, Label::kNear);
318   __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset));
319   __ cmp(scratch, factory->heap_number_map());
320   __ j(not_equal, non_float);  // argument in eax is not a number -> NaN
321
322   // Fall-through: Both operands are numbers.
323   __ bind(&done);
324 }
325
326
327 void MathPowStub::Generate(MacroAssembler* masm) {
328   // No SSE2 support
329   UNREACHABLE();
330 }
331
332
333 void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
334   Label miss;
335   Register receiver = LoadDescriptor::ReceiverRegister();
336
337   if (FLAG_vector_ics) {
338     // With careful management, we won't have to save slot and vector on
339     // the stack. Simply handle the possibly missing case first.
340     // TODO(mvstanton): this code can be more efficient.
341     __ cmp(FieldOperand(receiver, JSFunction::kPrototypeOrInitialMapOffset),
342            Immediate(isolate()->factory()->the_hole_value()));
343     __ j(equal, &miss);
344     __ TryGetFunctionPrototype(receiver, eax, ebx, &miss);
345     __ ret(0);
346   } else {
347     NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, eax,
348                                                             ebx, &miss);
349   }
350   __ bind(&miss);
351   PropertyAccessCompiler::TailCallBuiltin(
352       masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC));
353 }
354
355
356 void LoadIndexedInterceptorStub::Generate(MacroAssembler* masm) {
357   // Return address is on the stack.
358   Label slow;
359
360   Register receiver = LoadDescriptor::ReceiverRegister();
361   Register key = LoadDescriptor::NameRegister();
362   Register scratch = eax;
363   DCHECK(!scratch.is(receiver) && !scratch.is(key));
364
365   // Check that the key is an array index, that is Uint32.
366   __ test(key, Immediate(kSmiTagMask | kSmiSignMask));
367   __ j(not_zero, &slow);
368
369   // Everything is fine, call runtime.
370   __ pop(scratch);
371   __ push(receiver);  // receiver
372   __ push(key);       // key
373   __ push(scratch);   // return address
374
375   // Perform tail call to the entry.
376   ExternalReference ref = ExternalReference(
377       IC_Utility(IC::kLoadElementWithInterceptor), masm->isolate());
378   __ TailCallExternalReference(ref, 2, 1);
379
380   __ bind(&slow);
381   PropertyAccessCompiler::TailCallBuiltin(
382       masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
383 }
384
385
386 void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
387   // Return address is on the stack.
388   Label miss;
389
390   Register receiver = LoadDescriptor::ReceiverRegister();
391   Register index = LoadDescriptor::NameRegister();
392   Register scratch = edi;
393   DCHECK(!scratch.is(receiver) && !scratch.is(index));
394   Register result = eax;
395   DCHECK(!result.is(scratch));
396   DCHECK(!FLAG_vector_ics ||
397          (!scratch.is(VectorLoadICDescriptor::VectorRegister()) &&
398           result.is(VectorLoadICDescriptor::SlotRegister())));
399
400   // StringCharAtGenerator doesn't use the result register until it's passed
401   // the different miss possibilities. If it did, we would have a conflict
402   // when FLAG_vector_ics is true.
403
404   StringCharAtGenerator char_at_generator(receiver, index, scratch, result,
405                                           &miss,  // When not a string.
406                                           &miss,  // When not a number.
407                                           &miss,  // When index out of range.
408                                           STRING_INDEX_IS_ARRAY_INDEX,
409                                           RECEIVER_IS_STRING);
410   char_at_generator.GenerateFast(masm);
411   __ ret(0);
412
413   StubRuntimeCallHelper call_helper;
414   char_at_generator.GenerateSlow(masm, PART_OF_IC_HANDLER, call_helper);
415
416   __ bind(&miss);
417   PropertyAccessCompiler::TailCallBuiltin(
418       masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
419 }
420
421
422 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
423   CHECK(!has_new_target());
424   // The key is in edx and the parameter count is in eax.
425   DCHECK(edx.is(ArgumentsAccessReadDescriptor::index()));
426   DCHECK(eax.is(ArgumentsAccessReadDescriptor::parameter_count()));
427
428   // The displacement is used for skipping the frame pointer on the
429   // stack. It is the offset of the last parameter (if any) relative
430   // to the frame pointer.
431   static const int kDisplacement = 1 * kPointerSize;
432
433   // Check that the key is a smi.
434   Label slow;
435   __ JumpIfNotSmi(edx, &slow, Label::kNear);
436
437   // Check if the calling frame is an arguments adaptor frame.
438   Label adaptor;
439   __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
440   __ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset));
441   __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
442   __ j(equal, &adaptor, Label::kNear);
443
444   // Check index against formal parameters count limit passed in
445   // through register eax. Use unsigned comparison to get negative
446   // check for free.
447   __ cmp(edx, eax);
448   __ j(above_equal, &slow, Label::kNear);
449
450   // Read the argument from the stack and return it.
451   STATIC_ASSERT(kSmiTagSize == 1);
452   STATIC_ASSERT(kSmiTag == 0);  // Shifting code depends on these.
453   __ lea(ebx, Operand(ebp, eax, times_2, 0));
454   __ neg(edx);
455   __ mov(eax, Operand(ebx, edx, times_2, kDisplacement));
456   __ ret(0);
457
458   // Arguments adaptor case: Check index against actual arguments
459   // limit found in the arguments adaptor frame. Use unsigned
460   // comparison to get negative check for free.
461   __ bind(&adaptor);
462   __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
463   __ cmp(edx, ecx);
464   __ j(above_equal, &slow, Label::kNear);
465
466   // Read the argument from the stack and return it.
467   STATIC_ASSERT(kSmiTagSize == 1);
468   STATIC_ASSERT(kSmiTag == 0);  // Shifting code depends on these.
469   __ lea(ebx, Operand(ebx, ecx, times_2, 0));
470   __ neg(edx);
471   __ mov(eax, Operand(ebx, edx, times_2, kDisplacement));
472   __ ret(0);
473
474   // Slow-case: Handle non-smi or out-of-bounds access to arguments
475   // by calling the runtime system.
476   __ bind(&slow);
477   __ pop(ebx);  // Return address.
478   __ push(edx);
479   __ push(ebx);
480   __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1);
481 }
482
483
484 void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) {
485   // esp[0] : return address
486   // esp[4] : number of parameters
487   // esp[8] : receiver displacement
488   // esp[12] : function
489
490   CHECK(!has_new_target());
491
492   // Check if the calling frame is an arguments adaptor frame.
493   Label runtime;
494   __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
495   __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
496   __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
497   __ j(not_equal, &runtime, Label::kNear);
498
499   // Patch the arguments.length and the parameters pointer.
500   __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
501   __ mov(Operand(esp, 1 * kPointerSize), ecx);
502   __ lea(edx, Operand(edx, ecx, times_2,
503               StandardFrameConstants::kCallerSPOffset));
504   __ mov(Operand(esp, 2 * kPointerSize), edx);
505
506   __ bind(&runtime);
507   __ TailCallRuntime(Runtime::kNewSloppyArguments, 3, 1);
508 }
509
510
511 void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
512   // esp[0] : return address
513   // esp[4] : number of parameters (tagged)
514   // esp[8] : receiver displacement
515   // esp[12] : function
516
517   // ebx = parameter count (tagged)
518   __ mov(ebx, Operand(esp, 1 * kPointerSize));
519
520   CHECK(!has_new_target());
521
522   // Check if the calling frame is an arguments adaptor frame.
523   // TODO(rossberg): Factor out some of the bits that are shared with the other
524   // Generate* functions.
525   Label runtime;
526   Label adaptor_frame, try_allocate;
527   __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
528   __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
529   __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
530   __ j(equal, &adaptor_frame, Label::kNear);
531
532   // No adaptor, parameter count = argument count.
533   __ mov(ecx, ebx);
534   __ jmp(&try_allocate, Label::kNear);
535
536   // We have an adaptor frame. Patch the parameters pointer.
537   __ bind(&adaptor_frame);
538   __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
539   __ lea(edx, Operand(edx, ecx, times_2,
540                       StandardFrameConstants::kCallerSPOffset));
541   __ mov(Operand(esp, 2 * kPointerSize), edx);
542
543   // ebx = parameter count (tagged)
544   // ecx = argument count (smi-tagged)
545   // esp[4] = parameter count (tagged)
546   // esp[8] = address of receiver argument
547   // Compute the mapped parameter count = min(ebx, ecx) in ebx.
548   __ cmp(ebx, ecx);
549   __ j(less_equal, &try_allocate, Label::kNear);
550   __ mov(ebx, ecx);
551
552   __ bind(&try_allocate);
553
554   // Save mapped parameter count.
555   __ push(ebx);
556
557   // Compute the sizes of backing store, parameter map, and arguments object.
558   // 1. Parameter map, has 2 extra words containing context and backing store.
559   const int kParameterMapHeaderSize =
560       FixedArray::kHeaderSize + 2 * kPointerSize;
561   Label no_parameter_map;
562   __ test(ebx, ebx);
563   __ j(zero, &no_parameter_map, Label::kNear);
564   __ lea(ebx, Operand(ebx, times_2, kParameterMapHeaderSize));
565   __ bind(&no_parameter_map);
566
567   // 2. Backing store.
568   __ lea(ebx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize));
569
570   // 3. Arguments object.
571   __ add(ebx, Immediate(Heap::kSloppyArgumentsObjectSize));
572
573   // Do the allocation of all three objects in one go.
574   __ Allocate(ebx, eax, edx, edi, &runtime, TAG_OBJECT);
575
576   // eax = address of new object(s) (tagged)
577   // ecx = argument count (smi-tagged)
578   // esp[0] = mapped parameter count (tagged)
579   // esp[8] = parameter count (tagged)
580   // esp[12] = address of receiver argument
581   // Get the arguments map from the current native context into edi.
582   Label has_mapped_parameters, instantiate;
583   __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
584   __ mov(edi, FieldOperand(edi, GlobalObject::kNativeContextOffset));
585   __ mov(ebx, Operand(esp, 0 * kPointerSize));
586   __ test(ebx, ebx);
587   __ j(not_zero, &has_mapped_parameters, Label::kNear);
588   __ mov(
589       edi,
590       Operand(edi, Context::SlotOffset(Context::SLOPPY_ARGUMENTS_MAP_INDEX)));
591   __ jmp(&instantiate, Label::kNear);
592
593   __ bind(&has_mapped_parameters);
594   __ mov(
595       edi,
596       Operand(edi, Context::SlotOffset(Context::ALIASED_ARGUMENTS_MAP_INDEX)));
597   __ bind(&instantiate);
598
599   // eax = address of new object (tagged)
600   // ebx = mapped parameter count (tagged)
601   // ecx = argument count (smi-tagged)
602   // edi = address of arguments map (tagged)
603   // esp[0] = mapped parameter count (tagged)
604   // esp[8] = parameter count (tagged)
605   // esp[12] = address of receiver argument
606   // Copy the JS object part.
607   __ mov(FieldOperand(eax, JSObject::kMapOffset), edi);
608   __ mov(FieldOperand(eax, JSObject::kPropertiesOffset),
609          masm->isolate()->factory()->empty_fixed_array());
610   __ mov(FieldOperand(eax, JSObject::kElementsOffset),
611          masm->isolate()->factory()->empty_fixed_array());
612
613   // Set up the callee in-object property.
614   STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
615   __ mov(edx, Operand(esp, 4 * kPointerSize));
616   __ AssertNotSmi(edx);
617   __ mov(FieldOperand(eax, JSObject::kHeaderSize +
618                       Heap::kArgumentsCalleeIndex * kPointerSize),
619          edx);
620
621   // Use the length (smi tagged) and set that as an in-object property too.
622   __ AssertSmi(ecx);
623   STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
624   __ mov(FieldOperand(eax, JSObject::kHeaderSize +
625                       Heap::kArgumentsLengthIndex * kPointerSize),
626          ecx);
627
628   // Set up the elements pointer in the allocated arguments object.
629   // If we allocated a parameter map, edi will point there, otherwise to the
630   // backing store.
631   __ lea(edi, Operand(eax, Heap::kSloppyArgumentsObjectSize));
632   __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi);
633
634   // eax = address of new object (tagged)
635   // ebx = mapped parameter count (tagged)
636   // ecx = argument count (tagged)
637   // edi = address of parameter map or backing store (tagged)
638   // esp[0] = mapped parameter count (tagged)
639   // esp[8] = parameter count (tagged)
640   // esp[12] = address of receiver argument
641   // Free a register.
642   __ push(eax);
643
644   // Initialize parameter map. If there are no mapped arguments, we're done.
645   Label skip_parameter_map;
646   __ test(ebx, ebx);
647   __ j(zero, &skip_parameter_map);
648
649   __ mov(FieldOperand(edi, FixedArray::kMapOffset),
650          Immediate(isolate()->factory()->sloppy_arguments_elements_map()));
651   __ lea(eax, Operand(ebx, reinterpret_cast<intptr_t>(Smi::FromInt(2))));
652   __ mov(FieldOperand(edi, FixedArray::kLengthOffset), eax);
653   __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 0 * kPointerSize), esi);
654   __ lea(eax, Operand(edi, ebx, times_2, kParameterMapHeaderSize));
655   __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 1 * kPointerSize), eax);
656
657   // Copy the parameter slots and the holes in the arguments.
658   // We need to fill in mapped_parameter_count slots. They index the context,
659   // where parameters are stored in reverse order, at
660   //   MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1
661   // The mapped parameter thus need to get indices
662   //   MIN_CONTEXT_SLOTS+parameter_count-1 ..
663   //       MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count
664   // We loop from right to left.
665   Label parameters_loop, parameters_test;
666   __ push(ecx);
667   __ mov(eax, Operand(esp, 2 * kPointerSize));
668   __ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS)));
669   __ add(ebx, Operand(esp, 4 * kPointerSize));
670   __ sub(ebx, eax);
671   __ mov(ecx, isolate()->factory()->the_hole_value());
672   __ mov(edx, edi);
673   __ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize));
674   // eax = loop variable (tagged)
675   // ebx = mapping index (tagged)
676   // ecx = the hole value
677   // edx = address of parameter map (tagged)
678   // edi = address of backing store (tagged)
679   // esp[0] = argument count (tagged)
680   // esp[4] = address of new object (tagged)
681   // esp[8] = mapped parameter count (tagged)
682   // esp[16] = parameter count (tagged)
683   // esp[20] = address of receiver argument
684   __ jmp(&parameters_test, Label::kNear);
685
686   __ bind(&parameters_loop);
687   __ sub(eax, Immediate(Smi::FromInt(1)));
688   __ mov(FieldOperand(edx, eax, times_2, kParameterMapHeaderSize), ebx);
689   __ mov(FieldOperand(edi, eax, times_2, FixedArray::kHeaderSize), ecx);
690   __ add(ebx, Immediate(Smi::FromInt(1)));
691   __ bind(&parameters_test);
692   __ test(eax, eax);
693   __ j(not_zero, &parameters_loop, Label::kNear);
694   __ pop(ecx);
695
696   __ bind(&skip_parameter_map);
697
698   // ecx = argument count (tagged)
699   // edi = address of backing store (tagged)
700   // esp[0] = address of new object (tagged)
701   // esp[4] = mapped parameter count (tagged)
702   // esp[12] = parameter count (tagged)
703   // esp[16] = address of receiver argument
704   // Copy arguments header and remaining slots (if there are any).
705   __ mov(FieldOperand(edi, FixedArray::kMapOffset),
706          Immediate(isolate()->factory()->fixed_array_map()));
707   __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
708
709   Label arguments_loop, arguments_test;
710   __ mov(ebx, Operand(esp, 1 * kPointerSize));
711   __ mov(edx, Operand(esp, 4 * kPointerSize));
712   __ sub(edx, ebx);  // Is there a smarter way to do negative scaling?
713   __ sub(edx, ebx);
714   __ jmp(&arguments_test, Label::kNear);
715
716   __ bind(&arguments_loop);
717   __ sub(edx, Immediate(kPointerSize));
718   __ mov(eax, Operand(edx, 0));
719   __ mov(FieldOperand(edi, ebx, times_2, FixedArray::kHeaderSize), eax);
720   __ add(ebx, Immediate(Smi::FromInt(1)));
721
722   __ bind(&arguments_test);
723   __ cmp(ebx, ecx);
724   __ j(less, &arguments_loop, Label::kNear);
725
726   // Restore.
727   __ pop(eax);  // Address of arguments object.
728   __ pop(ebx);  // Parameter count.
729
730   // Return and remove the on-stack parameters.
731   __ ret(3 * kPointerSize);
732
733   // Do the runtime call to allocate the arguments object.
734   __ bind(&runtime);
735   __ pop(eax);  // Remove saved parameter count.
736   __ mov(Operand(esp, 1 * kPointerSize), ecx);  // Patch argument count.
737   __ TailCallRuntime(Runtime::kNewSloppyArguments, 3, 1);
738 }
739
740
741 void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
742   // esp[0] : return address
743   // esp[4] : number of parameters
744   // esp[8] : receiver displacement
745   // esp[12] : function
746
747   // Check if the calling frame is an arguments adaptor frame.
748   Label adaptor_frame, try_allocate, runtime;
749   __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
750   __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
751   __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
752   __ j(equal, &adaptor_frame, Label::kNear);
753
754   // Get the length from the frame.
755   __ mov(ecx, Operand(esp, 1 * kPointerSize));
756   __ jmp(&try_allocate, Label::kNear);
757
758   // Patch the arguments.length and the parameters pointer.
759   __ bind(&adaptor_frame);
760   __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
761
762   if (has_new_target()) {
763     // Subtract 1 from smi-tagged arguments count.
764     __ sub(ecx, Immediate(2));
765   }
766
767   __ lea(edx, Operand(edx, ecx, times_2,
768                       StandardFrameConstants::kCallerSPOffset));
769   __ mov(Operand(esp, 1 * kPointerSize), ecx);
770   __ mov(Operand(esp, 2 * kPointerSize), edx);
771
772   // Try the new space allocation. Start out with computing the size of
773   // the arguments object and the elements array.
774   Label add_arguments_object;
775   __ bind(&try_allocate);
776   __ test(ecx, ecx);
777   __ j(zero, &add_arguments_object, Label::kNear);
778   __ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize));
779   __ bind(&add_arguments_object);
780   __ add(ecx, Immediate(Heap::kStrictArgumentsObjectSize));
781
782   // Do the allocation of both objects in one go.
783   __ Allocate(ecx, eax, edx, ebx, &runtime, TAG_OBJECT);
784
785   // Get the arguments map from the current native context.
786   __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
787   __ mov(edi, FieldOperand(edi, GlobalObject::kNativeContextOffset));
788   const int offset = Context::SlotOffset(Context::STRICT_ARGUMENTS_MAP_INDEX);
789   __ mov(edi, Operand(edi, offset));
790
791   __ mov(FieldOperand(eax, JSObject::kMapOffset), edi);
792   __ mov(FieldOperand(eax, JSObject::kPropertiesOffset),
793          masm->isolate()->factory()->empty_fixed_array());
794   __ mov(FieldOperand(eax, JSObject::kElementsOffset),
795          masm->isolate()->factory()->empty_fixed_array());
796
797   // Get the length (smi tagged) and set that as an in-object property too.
798   STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
799   __ mov(ecx, Operand(esp, 1 * kPointerSize));
800   __ AssertSmi(ecx);
801   __ mov(FieldOperand(eax, JSObject::kHeaderSize +
802                       Heap::kArgumentsLengthIndex * kPointerSize),
803          ecx);
804
805   // If there are no actual arguments, we're done.
806   Label done;
807   __ test(ecx, ecx);
808   __ j(zero, &done, Label::kNear);
809
810   // Get the parameters pointer from the stack.
811   __ mov(edx, Operand(esp, 2 * kPointerSize));
812
813   // Set up the elements pointer in the allocated arguments object and
814   // initialize the header in the elements fixed array.
815   __ lea(edi, Operand(eax, Heap::kStrictArgumentsObjectSize));
816   __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi);
817   __ mov(FieldOperand(edi, FixedArray::kMapOffset),
818          Immediate(isolate()->factory()->fixed_array_map()));
819
820   __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx);
821   // Untag the length for the loop below.
822   __ SmiUntag(ecx);
823
824   // Copy the fixed array slots.
825   Label loop;
826   __ bind(&loop);
827   __ mov(ebx, Operand(edx, -1 * kPointerSize));  // Skip receiver.
828   __ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx);
829   __ add(edi, Immediate(kPointerSize));
830   __ sub(edx, Immediate(kPointerSize));
831   __ dec(ecx);
832   __ j(not_zero, &loop);
833
834   // Return and remove the on-stack parameters.
835   __ bind(&done);
836   __ ret(3 * kPointerSize);
837
838   // Do the runtime call to allocate the arguments object.
839   __ bind(&runtime);
840   __ TailCallRuntime(Runtime::kNewStrictArguments, 3, 1);
841 }
842
843
844 void RestParamAccessStub::GenerateNew(MacroAssembler* masm) {
845   // esp[0] : return address
846   // esp[4] : index of rest parameter
847   // esp[8] : number of parameters
848   // esp[12] : receiver displacement
849
850   // Check if the calling frame is an arguments adaptor frame.
851   Label runtime;
852   __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
853   __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset));
854   __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
855   __ j(not_equal, &runtime);
856
857   // Patch the arguments.length and the parameters pointer.
858   __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset));
859   __ mov(Operand(esp, 2 * kPointerSize), ecx);
860   __ lea(edx, Operand(edx, ecx, times_2,
861                       StandardFrameConstants::kCallerSPOffset));
862   __ mov(Operand(esp, 3 * kPointerSize), edx);
863
864   __ bind(&runtime);
865   __ TailCallRuntime(Runtime::kNewRestParam, 3, 1);
866 }
867
868
869 void RegExpExecStub::Generate(MacroAssembler* masm) {
870   // Just jump directly to runtime if native RegExp is not selected at compile
871   // time or if regexp entry in generated code is turned off runtime switch or
872   // at compilation.
873 #ifdef V8_INTERPRETED_REGEXP
874   __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
875 #else  // V8_INTERPRETED_REGEXP
876
877   // Stack frame on entry.
878   //  esp[0]: return address
879   //  esp[4]: last_match_info (expected JSArray)
880   //  esp[8]: previous index
881   //  esp[12]: subject string
882   //  esp[16]: JSRegExp object
883
884   static const int kLastMatchInfoOffset = 1 * kPointerSize;
885   static const int kPreviousIndexOffset = 2 * kPointerSize;
886   static const int kSubjectOffset = 3 * kPointerSize;
887   static const int kJSRegExpOffset = 4 * kPointerSize;
888
889   Label runtime;
890   Factory* factory = isolate()->factory();
891
892   // Ensure that a RegExp stack is allocated.
893   ExternalReference address_of_regexp_stack_memory_address =
894       ExternalReference::address_of_regexp_stack_memory_address(isolate());
895   ExternalReference address_of_regexp_stack_memory_size =
896       ExternalReference::address_of_regexp_stack_memory_size(isolate());
897   __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size));
898   __ test(ebx, ebx);
899   __ j(zero, &runtime);
900
901   // Check that the first argument is a JSRegExp object.
902   __ mov(eax, Operand(esp, kJSRegExpOffset));
903   STATIC_ASSERT(kSmiTag == 0);
904   __ JumpIfSmi(eax, &runtime);
905   __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx);
906   __ j(not_equal, &runtime);
907
908   // Check that the RegExp has been compiled (data contains a fixed array).
909   __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset));
910   if (FLAG_debug_code) {
911     __ test(ecx, Immediate(kSmiTagMask));
912     __ Check(not_zero, kUnexpectedTypeForRegExpDataFixedArrayExpected);
913     __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx);
914     __ Check(equal, kUnexpectedTypeForRegExpDataFixedArrayExpected);
915   }
916
917   // ecx: RegExp data (FixedArray)
918   // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
919   __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset));
920   __ cmp(ebx, Immediate(Smi::FromInt(JSRegExp::IRREGEXP)));
921   __ j(not_equal, &runtime);
922
923   // ecx: RegExp data (FixedArray)
924   // Check that the number of captures fit in the static offsets vector buffer.
925   __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset));
926   // Check (number_of_captures + 1) * 2 <= offsets vector size
927   // Or          number_of_captures * 2 <= offsets vector size - 2
928   // Multiplying by 2 comes for free since edx is smi-tagged.
929   STATIC_ASSERT(kSmiTag == 0);
930   STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
931   STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2);
932   __ cmp(edx, Isolate::kJSRegexpStaticOffsetsVectorSize - 2);
933   __ j(above, &runtime);
934
935   // Reset offset for possibly sliced string.
936   __ Move(edi, Immediate(0));
937   __ mov(eax, Operand(esp, kSubjectOffset));
938   __ JumpIfSmi(eax, &runtime);
939   __ mov(edx, eax);  // Make a copy of the original subject string.
940   __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
941   __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
942
943   // eax: subject string
944   // edx: subject string
945   // ebx: subject string instance type
946   // ecx: RegExp data (FixedArray)
947   // Handle subject string according to its encoding and representation:
948   // (1) Sequential two byte?  If yes, go to (9).
949   // (2) Sequential one byte?  If yes, go to (6).
950   // (3) Anything but sequential or cons?  If yes, go to (7).
951   // (4) Cons string.  If the string is flat, replace subject with first string.
952   //     Otherwise bailout.
953   // (5a) Is subject sequential two byte?  If yes, go to (9).
954   // (5b) Is subject external?  If yes, go to (8).
955   // (6) One byte sequential.  Load regexp code for one byte.
956   // (E) Carry on.
957   /// [...]
958
959   // Deferred code at the end of the stub:
960   // (7) Not a long external string?  If yes, go to (10).
961   // (8) External string.  Make it, offset-wise, look like a sequential string.
962   // (8a) Is the external string one byte?  If yes, go to (6).
963   // (9) Two byte sequential.  Load regexp code for one byte. Go to (E).
964   // (10) Short external string or not a string?  If yes, bail out to runtime.
965   // (11) Sliced string.  Replace subject with parent. Go to (5a).
966
967   Label seq_one_byte_string /* 6 */, seq_two_byte_string /* 9 */,
968         external_string /* 8 */, check_underlying /* 5a */,
969         not_seq_nor_cons /* 7 */, check_code /* E */,
970         not_long_external /* 10 */;
971
972   // (1) Sequential two byte?  If yes, go to (9).
973   __ and_(ebx, kIsNotStringMask |
974                kStringRepresentationMask |
975                kStringEncodingMask |
976                kShortExternalStringMask);
977   STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0);
978   __ j(zero, &seq_two_byte_string);  // Go to (9).
979
980   // (2) Sequential one byte?  If yes, go to (6).
981   // Any other sequential string must be one byte.
982   __ and_(ebx, Immediate(kIsNotStringMask |
983                          kStringRepresentationMask |
984                          kShortExternalStringMask));
985   __ j(zero, &seq_one_byte_string, Label::kNear);  // Go to (6).
986
987   // (3) Anything but sequential or cons?  If yes, go to (7).
988   // We check whether the subject string is a cons, since sequential strings
989   // have already been covered.
990   STATIC_ASSERT(kConsStringTag < kExternalStringTag);
991   STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
992   STATIC_ASSERT(kIsNotStringMask > kExternalStringTag);
993   STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag);
994   __ cmp(ebx, Immediate(kExternalStringTag));
995   __ j(greater_equal, &not_seq_nor_cons);  // Go to (7).
996
997   // (4) Cons string.  Check that it's flat.
998   // Replace subject with first string and reload instance type.
999   __ cmp(FieldOperand(eax, ConsString::kSecondOffset), factory->empty_string());
1000   __ j(not_equal, &runtime);
1001   __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset));
1002   __ bind(&check_underlying);
1003   __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
1004   __ mov(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
1005
1006   // (5a) Is subject sequential two byte?  If yes, go to (9).
1007   __ test_b(ebx, kStringRepresentationMask | kStringEncodingMask);
1008   STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0);
1009   __ j(zero, &seq_two_byte_string);  // Go to (9).
1010   // (5b) Is subject external?  If yes, go to (8).
1011   __ test_b(ebx, kStringRepresentationMask);
1012   // The underlying external string is never a short external string.
1013   STATIC_ASSERT(ExternalString::kMaxShortLength < ConsString::kMinLength);
1014   STATIC_ASSERT(ExternalString::kMaxShortLength < SlicedString::kMinLength);
1015   __ j(not_zero, &external_string);  // Go to (8).
1016
1017   // eax: sequential subject string (or look-alike, external string)
1018   // edx: original subject string
1019   // ecx: RegExp data (FixedArray)
1020   // (6) One byte sequential.  Load regexp code for one byte.
1021   __ bind(&seq_one_byte_string);
1022   // Load previous index and check range before edx is overwritten.  We have
1023   // to use edx instead of eax here because it might have been only made to
1024   // look like a sequential string when it actually is an external string.
1025   __ mov(ebx, Operand(esp, kPreviousIndexOffset));
1026   __ JumpIfNotSmi(ebx, &runtime);
1027   __ cmp(ebx, FieldOperand(edx, String::kLengthOffset));
1028   __ j(above_equal, &runtime);
1029   __ mov(edx, FieldOperand(ecx, JSRegExp::kDataOneByteCodeOffset));
1030   __ Move(ecx, Immediate(1));  // Type is one byte.
1031
1032   // (E) Carry on.  String handling is done.
1033   __ bind(&check_code);
1034   // edx: irregexp code
1035   // Check that the irregexp code has been generated for the actual string
1036   // encoding. If it has, the field contains a code object otherwise it contains
1037   // a smi (code flushing support).
1038   __ JumpIfSmi(edx, &runtime);
1039
1040   // eax: subject string
1041   // ebx: previous index (smi)
1042   // edx: code
1043   // ecx: encoding of subject string (1 if one_byte, 0 if two_byte);
1044   // All checks done. Now push arguments for native regexp code.
1045   Counters* counters = isolate()->counters();
1046   __ IncrementCounter(counters->regexp_entry_native(), 1);
1047
1048   // Isolates: note we add an additional parameter here (isolate pointer).
1049   static const int kRegExpExecuteArguments = 9;
1050   __ EnterApiExitFrame(kRegExpExecuteArguments);
1051
1052   // Argument 9: Pass current isolate address.
1053   __ mov(Operand(esp, 8 * kPointerSize),
1054       Immediate(ExternalReference::isolate_address(isolate())));
1055
1056   // Argument 8: Indicate that this is a direct call from JavaScript.
1057   __ mov(Operand(esp, 7 * kPointerSize), Immediate(1));
1058
1059   // Argument 7: Start (high end) of backtracking stack memory area.
1060   __ mov(esi, Operand::StaticVariable(address_of_regexp_stack_memory_address));
1061   __ add(esi, Operand::StaticVariable(address_of_regexp_stack_memory_size));
1062   __ mov(Operand(esp, 6 * kPointerSize), esi);
1063
1064   // Argument 6: Set the number of capture registers to zero to force global
1065   // regexps to behave as non-global.  This does not affect non-global regexps.
1066   __ mov(Operand(esp, 5 * kPointerSize), Immediate(0));
1067
1068   // Argument 5: static offsets vector buffer.
1069   __ mov(Operand(esp, 4 * kPointerSize),
1070          Immediate(ExternalReference::address_of_static_offsets_vector(
1071              isolate())));
1072
1073   // Argument 2: Previous index.
1074   __ SmiUntag(ebx);
1075   __ mov(Operand(esp, 1 * kPointerSize), ebx);
1076
1077   // Argument 1: Original subject string.
1078   // The original subject is in the previous stack frame. Therefore we have to
1079   // use ebp, which points exactly to one pointer size below the previous esp.
1080   // (Because creating a new stack frame pushes the previous ebp onto the stack
1081   // and thereby moves up esp by one kPointerSize.)
1082   __ mov(esi, Operand(ebp, kSubjectOffset + kPointerSize));
1083   __ mov(Operand(esp, 0 * kPointerSize), esi);
1084
1085   // esi: original subject string
1086   // eax: underlying subject string
1087   // ebx: previous index
1088   // ecx: encoding of subject string (1 if one_byte 0 if two_byte);
1089   // edx: code
1090   // Argument 4: End of string data
1091   // Argument 3: Start of string data
1092   // Prepare start and end index of the input.
1093   // Load the length from the original sliced string if that is the case.
1094   __ mov(esi, FieldOperand(esi, String::kLengthOffset));
1095   __ add(esi, edi);  // Calculate input end wrt offset.
1096   __ SmiUntag(edi);
1097   __ add(ebx, edi);  // Calculate input start wrt offset.
1098
1099   // ebx: start index of the input string
1100   // esi: end index of the input string
1101   Label setup_two_byte, setup_rest;
1102   __ test(ecx, ecx);
1103   __ j(zero, &setup_two_byte, Label::kNear);
1104   __ SmiUntag(esi);
1105   __ lea(ecx, FieldOperand(eax, esi, times_1, SeqOneByteString::kHeaderSize));
1106   __ mov(Operand(esp, 3 * kPointerSize), ecx);  // Argument 4.
1107   __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqOneByteString::kHeaderSize));
1108   __ mov(Operand(esp, 2 * kPointerSize), ecx);  // Argument 3.
1109   __ jmp(&setup_rest, Label::kNear);
1110
1111   __ bind(&setup_two_byte);
1112   STATIC_ASSERT(kSmiTag == 0);
1113   STATIC_ASSERT(kSmiTagSize == 1);  // esi is smi (powered by 2).
1114   __ lea(ecx, FieldOperand(eax, esi, times_1, SeqTwoByteString::kHeaderSize));
1115   __ mov(Operand(esp, 3 * kPointerSize), ecx);  // Argument 4.
1116   __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize));
1117   __ mov(Operand(esp, 2 * kPointerSize), ecx);  // Argument 3.
1118
1119   __ bind(&setup_rest);
1120
1121   // Locate the code entry and call it.
1122   __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
1123   __ call(edx);
1124
1125   // Drop arguments and come back to JS mode.
1126   __ LeaveApiExitFrame(true);
1127
1128   // Check the result.
1129   Label success;
1130   __ cmp(eax, 1);
1131   // We expect exactly one result since we force the called regexp to behave
1132   // as non-global.
1133   __ j(equal, &success);
1134   Label failure;
1135   __ cmp(eax, NativeRegExpMacroAssembler::FAILURE);
1136   __ j(equal, &failure);
1137   __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION);
1138   // If not exception it can only be retry. Handle that in the runtime system.
1139   __ j(not_equal, &runtime);
1140   // Result must now be exception. If there is no pending exception already a
1141   // stack overflow (on the backtrack stack) was detected in RegExp code but
1142   // haven't created the exception yet. Handle that in the runtime system.
1143   // TODO(592): Rerunning the RegExp to get the stack overflow exception.
1144   ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
1145                                       isolate());
1146   __ mov(edx, Immediate(isolate()->factory()->the_hole_value()));
1147   __ mov(eax, Operand::StaticVariable(pending_exception));
1148   __ cmp(edx, eax);
1149   __ j(equal, &runtime);
1150
1151   // For exception, throw the exception again.
1152   __ TailCallRuntime(Runtime::kRegExpExecReThrow, 4, 1);
1153
1154   __ bind(&failure);
1155   // For failure to match, return null.
1156   __ mov(eax, factory->null_value());
1157   __ ret(4 * kPointerSize);
1158
1159   // Load RegExp data.
1160   __ bind(&success);
1161   __ mov(eax, Operand(esp, kJSRegExpOffset));
1162   __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset));
1163   __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset));
1164   // Calculate number of capture registers (number_of_captures + 1) * 2.
1165   STATIC_ASSERT(kSmiTag == 0);
1166   STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
1167   __ add(edx, Immediate(2));  // edx was a smi.
1168
1169   // edx: Number of capture registers
1170   // Load last_match_info which is still known to be a fast case JSArray.
1171   // Check that the fourth object is a JSArray object.
1172   __ mov(eax, Operand(esp, kLastMatchInfoOffset));
1173   __ JumpIfSmi(eax, &runtime);
1174   __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
1175   __ j(not_equal, &runtime);
1176   // Check that the JSArray is in fast case.
1177   __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset));
1178   __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset));
1179   __ cmp(eax, factory->fixed_array_map());
1180   __ j(not_equal, &runtime);
1181   // Check that the last match info has space for the capture registers and the
1182   // additional information.
1183   __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset));
1184   __ SmiUntag(eax);
1185   __ sub(eax, Immediate(RegExpImpl::kLastMatchOverhead));
1186   __ cmp(edx, eax);
1187   __ j(greater, &runtime);
1188
1189   // ebx: last_match_info backing store (FixedArray)
1190   // edx: number of capture registers
1191   // Store the capture count.
1192   __ SmiTag(edx);  // Number of capture registers to smi.
1193   __ mov(FieldOperand(ebx, RegExpImpl::kLastCaptureCountOffset), edx);
1194   __ SmiUntag(edx);  // Number of capture registers back from smi.
1195   // Store last subject and last input.
1196   __ mov(eax, Operand(esp, kSubjectOffset));
1197   __ mov(ecx, eax);
1198   __ mov(FieldOperand(ebx, RegExpImpl::kLastSubjectOffset), eax);
1199   __ RecordWriteField(ebx, RegExpImpl::kLastSubjectOffset, eax, edi,
1200                       kDontSaveFPRegs);
1201   __ mov(eax, ecx);
1202   __ mov(FieldOperand(ebx, RegExpImpl::kLastInputOffset), eax);
1203   __ RecordWriteField(ebx, RegExpImpl::kLastInputOffset, eax, edi,
1204                       kDontSaveFPRegs);
1205
1206   // Get the static offsets vector filled by the native regexp code.
1207   ExternalReference address_of_static_offsets_vector =
1208       ExternalReference::address_of_static_offsets_vector(isolate());
1209   __ mov(ecx, Immediate(address_of_static_offsets_vector));
1210
1211   // ebx: last_match_info backing store (FixedArray)
1212   // ecx: offsets vector
1213   // edx: number of capture registers
1214   Label next_capture, done;
1215   // Capture register counter starts from number of capture registers and
1216   // counts down until wraping after zero.
1217   __ bind(&next_capture);
1218   __ sub(edx, Immediate(1));
1219   __ j(negative, &done, Label::kNear);
1220   // Read the value from the static offsets vector buffer.
1221   __ mov(edi, Operand(ecx, edx, times_int_size, 0));
1222   __ SmiTag(edi);
1223   // Store the smi value in the last match info.
1224   __ mov(FieldOperand(ebx,
1225                       edx,
1226                       times_pointer_size,
1227                       RegExpImpl::kFirstCaptureOffset),
1228                       edi);
1229   __ jmp(&next_capture);
1230   __ bind(&done);
1231
1232   // Return last match info.
1233   __ mov(eax, Operand(esp, kLastMatchInfoOffset));
1234   __ ret(4 * kPointerSize);
1235
1236   // Do the runtime call to execute the regexp.
1237   __ bind(&runtime);
1238   __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
1239
1240   // Deferred code for string handling.
1241   // (7) Not a long external string?  If yes, go to (10).
1242   __ bind(&not_seq_nor_cons);
1243   // Compare flags are still set from (3).
1244   __ j(greater, &not_long_external, Label::kNear);  // Go to (10).
1245
1246   // (8) External string.  Short external strings have been ruled out.
1247   __ bind(&external_string);
1248   // Reload instance type.
1249   __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
1250   __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
1251   if (FLAG_debug_code) {
1252     // Assert that we do not have a cons or slice (indirect strings) here.
1253     // Sequential strings have already been ruled out.
1254     __ test_b(ebx, kIsIndirectStringMask);
1255     __ Assert(zero, kExternalStringExpectedButNotFound);
1256   }
1257   __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset));
1258   // Move the pointer so that offset-wise, it looks like a sequential string.
1259   STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
1260   __ sub(eax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
1261   STATIC_ASSERT(kTwoByteStringTag == 0);
1262   // (8a) Is the external string one byte?  If yes, go to (6).
1263   __ test_b(ebx, kStringEncodingMask);
1264   __ j(not_zero, &seq_one_byte_string);  // Goto (6).
1265
1266   // eax: sequential subject string (or look-alike, external string)
1267   // edx: original subject string
1268   // ecx: RegExp data (FixedArray)
1269   // (9) Two byte sequential.  Load regexp code for one byte. Go to (E).
1270   __ bind(&seq_two_byte_string);
1271   // Load previous index and check range before edx is overwritten.  We have
1272   // to use edx instead of eax here because it might have been only made to
1273   // look like a sequential string when it actually is an external string.
1274   __ mov(ebx, Operand(esp, kPreviousIndexOffset));
1275   __ JumpIfNotSmi(ebx, &runtime);
1276   __ cmp(ebx, FieldOperand(edx, String::kLengthOffset));
1277   __ j(above_equal, &runtime);
1278   __ mov(edx, FieldOperand(ecx, JSRegExp::kDataUC16CodeOffset));
1279   __ Move(ecx, Immediate(0));  // Type is two byte.
1280   __ jmp(&check_code);  // Go to (E).
1281
1282   // (10) Not a string or a short external string?  If yes, bail out to runtime.
1283   __ bind(&not_long_external);
1284   // Catch non-string subject or short external string.
1285   STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0);
1286   __ test(ebx, Immediate(kIsNotStringMask | kShortExternalStringTag));
1287   __ j(not_zero, &runtime);
1288
1289   // (11) Sliced string.  Replace subject with parent.  Go to (5a).
1290   // Load offset into edi and replace subject string with parent.
1291   __ mov(edi, FieldOperand(eax, SlicedString::kOffsetOffset));
1292   __ mov(eax, FieldOperand(eax, SlicedString::kParentOffset));
1293   __ jmp(&check_underlying);  // Go to (5a).
1294 #endif  // V8_INTERPRETED_REGEXP
1295 }
1296
1297
1298 static int NegativeComparisonResult(Condition cc) {
1299   DCHECK(cc != equal);
1300   DCHECK((cc == less) || (cc == less_equal)
1301       || (cc == greater) || (cc == greater_equal));
1302   return (cc == greater || cc == greater_equal) ? LESS : GREATER;
1303 }
1304
1305
1306 static void CheckInputType(MacroAssembler* masm, Register input,
1307                            CompareICState::State expected, Label* fail) {
1308   Label ok;
1309   if (expected == CompareICState::SMI) {
1310     __ JumpIfNotSmi(input, fail);
1311   } else if (expected == CompareICState::NUMBER) {
1312     __ JumpIfSmi(input, &ok);
1313     __ cmp(FieldOperand(input, HeapObject::kMapOffset),
1314            Immediate(masm->isolate()->factory()->heap_number_map()));
1315     __ j(not_equal, fail);
1316   }
1317   // We could be strict about internalized/non-internalized here, but as long as
1318   // hydrogen doesn't care, the stub doesn't have to care either.
1319   __ bind(&ok);
1320 }
1321
1322
1323 static void BranchIfNotInternalizedString(MacroAssembler* masm,
1324                                           Label* label,
1325                                           Register object,
1326                                           Register scratch) {
1327   __ JumpIfSmi(object, label);
1328   __ mov(scratch, FieldOperand(object, HeapObject::kMapOffset));
1329   __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
1330   STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
1331   __ test(scratch, Immediate(kIsNotStringMask | kIsNotInternalizedMask));
1332   __ j(not_zero, label);
1333 }
1334
1335
1336 void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
1337   Label check_unequal_objects;
1338   Condition cc = GetCondition();
1339
1340   Label miss;
1341   CheckInputType(masm, edx, left(), &miss);
1342   CheckInputType(masm, eax, right(), &miss);
1343
1344   // Compare two smis.
1345   Label non_smi, smi_done;
1346   __ mov(ecx, edx);
1347   __ or_(ecx, eax);
1348   __ JumpIfNotSmi(ecx, &non_smi, Label::kNear);
1349   __ sub(edx, eax);  // Return on the result of the subtraction.
1350   __ j(no_overflow, &smi_done, Label::kNear);
1351   __ not_(edx);  // Correct sign in case of overflow. edx is never 0 here.
1352   __ bind(&smi_done);
1353   __ mov(eax, edx);
1354   __ ret(0);
1355   __ bind(&non_smi);
1356
1357   // NOTICE! This code is only reached after a smi-fast-case check, so
1358   // it is certain that at least one operand isn't a smi.
1359
1360   // Identical objects can be compared fast, but there are some tricky cases
1361   // for NaN and undefined.
1362   Label generic_heap_number_comparison;
1363   {
1364     Label not_identical;
1365     __ cmp(eax, edx);
1366     __ j(not_equal, &not_identical);
1367
1368     if (cc != equal) {
1369       // Check for undefined.  undefined OP undefined is false even though
1370       // undefined == undefined.
1371       Label check_for_nan;
1372       __ cmp(edx, isolate()->factory()->undefined_value());
1373       __ j(not_equal, &check_for_nan, Label::kNear);
1374       __ Move(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
1375       __ ret(0);
1376       __ bind(&check_for_nan);
1377     }
1378
1379     // Test for NaN. Compare heap numbers in a general way,
1380     // to hanlde NaNs correctly.
1381     __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
1382            Immediate(isolate()->factory()->heap_number_map()));
1383     __ j(equal, &generic_heap_number_comparison, Label::kNear);
1384     if (cc != equal) {
1385       // Call runtime on identical JSObjects.  Otherwise return equal.
1386       __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
1387       __ j(above_equal, &not_identical);
1388     }
1389     __ Move(eax, Immediate(Smi::FromInt(EQUAL)));
1390     __ ret(0);
1391
1392
1393     __ bind(&not_identical);
1394   }
1395
1396   // Strict equality can quickly decide whether objects are equal.
1397   // Non-strict object equality is slower, so it is handled later in the stub.
1398   if (cc == equal && strict()) {
1399     Label slow;  // Fallthrough label.
1400     Label not_smis;
1401     // If we're doing a strict equality comparison, we don't have to do
1402     // type conversion, so we generate code to do fast comparison for objects
1403     // and oddballs. Non-smi numbers and strings still go through the usual
1404     // slow-case code.
1405     // If either is a Smi (we know that not both are), then they can only
1406     // be equal if the other is a HeapNumber. If so, use the slow case.
1407     STATIC_ASSERT(kSmiTag == 0);
1408     DCHECK_EQ(static_cast<Smi*>(0), Smi::FromInt(0));
1409     __ mov(ecx, Immediate(kSmiTagMask));
1410     __ and_(ecx, eax);
1411     __ test(ecx, edx);
1412     __ j(not_zero, &not_smis, Label::kNear);
1413     // One operand is a smi.
1414
1415     // Check whether the non-smi is a heap number.
1416     STATIC_ASSERT(kSmiTagMask == 1);
1417     // ecx still holds eax & kSmiTag, which is either zero or one.
1418     __ sub(ecx, Immediate(0x01));
1419     __ mov(ebx, edx);
1420     __ xor_(ebx, eax);
1421     __ and_(ebx, ecx);  // ebx holds either 0 or eax ^ edx.
1422     __ xor_(ebx, eax);
1423     // if eax was smi, ebx is now edx, else eax.
1424
1425     // Check if the non-smi operand is a heap number.
1426     __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
1427            Immediate(isolate()->factory()->heap_number_map()));
1428     // If heap number, handle it in the slow case.
1429     __ j(equal, &slow, Label::kNear);
1430     // Return non-equal (ebx is not zero)
1431     __ mov(eax, ebx);
1432     __ ret(0);
1433
1434     __ bind(&not_smis);
1435     // If either operand is a JSObject or an oddball value, then they are not
1436     // equal since their pointers are different
1437     // There is no test for undetectability in strict equality.
1438
1439     // Get the type of the first operand.
1440     // If the first object is a JS object, we have done pointer comparison.
1441     Label first_non_object;
1442     STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
1443     __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
1444     __ j(below, &first_non_object, Label::kNear);
1445
1446     // Return non-zero (eax is not zero)
1447     Label return_not_equal;
1448     STATIC_ASSERT(kHeapObjectTag != 0);
1449     __ bind(&return_not_equal);
1450     __ ret(0);
1451
1452     __ bind(&first_non_object);
1453     // Check for oddballs: true, false, null, undefined.
1454     __ CmpInstanceType(ecx, ODDBALL_TYPE);
1455     __ j(equal, &return_not_equal);
1456
1457     __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ecx);
1458     __ j(above_equal, &return_not_equal);
1459
1460     // Check for oddballs: true, false, null, undefined.
1461     __ CmpInstanceType(ecx, ODDBALL_TYPE);
1462     __ j(equal, &return_not_equal);
1463
1464     // Fall through to the general case.
1465     __ bind(&slow);
1466   }
1467
1468   // Generate the number comparison code.
1469   Label non_number_comparison;
1470   Label unordered;
1471   __ bind(&generic_heap_number_comparison);
1472   FloatingPointHelper::CheckFloatOperands(
1473       masm, &non_number_comparison, ebx);
1474   FloatingPointHelper::LoadFloatOperand(masm, eax);
1475   FloatingPointHelper::LoadFloatOperand(masm, edx);
1476   __ FCmp();
1477
1478   // Don't base result on EFLAGS when a NaN is involved.
1479   __ j(parity_even, &unordered, Label::kNear);
1480
1481   Label below_label, above_label;
1482   // Return a result of -1, 0, or 1, based on EFLAGS.
1483   __ j(below, &below_label, Label::kNear);
1484   __ j(above, &above_label, Label::kNear);
1485
1486   __ Move(eax, Immediate(0));
1487   __ ret(0);
1488
1489   __ bind(&below_label);
1490   __ mov(eax, Immediate(Smi::FromInt(-1)));
1491   __ ret(0);
1492
1493   __ bind(&above_label);
1494   __ mov(eax, Immediate(Smi::FromInt(1)));
1495   __ ret(0);
1496
1497   // If one of the numbers was NaN, then the result is always false.
1498   // The cc is never not-equal.
1499   __ bind(&unordered);
1500   DCHECK(cc != not_equal);
1501   if (cc == less || cc == less_equal) {
1502     __ mov(eax, Immediate(Smi::FromInt(1)));
1503   } else {
1504     __ mov(eax, Immediate(Smi::FromInt(-1)));
1505   }
1506   __ ret(0);
1507
1508   // The number comparison code did not provide a valid result.
1509   __ bind(&non_number_comparison);
1510
1511   // Fast negative check for internalized-to-internalized equality.
1512   Label check_for_strings;
1513   if (cc == equal) {
1514     BranchIfNotInternalizedString(masm, &check_for_strings, eax, ecx);
1515     BranchIfNotInternalizedString(masm, &check_for_strings, edx, ecx);
1516
1517     // We've already checked for object identity, so if both operands
1518     // are internalized they aren't equal. Register eax already holds a
1519     // non-zero value, which indicates not equal, so just return.
1520     __ ret(0);
1521   }
1522
1523   __ bind(&check_for_strings);
1524
1525   __ JumpIfNotBothSequentialOneByteStrings(edx, eax, ecx, ebx,
1526                                            &check_unequal_objects);
1527
1528   // Inline comparison of one-byte strings.
1529   if (cc == equal) {
1530     StringHelper::GenerateFlatOneByteStringEquals(masm, edx, eax, ecx, ebx);
1531   } else {
1532     StringHelper::GenerateCompareFlatOneByteStrings(masm, edx, eax, ecx, ebx,
1533                                                     edi);
1534   }
1535 #ifdef DEBUG
1536   __ Abort(kUnexpectedFallThroughFromStringComparison);
1537 #endif
1538
1539   __ bind(&check_unequal_objects);
1540   if (cc == equal && !strict()) {
1541     // Non-strict equality.  Objects are unequal if
1542     // they are both JSObjects and not undetectable,
1543     // and their pointers are different.
1544     Label not_both_objects;
1545     Label return_unequal;
1546     // At most one is a smi, so we can test for smi by adding the two.
1547     // A smi plus a heap object has the low bit set, a heap object plus
1548     // a heap object has the low bit clear.
1549     STATIC_ASSERT(kSmiTag == 0);
1550     STATIC_ASSERT(kSmiTagMask == 1);
1551     __ lea(ecx, Operand(eax, edx, times_1, 0));
1552     __ test(ecx, Immediate(kSmiTagMask));
1553     __ j(not_zero, &not_both_objects, Label::kNear);
1554     __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
1555     __ j(below, &not_both_objects, Label::kNear);
1556     __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ebx);
1557     __ j(below, &not_both_objects, Label::kNear);
1558     // We do not bail out after this point.  Both are JSObjects, and
1559     // they are equal if and only if both are undetectable.
1560     // The and of the undetectable flags is 1 if and only if they are equal.
1561     __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
1562               1 << Map::kIsUndetectable);
1563     __ j(zero, &return_unequal, Label::kNear);
1564     __ test_b(FieldOperand(ebx, Map::kBitFieldOffset),
1565               1 << Map::kIsUndetectable);
1566     __ j(zero, &return_unequal, Label::kNear);
1567     // The objects are both undetectable, so they both compare as the value
1568     // undefined, and are equal.
1569     __ Move(eax, Immediate(EQUAL));
1570     __ bind(&return_unequal);
1571     // Return non-equal by returning the non-zero object pointer in eax,
1572     // or return equal if we fell through to here.
1573     __ ret(0);  // rax, rdx were pushed
1574     __ bind(&not_both_objects);
1575   }
1576
1577   // Push arguments below the return address.
1578   __ pop(ecx);
1579   __ push(edx);
1580   __ push(eax);
1581
1582   // Figure out which native to call and setup the arguments.
1583   Builtins::JavaScript builtin;
1584   if (cc == equal) {
1585     builtin = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
1586   } else {
1587     builtin = Builtins::COMPARE;
1588     __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc))));
1589   }
1590
1591   // Restore return address on the stack.
1592   __ push(ecx);
1593
1594   // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
1595   // tagged as a small integer.
1596   __ InvokeBuiltin(builtin, JUMP_FUNCTION);
1597
1598   __ bind(&miss);
1599   GenerateMiss(masm);
1600 }
1601
1602
1603 static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) {
1604   // eax : number of arguments to the construct function
1605   // ebx : Feedback vector
1606   // edx : slot in feedback vector (Smi)
1607   // edi : the function to call
1608   FrameScope scope(masm, StackFrame::INTERNAL);
1609
1610   // Arguments register must be smi-tagged to call out.
1611   __ SmiTag(eax);
1612   __ push(eax);
1613   __ push(edi);
1614   __ push(edx);
1615   __ push(ebx);
1616
1617   __ CallStub(stub);
1618
1619   __ pop(ebx);
1620   __ pop(edx);
1621   __ pop(edi);
1622   __ pop(eax);
1623   __ SmiUntag(eax);
1624 }
1625
1626
1627 static void GenerateRecordCallTarget(MacroAssembler* masm) {
1628   // Cache the called function in a feedback vector slot.  Cache states
1629   // are uninitialized, monomorphic (indicated by a JSFunction), and
1630   // megamorphic.
1631   // eax : number of arguments to the construct function
1632   // ebx : Feedback vector
1633   // edx : slot in feedback vector (Smi)
1634   // edi : the function to call
1635   Isolate* isolate = masm->isolate();
1636   Label initialize, done, miss, megamorphic, not_array_function;
1637
1638   // Load the cache state into ecx.
1639   __ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size,
1640                            FixedArray::kHeaderSize));
1641
1642   // A monomorphic cache hit or an already megamorphic state: invoke the
1643   // function without changing the state.
1644   Label check_allocation_site;
1645   __ cmp(edi, FieldOperand(ecx, WeakCell::kValueOffset));
1646   __ j(equal, &done, Label::kFar);
1647   __ CompareRoot(ecx, Heap::kmegamorphic_symbolRootIndex);
1648   __ j(equal, &done, Label::kFar);
1649   __ CompareRoot(FieldOperand(ecx, 0), Heap::kWeakCellMapRootIndex);
1650   __ j(not_equal, FLAG_pretenuring_call_new ? &miss : &check_allocation_site);
1651
1652   // If edi is not equal to the weak cell value, and the weak cell value is
1653   // cleared, we have a new chance to become monomorphic.
1654   __ JumpIfSmi(FieldOperand(ecx, WeakCell::kValueOffset), &initialize);
1655   __ jmp(&megamorphic);
1656
1657   if (!FLAG_pretenuring_call_new) {
1658     __ bind(&check_allocation_site);
1659     // If we came here, we need to see if we are the array function.
1660     // If we didn't have a matching function, and we didn't find the megamorph
1661     // sentinel, then we have in the slot either some other function or an
1662     // AllocationSite. Do a map check on the object in ecx.
1663     __ CompareRoot(FieldOperand(ecx, 0), Heap::kAllocationSiteMapRootIndex);
1664     __ j(not_equal, &miss);
1665
1666     // Make sure the function is the Array() function
1667     __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, ecx);
1668     __ cmp(edi, ecx);
1669     __ j(not_equal, &megamorphic);
1670     __ jmp(&done, Label::kFar);
1671   }
1672
1673   __ bind(&miss);
1674
1675   // A monomorphic miss (i.e, here the cache is not uninitialized) goes
1676   // megamorphic.
1677   __ CompareRoot(ecx, Heap::kuninitialized_symbolRootIndex);
1678   __ j(equal, &initialize);
1679   // MegamorphicSentinel is an immortal immovable object (undefined) so no
1680   // write-barrier is needed.
1681   __ bind(&megamorphic);
1682   __ mov(
1683       FieldOperand(ebx, edx, times_half_pointer_size, FixedArray::kHeaderSize),
1684       Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate)));
1685   __ jmp(&done, Label::kFar);
1686
1687   // An uninitialized cache is patched with the function or sentinel to
1688   // indicate the ElementsKind if function is the Array constructor.
1689   __ bind(&initialize);
1690   if (!FLAG_pretenuring_call_new) {
1691     // Make sure the function is the Array() function
1692     __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, ecx);
1693     __ cmp(edi, ecx);
1694     __ j(not_equal, &not_array_function);
1695
1696     // The target function is the Array constructor,
1697     // Create an AllocationSite if we don't already have it, store it in the
1698     // slot.
1699     CreateAllocationSiteStub create_stub(isolate);
1700     CallStubInRecordCallTarget(masm, &create_stub);
1701     __ jmp(&done);
1702
1703     __ bind(&not_array_function);
1704   }
1705
1706   CreateWeakCellStub create_stub(isolate);
1707   CallStubInRecordCallTarget(masm, &create_stub);
1708   __ bind(&done);
1709 }
1710
1711
1712 static void EmitContinueIfStrictOrNative(MacroAssembler* masm, Label* cont) {
1713   // Do not transform the receiver for strict mode functions.
1714   __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1715   __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
1716             1 << SharedFunctionInfo::kStrictModeBitWithinByte);
1717   __ j(not_equal, cont);
1718
1719   // Do not transform the receiver for natives (shared already in ecx).
1720   __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset),
1721             1 << SharedFunctionInfo::kNativeBitWithinByte);
1722   __ j(not_equal, cont);
1723 }
1724
1725
1726 static void EmitSlowCase(Isolate* isolate,
1727                          MacroAssembler* masm,
1728                          int argc,
1729                          Label* non_function) {
1730   // Check for function proxy.
1731   __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
1732   __ j(not_equal, non_function);
1733   __ pop(ecx);
1734   __ push(edi);  // put proxy as additional argument under return address
1735   __ push(ecx);
1736   __ Move(eax, Immediate(argc + 1));
1737   __ Move(ebx, Immediate(0));
1738   __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
1739   {
1740     Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline();
1741     __ jmp(adaptor, RelocInfo::CODE_TARGET);
1742   }
1743
1744   // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
1745   // of the original receiver from the call site).
1746   __ bind(non_function);
1747   __ mov(Operand(esp, (argc + 1) * kPointerSize), edi);
1748   __ Move(eax, Immediate(argc));
1749   __ Move(ebx, Immediate(0));
1750   __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
1751   Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline();
1752   __ jmp(adaptor, RelocInfo::CODE_TARGET);
1753 }
1754
1755
1756 static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) {
1757   // Wrap the receiver and patch it back onto the stack.
1758   { FrameScope frame_scope(masm, StackFrame::INTERNAL);
1759     __ push(edi);
1760     __ push(eax);
1761     __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
1762     __ pop(edi);
1763   }
1764   __ mov(Operand(esp, (argc + 1) * kPointerSize), eax);
1765   __ jmp(cont);
1766 }
1767
1768
1769 static void CallFunctionNoFeedback(MacroAssembler* masm,
1770                                    int argc, bool needs_checks,
1771                                    bool call_as_method) {
1772   // edi : the function to call
1773   Label slow, non_function, wrap, cont;
1774
1775   if (needs_checks) {
1776     // Check that the function really is a JavaScript function.
1777     __ JumpIfSmi(edi, &non_function);
1778
1779     // Goto slow case if we do not have a function.
1780     __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
1781     __ j(not_equal, &slow);
1782   }
1783
1784   // Fast-case: Just invoke the function.
1785   ParameterCount actual(argc);
1786
1787   if (call_as_method) {
1788     if (needs_checks) {
1789       EmitContinueIfStrictOrNative(masm, &cont);
1790     }
1791
1792     // Load the receiver from the stack.
1793     __ mov(eax, Operand(esp, (argc + 1) * kPointerSize));
1794
1795     if (needs_checks) {
1796       __ JumpIfSmi(eax, &wrap);
1797
1798       __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
1799       __ j(below, &wrap);
1800     } else {
1801       __ jmp(&wrap);
1802     }
1803
1804     __ bind(&cont);
1805   }
1806
1807   __ InvokeFunction(edi, actual, JUMP_FUNCTION, NullCallWrapper());
1808
1809   if (needs_checks) {
1810     // Slow-case: Non-function called.
1811     __ bind(&slow);
1812     // (non_function is bound in EmitSlowCase)
1813     EmitSlowCase(masm->isolate(), masm, argc, &non_function);
1814   }
1815
1816   if (call_as_method) {
1817     __ bind(&wrap);
1818     EmitWrapCase(masm, argc, &cont);
1819   }
1820 }
1821
1822
1823 void CallFunctionStub::Generate(MacroAssembler* masm) {
1824   CallFunctionNoFeedback(masm, argc(), NeedsChecks(), CallAsMethod());
1825 }
1826
1827
1828 void CallConstructStub::Generate(MacroAssembler* masm) {
1829   // eax : number of arguments
1830   // ebx : feedback vector
1831   // edx : (only if ebx is not the megamorphic symbol) slot in feedback
1832   //       vector (Smi)
1833   // edi : constructor function
1834   Label slow, non_function_call;
1835
1836   // Check that function is not a smi.
1837   __ JumpIfSmi(edi, &non_function_call);
1838   // Check that function is a JSFunction.
1839   __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
1840   __ j(not_equal, &slow);
1841
1842   if (RecordCallTarget()) {
1843     GenerateRecordCallTarget(masm);
1844
1845     if (FLAG_pretenuring_call_new) {
1846       // Put the AllocationSite from the feedback vector into ebx.
1847       // By adding kPointerSize we encode that we know the AllocationSite
1848       // entry is at the feedback vector slot given by edx + 1.
1849       __ mov(ebx, FieldOperand(ebx, edx, times_half_pointer_size,
1850                                FixedArray::kHeaderSize + kPointerSize));
1851     } else {
1852       Label feedback_register_initialized;
1853       // Put the AllocationSite from the feedback vector into ebx, or undefined.
1854       __ mov(ebx, FieldOperand(ebx, edx, times_half_pointer_size,
1855                                FixedArray::kHeaderSize));
1856       Handle<Map> allocation_site_map =
1857           isolate()->factory()->allocation_site_map();
1858       __ cmp(FieldOperand(ebx, 0), Immediate(allocation_site_map));
1859       __ j(equal, &feedback_register_initialized);
1860       __ mov(ebx, isolate()->factory()->undefined_value());
1861       __ bind(&feedback_register_initialized);
1862     }
1863
1864     __ AssertUndefinedOrAllocationSite(ebx);
1865   }
1866
1867   if (IsSuperConstructorCall()) {
1868     __ mov(edx, Operand(esp, eax, times_pointer_size, 2 * kPointerSize));
1869   } else {
1870     // Pass original constructor to construct stub.
1871     __ mov(edx, edi);
1872   }
1873
1874   // Jump to the function-specific construct stub.
1875   Register jmp_reg = ecx;
1876   __ mov(jmp_reg, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1877   __ mov(jmp_reg, FieldOperand(jmp_reg,
1878                                SharedFunctionInfo::kConstructStubOffset));
1879   __ lea(jmp_reg, FieldOperand(jmp_reg, Code::kHeaderSize));
1880   __ jmp(jmp_reg);
1881
1882   // edi: called object
1883   // eax: number of arguments
1884   // ecx: object map
1885   Label do_call;
1886   __ bind(&slow);
1887   __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
1888   __ j(not_equal, &non_function_call);
1889   __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR);
1890   __ jmp(&do_call);
1891
1892   __ bind(&non_function_call);
1893   __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
1894   __ bind(&do_call);
1895   // Set expected number of arguments to zero (not changing eax).
1896   __ Move(ebx, Immediate(0));
1897   Handle<Code> arguments_adaptor =
1898       isolate()->builtins()->ArgumentsAdaptorTrampoline();
1899   __ jmp(arguments_adaptor, RelocInfo::CODE_TARGET);
1900 }
1901
1902
1903 static void EmitLoadTypeFeedbackVector(MacroAssembler* masm, Register vector) {
1904   __ mov(vector, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1905   __ mov(vector, FieldOperand(vector, JSFunction::kSharedFunctionInfoOffset));
1906   __ mov(vector, FieldOperand(vector,
1907                               SharedFunctionInfo::kFeedbackVectorOffset));
1908 }
1909
1910
1911 void CallIC_ArrayStub::Generate(MacroAssembler* masm) {
1912   // edi - function
1913   // edx - slot id
1914   // ebx - vector
1915   Label miss;
1916   int argc = arg_count();
1917   ParameterCount actual(argc);
1918
1919   __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, ecx);
1920   __ cmp(edi, ecx);
1921   __ j(not_equal, &miss);
1922
1923   __ mov(eax, arg_count());
1924   __ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size,
1925                            FixedArray::kHeaderSize));
1926
1927   // Verify that ecx contains an AllocationSite
1928   Factory* factory = masm->isolate()->factory();
1929   __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
1930          factory->allocation_site_map());
1931   __ j(not_equal, &miss);
1932
1933   __ mov(ebx, ecx);
1934   __ mov(edx, edi);
1935   ArrayConstructorStub stub(masm->isolate(), arg_count());
1936   __ TailCallStub(&stub);
1937
1938   __ bind(&miss);
1939   GenerateMiss(masm);
1940
1941   // The slow case, we need this no matter what to complete a call after a miss.
1942   CallFunctionNoFeedback(masm,
1943                          arg_count(),
1944                          true,
1945                          CallAsMethod());
1946
1947   // Unreachable.
1948   __ int3();
1949 }
1950
1951
1952 void CallICStub::Generate(MacroAssembler* masm) {
1953   // edi - function
1954   // edx - slot id
1955   // ebx - vector
1956   Isolate* isolate = masm->isolate();
1957   const int with_types_offset =
1958       FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
1959   const int generic_offset =
1960       FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
1961   Label extra_checks_or_miss, slow_start;
1962   Label slow, non_function, wrap, cont;
1963   Label have_js_function;
1964   int argc = arg_count();
1965   ParameterCount actual(argc);
1966
1967   // The checks. First, does edi match the recorded monomorphic target?
1968   __ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size,
1969                            FixedArray::kHeaderSize));
1970
1971   // We don't know that we have a weak cell. We might have a private symbol
1972   // or an AllocationSite, but the memory is safe to examine.
1973   // AllocationSite::kTransitionInfoOffset - contains a Smi or pointer to
1974   // FixedArray.
1975   // WeakCell::kValueOffset - contains a JSFunction or Smi(0)
1976   // Symbol::kHashFieldSlot - if the low bit is 1, then the hash is not
1977   // computed, meaning that it can't appear to be a pointer. If the low bit is
1978   // 0, then hash is computed, but the 0 bit prevents the field from appearing
1979   // to be a pointer.
1980   STATIC_ASSERT(WeakCell::kSize >= kPointerSize);
1981   STATIC_ASSERT(AllocationSite::kTransitionInfoOffset ==
1982                     WeakCell::kValueOffset &&
1983                 WeakCell::kValueOffset == Symbol::kHashFieldSlot);
1984
1985   __ cmp(edi, FieldOperand(ecx, WeakCell::kValueOffset));
1986   __ j(not_equal, &extra_checks_or_miss);
1987
1988   // The compare above could have been a SMI/SMI comparison. Guard against this
1989   // convincing us that we have a monomorphic JSFunction.
1990   __ JumpIfSmi(edi, &extra_checks_or_miss);
1991
1992   __ bind(&have_js_function);
1993   if (CallAsMethod()) {
1994     EmitContinueIfStrictOrNative(masm, &cont);
1995
1996     // Load the receiver from the stack.
1997     __ mov(eax, Operand(esp, (argc + 1) * kPointerSize));
1998
1999     __ JumpIfSmi(eax, &wrap);
2000
2001     __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
2002     __ j(below, &wrap);
2003
2004     __ bind(&cont);
2005   }
2006
2007   __ InvokeFunction(edi, actual, JUMP_FUNCTION, NullCallWrapper());
2008
2009   __ bind(&slow);
2010   EmitSlowCase(isolate, masm, argc, &non_function);
2011
2012   if (CallAsMethod()) {
2013     __ bind(&wrap);
2014     EmitWrapCase(masm, argc, &cont);
2015   }
2016
2017   __ bind(&extra_checks_or_miss);
2018   Label uninitialized, miss;
2019
2020   __ cmp(ecx, Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate)));
2021   __ j(equal, &slow_start);
2022
2023   // The following cases attempt to handle MISS cases without going to the
2024   // runtime.
2025   if (FLAG_trace_ic) {
2026     __ jmp(&miss);
2027   }
2028
2029   __ cmp(ecx, Immediate(TypeFeedbackVector::UninitializedSentinel(isolate)));
2030   __ j(equal, &uninitialized);
2031
2032   // We are going megamorphic. If the feedback is a JSFunction, it is fine
2033   // to handle it here. More complex cases are dealt with in the runtime.
2034   __ AssertNotSmi(ecx);
2035   __ CmpObjectType(ecx, JS_FUNCTION_TYPE, ecx);
2036   __ j(not_equal, &miss);
2037   __ mov(
2038       FieldOperand(ebx, edx, times_half_pointer_size, FixedArray::kHeaderSize),
2039       Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate)));
2040   // We have to update statistics for runtime profiling.
2041   __ sub(FieldOperand(ebx, with_types_offset), Immediate(Smi::FromInt(1)));
2042   __ add(FieldOperand(ebx, generic_offset), Immediate(Smi::FromInt(1)));
2043   __ jmp(&slow_start);
2044
2045   __ bind(&uninitialized);
2046
2047   // We are going monomorphic, provided we actually have a JSFunction.
2048   __ JumpIfSmi(edi, &miss);
2049
2050   // Goto miss case if we do not have a function.
2051   __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
2052   __ j(not_equal, &miss);
2053
2054   // Make sure the function is not the Array() function, which requires special
2055   // behavior on MISS.
2056   __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, ecx);
2057   __ cmp(edi, ecx);
2058   __ j(equal, &miss);
2059
2060   // Update stats.
2061   __ add(FieldOperand(ebx, with_types_offset), Immediate(Smi::FromInt(1)));
2062
2063   // Store the function. Use a stub since we need a frame for allocation.
2064   // ebx - vector
2065   // edx - slot
2066   // edi - function
2067   {
2068     FrameScope scope(masm, StackFrame::INTERNAL);
2069     CreateWeakCellStub create_stub(isolate);
2070     __ push(edi);
2071     __ CallStub(&create_stub);
2072     __ pop(edi);
2073   }
2074
2075   __ jmp(&have_js_function);
2076
2077   // We are here because tracing is on or we encountered a MISS case we can't
2078   // handle here.
2079   __ bind(&miss);
2080   GenerateMiss(masm);
2081
2082   // the slow case
2083   __ bind(&slow_start);
2084
2085   // Check that the function really is a JavaScript function.
2086   __ JumpIfSmi(edi, &non_function);
2087
2088   // Goto slow case if we do not have a function.
2089   __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
2090   __ j(not_equal, &slow);
2091   __ jmp(&have_js_function);
2092
2093   // Unreachable
2094   __ int3();
2095 }
2096
2097
2098 void CallICStub::GenerateMiss(MacroAssembler* masm) {
2099   FrameScope scope(masm, StackFrame::INTERNAL);
2100
2101   // Push the receiver and the function and feedback info.
2102   __ push(edi);
2103   __ push(ebx);
2104   __ push(edx);
2105
2106   // Call the entry.
2107   IC::UtilityId id = GetICState() == DEFAULT ? IC::kCallIC_Miss
2108                                              : IC::kCallIC_Customization_Miss;
2109
2110   ExternalReference miss = ExternalReference(IC_Utility(id), masm->isolate());
2111   __ CallExternalReference(miss, 3);
2112
2113   // Move result to edi and exit the internal frame.
2114   __ mov(edi, eax);
2115 }
2116
2117
2118 bool CEntryStub::NeedsImmovableCode() {
2119   return false;
2120 }
2121
2122
2123 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
2124   CEntryStub::GenerateAheadOfTime(isolate);
2125   StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
2126   StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
2127   // It is important that the store buffer overflow stubs are generated first.
2128   ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
2129   CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
2130   CreateWeakCellStub::GenerateAheadOfTime(isolate);
2131   BinaryOpICStub::GenerateAheadOfTime(isolate);
2132   BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
2133   StoreFastElementStub::GenerateAheadOfTime(isolate);
2134 }
2135
2136
2137 void CodeStub::GenerateFPStubs(Isolate* isolate) {
2138   CEntryStub save_doubles(isolate, 1, kSaveFPRegs);
2139   // Stubs might already be in the snapshot, detect that and don't regenerate,
2140   // which would lead to code stub initialization state being messed up.
2141   Code* save_doubles_code;
2142   if (!save_doubles.FindCodeInCache(&save_doubles_code)) {
2143     save_doubles_code = *(save_doubles.GetCode());
2144   }
2145   isolate->set_fp_stubs_generated(true);
2146 }
2147
2148
2149 void CEntryStub::GenerateAheadOfTime(Isolate* isolate) {
2150   CEntryStub stub(isolate, 1, kDontSaveFPRegs);
2151   stub.GetCode();
2152 }
2153
2154
2155 void CEntryStub::Generate(MacroAssembler* masm) {
2156   // eax: number of arguments including receiver
2157   // ebx: pointer to C function  (C callee-saved)
2158   // ebp: frame pointer  (restored after C call)
2159   // esp: stack pointer  (restored after C call)
2160   // esi: current context (C callee-saved)
2161   // edi: JS function of the caller (C callee-saved)
2162
2163   ProfileEntryHookStub::MaybeCallEntryHook(masm);
2164
2165   // Enter the exit frame that transitions from JavaScript to C++.
2166   __ EnterExitFrame(save_doubles());
2167
2168   // ebx: pointer to C function  (C callee-saved)
2169   // ebp: frame pointer  (restored after C call)
2170   // esp: stack pointer  (restored after C call)
2171   // edi: number of arguments including receiver  (C callee-saved)
2172   // esi: pointer to the first argument (C callee-saved)
2173
2174   // Result returned in eax, or eax+edx if result size is 2.
2175
2176   // Check stack alignment.
2177   if (FLAG_debug_code) {
2178     __ CheckStackAlignment();
2179   }
2180
2181   // Call C function.
2182   __ mov(Operand(esp, 0 * kPointerSize), edi);  // argc.
2183   __ mov(Operand(esp, 1 * kPointerSize), esi);  // argv.
2184   __ mov(Operand(esp, 2 * kPointerSize),
2185          Immediate(ExternalReference::isolate_address(isolate())));
2186   __ call(ebx);
2187   // Result is in eax or edx:eax - do not destroy these registers!
2188
2189   // Runtime functions should not return 'the hole'.  Allowing it to escape may
2190   // lead to crashes in the IC code later.
2191   if (FLAG_debug_code) {
2192     Label okay;
2193     __ cmp(eax, isolate()->factory()->the_hole_value());
2194     __ j(not_equal, &okay, Label::kNear);
2195     __ int3();
2196     __ bind(&okay);
2197   }
2198
2199   // Check result for exception sentinel.
2200   Label exception_returned;
2201   __ cmp(eax, isolate()->factory()->exception());
2202   __ j(equal, &exception_returned);
2203
2204   // Check that there is no pending exception, otherwise we
2205   // should have returned the exception sentinel.
2206   if (FLAG_debug_code) {
2207     __ push(edx);
2208     __ mov(edx, Immediate(isolate()->factory()->the_hole_value()));
2209     Label okay;
2210     ExternalReference pending_exception_address(
2211         Isolate::kPendingExceptionAddress, isolate());
2212     __ cmp(edx, Operand::StaticVariable(pending_exception_address));
2213     // Cannot use check here as it attempts to generate call into runtime.
2214     __ j(equal, &okay, Label::kNear);
2215     __ int3();
2216     __ bind(&okay);
2217     __ pop(edx);
2218   }
2219
2220   // Exit the JavaScript to C++ exit frame.
2221   __ LeaveExitFrame(save_doubles());
2222   __ ret(0);
2223
2224   // Handling of exception.
2225   __ bind(&exception_returned);
2226
2227   ExternalReference pending_handler_context_address(
2228       Isolate::kPendingHandlerContextAddress, isolate());
2229   ExternalReference pending_handler_code_address(
2230       Isolate::kPendingHandlerCodeAddress, isolate());
2231   ExternalReference pending_handler_offset_address(
2232       Isolate::kPendingHandlerOffsetAddress, isolate());
2233   ExternalReference pending_handler_fp_address(
2234       Isolate::kPendingHandlerFPAddress, isolate());
2235   ExternalReference pending_handler_sp_address(
2236       Isolate::kPendingHandlerSPAddress, isolate());
2237
2238   // Ask the runtime for help to determine the handler. This will set eax to
2239   // contain the current pending exception, don't clobber it.
2240   ExternalReference find_handler(Runtime::kFindExceptionHandler, isolate());
2241   {
2242     FrameScope scope(masm, StackFrame::MANUAL);
2243     __ PrepareCallCFunction(3, eax);
2244     __ mov(Operand(esp, 0 * kPointerSize), Immediate(0));  // argc.
2245     __ mov(Operand(esp, 1 * kPointerSize), Immediate(0));  // argv.
2246     __ mov(Operand(esp, 2 * kPointerSize),
2247            Immediate(ExternalReference::isolate_address(isolate())));
2248     __ CallCFunction(find_handler, 3);
2249   }
2250
2251   // Retrieve the handler context, SP and FP.
2252   __ mov(esi, Operand::StaticVariable(pending_handler_context_address));
2253   __ mov(esp, Operand::StaticVariable(pending_handler_sp_address));
2254   __ mov(ebp, Operand::StaticVariable(pending_handler_fp_address));
2255
2256   // If the handler is a JS frame, restore the context to the frame. Note that
2257   // the context will be set to (esi == 0) for non-JS frames.
2258   Label skip;
2259   __ test(esi, esi);
2260   __ j(zero, &skip, Label::kNear);
2261   __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
2262   __ bind(&skip);
2263
2264   // Compute the handler entry address and jump to it.
2265   __ mov(edi, Operand::StaticVariable(pending_handler_code_address));
2266   __ mov(edx, Operand::StaticVariable(pending_handler_offset_address));
2267   __ lea(edi, FieldOperand(edi, edx, times_1, Code::kHeaderSize));
2268   __ jmp(edi);
2269 }
2270
2271
2272 void JSEntryStub::Generate(MacroAssembler* masm) {
2273   Label invoke, handler_entry, exit;
2274   Label not_outermost_js, not_outermost_js_2;
2275
2276   ProfileEntryHookStub::MaybeCallEntryHook(masm);
2277
2278   // Set up frame.
2279   __ push(ebp);
2280   __ mov(ebp, esp);
2281
2282   // Push marker in two places.
2283   int marker = type();
2284   __ push(Immediate(Smi::FromInt(marker)));  // context slot
2285   __ push(Immediate(Smi::FromInt(marker)));  // function slot
2286   // Save callee-saved registers (C calling conventions).
2287   __ push(edi);
2288   __ push(esi);
2289   __ push(ebx);
2290
2291   // Save copies of the top frame descriptor on the stack.
2292   ExternalReference c_entry_fp(Isolate::kCEntryFPAddress, isolate());
2293   __ push(Operand::StaticVariable(c_entry_fp));
2294
2295   // If this is the outermost JS call, set js_entry_sp value.
2296   ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate());
2297   __ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0));
2298   __ j(not_equal, &not_outermost_js, Label::kNear);
2299   __ mov(Operand::StaticVariable(js_entry_sp), ebp);
2300   __ push(Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
2301   __ jmp(&invoke, Label::kNear);
2302   __ bind(&not_outermost_js);
2303   __ push(Immediate(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME)));
2304
2305   // Jump to a faked try block that does the invoke, with a faked catch
2306   // block that sets the pending exception.
2307   __ jmp(&invoke);
2308   __ bind(&handler_entry);
2309   handler_offset_ = handler_entry.pos();
2310   // Caught exception: Store result (exception) in the pending exception
2311   // field in the JSEnv and return a failure sentinel.
2312   ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
2313                                       isolate());
2314   __ mov(Operand::StaticVariable(pending_exception), eax);
2315   __ mov(eax, Immediate(isolate()->factory()->exception()));
2316   __ jmp(&exit);
2317
2318   // Invoke: Link this frame into the handler chain.
2319   __ bind(&invoke);
2320   __ PushStackHandler();
2321
2322   // Clear any pending exceptions.
2323   __ mov(edx, Immediate(isolate()->factory()->the_hole_value()));
2324   __ mov(Operand::StaticVariable(pending_exception), edx);
2325
2326   // Fake a receiver (NULL).
2327   __ push(Immediate(0));  // receiver
2328
2329   // Invoke the function by calling through JS entry trampoline builtin and
2330   // pop the faked function when we return. Notice that we cannot store a
2331   // reference to the trampoline code directly in this stub, because the
2332   // builtin stubs may not have been generated yet.
2333   if (type() == StackFrame::ENTRY_CONSTRUCT) {
2334     ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline,
2335                                       isolate());
2336     __ mov(edx, Immediate(construct_entry));
2337   } else {
2338     ExternalReference entry(Builtins::kJSEntryTrampoline, isolate());
2339     __ mov(edx, Immediate(entry));
2340   }
2341   __ mov(edx, Operand(edx, 0));  // deref address
2342   __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
2343   __ call(edx);
2344
2345   // Unlink this frame from the handler chain.
2346   __ PopStackHandler();
2347
2348   __ bind(&exit);
2349   // Check if the current stack frame is marked as the outermost JS frame.
2350   __ pop(ebx);
2351   __ cmp(ebx, Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME)));
2352   __ j(not_equal, &not_outermost_js_2);
2353   __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0));
2354   __ bind(&not_outermost_js_2);
2355
2356   // Restore the top frame descriptor from the stack.
2357   __ pop(Operand::StaticVariable(ExternalReference(
2358       Isolate::kCEntryFPAddress, isolate())));
2359
2360   // Restore callee-saved registers (C calling conventions).
2361   __ pop(ebx);
2362   __ pop(esi);
2363   __ pop(edi);
2364   __ add(esp, Immediate(2 * kPointerSize));  // remove markers
2365
2366   // Restore frame pointer and return.
2367   __ pop(ebp);
2368   __ ret(0);
2369 }
2370
2371
2372 // Generate stub code for instanceof.
2373 // This code can patch a call site inlined cache of the instance of check,
2374 // which looks like this.
2375 //
2376 //   81 ff XX XX XX XX   cmp    edi, <the hole, patched to a map>
2377 //   75 0a               jne    <some near label>
2378 //   b8 XX XX XX XX      mov    eax, <the hole, patched to either true or false>
2379 //
2380 // If call site patching is requested the stack will have the delta from the
2381 // return address to the cmp instruction just below the return address. This
2382 // also means that call site patching can only take place with arguments in
2383 // registers. TOS looks like this when call site patching is requested
2384 //
2385 //   esp[0] : return address
2386 //   esp[4] : delta from return address to cmp instruction
2387 //
2388 void InstanceofStub::Generate(MacroAssembler* masm) {
2389   // Call site inlining and patching implies arguments in registers.
2390   DCHECK(HasArgsInRegisters() || !HasCallSiteInlineCheck());
2391
2392   // Fixed register usage throughout the stub.
2393   Register object = eax;  // Object (lhs).
2394   Register map = ebx;  // Map of the object.
2395   Register function = edx;  // Function (rhs).
2396   Register prototype = edi;  // Prototype of the function.
2397   Register scratch = ecx;
2398
2399   // Constants describing the call site code to patch.
2400   static const int kDeltaToCmpImmediate = 2;
2401   static const int kDeltaToMov = 8;
2402   static const int kDeltaToMovImmediate = 9;
2403   static const int8_t kCmpEdiOperandByte1 = bit_cast<int8_t, uint8_t>(0x3b);
2404   static const int8_t kCmpEdiOperandByte2 = bit_cast<int8_t, uint8_t>(0x3d);
2405   static const int8_t kMovEaxImmediateByte = bit_cast<int8_t, uint8_t>(0xb8);
2406
2407   DCHECK_EQ(object.code(), InstanceofStub::left().code());
2408   DCHECK_EQ(function.code(), InstanceofStub::right().code());
2409
2410   // Get the object and function - they are always both needed.
2411   Label slow, not_js_object;
2412   if (!HasArgsInRegisters()) {
2413     __ mov(object, Operand(esp, 2 * kPointerSize));
2414     __ mov(function, Operand(esp, 1 * kPointerSize));
2415   }
2416
2417   // Check that the left hand is a JS object.
2418   __ JumpIfSmi(object, &not_js_object);
2419   __ IsObjectJSObjectType(object, map, scratch, &not_js_object);
2420
2421   // If there is a call site cache don't look in the global cache, but do the
2422   // real lookup and update the call site cache.
2423   if (!HasCallSiteInlineCheck() && !ReturnTrueFalseObject()) {
2424     // Look up the function and the map in the instanceof cache.
2425     Label miss;
2426     __ CompareRoot(function, scratch, Heap::kInstanceofCacheFunctionRootIndex);
2427     __ j(not_equal, &miss, Label::kNear);
2428     __ CompareRoot(map, scratch, Heap::kInstanceofCacheMapRootIndex);
2429     __ j(not_equal, &miss, Label::kNear);
2430     __ LoadRoot(eax, Heap::kInstanceofCacheAnswerRootIndex);
2431     __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
2432     __ bind(&miss);
2433   }
2434
2435   // Get the prototype of the function.
2436   __ TryGetFunctionPrototype(function, prototype, scratch, &slow, true);
2437
2438   // Check that the function prototype is a JS object.
2439   __ JumpIfSmi(prototype, &slow);
2440   __ IsObjectJSObjectType(prototype, scratch, scratch, &slow);
2441
2442   // Update the global instanceof or call site inlined cache with the current
2443   // map and function. The cached answer will be set when it is known below.
2444   if (!HasCallSiteInlineCheck()) {
2445     __ StoreRoot(map, scratch, Heap::kInstanceofCacheMapRootIndex);
2446     __ StoreRoot(function, scratch, Heap::kInstanceofCacheFunctionRootIndex);
2447   } else {
2448     // The constants for the code patching are based on no push instructions
2449     // at the call site.
2450     DCHECK(HasArgsInRegisters());
2451     // Get return address and delta to inlined map check.
2452     __ mov(scratch, Operand(esp, 0 * kPointerSize));
2453     __ sub(scratch, Operand(esp, 1 * kPointerSize));
2454     if (FLAG_debug_code) {
2455       __ cmpb(Operand(scratch, 0), kCmpEdiOperandByte1);
2456       __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheCmp1);
2457       __ cmpb(Operand(scratch, 1), kCmpEdiOperandByte2);
2458       __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheCmp2);
2459     }
2460     __ mov(scratch, Operand(scratch, kDeltaToCmpImmediate));
2461     __ mov(Operand(scratch, 0), map);
2462   }
2463
2464   // Loop through the prototype chain of the object looking for the function
2465   // prototype.
2466   __ mov(scratch, FieldOperand(map, Map::kPrototypeOffset));
2467   Label loop, is_instance, is_not_instance;
2468   __ bind(&loop);
2469   __ cmp(scratch, prototype);
2470   __ j(equal, &is_instance, Label::kNear);
2471   Factory* factory = isolate()->factory();
2472   __ cmp(scratch, Immediate(factory->null_value()));
2473   __ j(equal, &is_not_instance, Label::kNear);
2474   __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
2475   __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset));
2476   __ jmp(&loop);
2477
2478   __ bind(&is_instance);
2479   if (!HasCallSiteInlineCheck()) {
2480     __ mov(eax, Immediate(0));
2481     __ StoreRoot(eax, scratch, Heap::kInstanceofCacheAnswerRootIndex);
2482     if (ReturnTrueFalseObject()) {
2483       __ mov(eax, factory->true_value());
2484     }
2485   } else {
2486     // Get return address and delta to inlined map check.
2487     __ mov(eax, factory->true_value());
2488     __ mov(scratch, Operand(esp, 0 * kPointerSize));
2489     __ sub(scratch, Operand(esp, 1 * kPointerSize));
2490     if (FLAG_debug_code) {
2491       __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte);
2492       __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov);
2493     }
2494     __ mov(Operand(scratch, kDeltaToMovImmediate), eax);
2495     if (!ReturnTrueFalseObject()) {
2496       __ Move(eax, Immediate(0));
2497     }
2498   }
2499   __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
2500
2501   __ bind(&is_not_instance);
2502   if (!HasCallSiteInlineCheck()) {
2503     __ mov(eax, Immediate(Smi::FromInt(1)));
2504     __ StoreRoot(eax, scratch, Heap::kInstanceofCacheAnswerRootIndex);
2505     if (ReturnTrueFalseObject()) {
2506       __ mov(eax, factory->false_value());
2507     }
2508   } else {
2509     // Get return address and delta to inlined map check.
2510     __ mov(eax, factory->false_value());
2511     __ mov(scratch, Operand(esp, 0 * kPointerSize));
2512     __ sub(scratch, Operand(esp, 1 * kPointerSize));
2513     if (FLAG_debug_code) {
2514       __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte);
2515       __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov);
2516     }
2517     __ mov(Operand(scratch, kDeltaToMovImmediate), eax);
2518     if (!ReturnTrueFalseObject()) {
2519       __ Move(eax, Immediate(Smi::FromInt(1)));
2520     }
2521   }
2522   __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
2523
2524   Label object_not_null, object_not_null_or_smi;
2525   __ bind(&not_js_object);
2526   // Before null, smi and string value checks, check that the rhs is a function
2527   // as for a non-function rhs an exception needs to be thrown.
2528   __ JumpIfSmi(function, &slow, Label::kNear);
2529   __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch);
2530   __ j(not_equal, &slow, Label::kNear);
2531
2532   // Null is not instance of anything.
2533   __ cmp(object, factory->null_value());
2534   __ j(not_equal, &object_not_null, Label::kNear);
2535   if (ReturnTrueFalseObject()) {
2536     __ mov(eax, factory->false_value());
2537   } else {
2538     __ Move(eax, Immediate(Smi::FromInt(1)));
2539   }
2540   __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
2541
2542   __ bind(&object_not_null);
2543   // Smi values is not instance of anything.
2544   __ JumpIfNotSmi(object, &object_not_null_or_smi, Label::kNear);
2545   if (ReturnTrueFalseObject()) {
2546     __ mov(eax, factory->false_value());
2547   } else {
2548     __ Move(eax, Immediate(Smi::FromInt(1)));
2549   }
2550   __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
2551
2552   __ bind(&object_not_null_or_smi);
2553   // String values is not instance of anything.
2554   Condition is_string = masm->IsObjectStringType(object, scratch, scratch);
2555   __ j(NegateCondition(is_string), &slow, Label::kNear);
2556   if (ReturnTrueFalseObject()) {
2557     __ mov(eax, factory->false_value());
2558   } else {
2559     __ Move(eax, Immediate(Smi::FromInt(1)));
2560   }
2561   __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
2562
2563   // Slow-case: Go through the JavaScript implementation.
2564   __ bind(&slow);
2565   if (!ReturnTrueFalseObject()) {
2566     // Tail call the builtin which returns 0 or 1.
2567     if (HasArgsInRegisters()) {
2568       // Push arguments below return address.
2569       __ pop(scratch);
2570       __ push(object);
2571       __ push(function);
2572       __ push(scratch);
2573     }
2574     __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
2575   } else {
2576     // Call the builtin and convert 0/1 to true/false.
2577     {
2578       FrameScope scope(masm, StackFrame::INTERNAL);
2579       __ push(object);
2580       __ push(function);
2581       __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
2582     }
2583     Label true_value, done;
2584     __ test(eax, eax);
2585     __ j(zero, &true_value, Label::kNear);
2586     __ mov(eax, factory->false_value());
2587     __ jmp(&done, Label::kNear);
2588     __ bind(&true_value);
2589     __ mov(eax, factory->true_value());
2590     __ bind(&done);
2591     __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize);
2592   }
2593 }
2594
2595
2596 // -------------------------------------------------------------------------
2597 // StringCharCodeAtGenerator
2598
2599 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
2600   // If the receiver is a smi trigger the non-string case.
2601   if (check_mode_ == RECEIVER_IS_UNKNOWN) {
2602     __ JumpIfSmi(object_, receiver_not_string_);
2603
2604     // Fetch the instance type of the receiver into result register.
2605     __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
2606     __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
2607     // If the receiver is not a string trigger the non-string case.
2608     __ test(result_, Immediate(kIsNotStringMask));
2609     __ j(not_zero, receiver_not_string_);
2610   }
2611
2612   // If the index is non-smi trigger the non-smi case.
2613   __ JumpIfNotSmi(index_, &index_not_smi_);
2614   __ bind(&got_smi_index_);
2615
2616   // Check for index out of range.
2617   __ cmp(index_, FieldOperand(object_, String::kLengthOffset));
2618   __ j(above_equal, index_out_of_range_);
2619
2620   __ SmiUntag(index_);
2621
2622   Factory* factory = masm->isolate()->factory();
2623   StringCharLoadGenerator::Generate(
2624       masm, factory, object_, index_, result_, &call_runtime_);
2625
2626   __ SmiTag(result_);
2627   __ bind(&exit_);
2628 }
2629
2630
2631 void StringCharCodeAtGenerator::GenerateSlow(
2632     MacroAssembler* masm, EmbedMode embed_mode,
2633     const RuntimeCallHelper& call_helper) {
2634   __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase);
2635
2636   // Index is not a smi.
2637   __ bind(&index_not_smi_);
2638   // If index is a heap number, try converting it to an integer.
2639   __ CheckMap(index_,
2640               masm->isolate()->factory()->heap_number_map(),
2641               index_not_number_,
2642               DONT_DO_SMI_CHECK);
2643   call_helper.BeforeCall(masm);
2644   if (FLAG_vector_ics && embed_mode == PART_OF_IC_HANDLER) {
2645     __ push(VectorLoadICDescriptor::VectorRegister());
2646     __ push(VectorLoadICDescriptor::SlotRegister());
2647   }
2648   __ push(object_);
2649   __ push(index_);  // Consumed by runtime conversion function.
2650   if (index_flags_ == STRING_INDEX_IS_NUMBER) {
2651     __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
2652   } else {
2653     DCHECK(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX);
2654     // NumberToSmi discards numbers that are not exact integers.
2655     __ CallRuntime(Runtime::kNumberToSmi, 1);
2656   }
2657   if (!index_.is(eax)) {
2658     // Save the conversion result before the pop instructions below
2659     // have a chance to overwrite it.
2660     __ mov(index_, eax);
2661   }
2662   __ pop(object_);
2663   if (FLAG_vector_ics && embed_mode == PART_OF_IC_HANDLER) {
2664     __ pop(VectorLoadICDescriptor::SlotRegister());
2665     __ pop(VectorLoadICDescriptor::VectorRegister());
2666   }
2667   // Reload the instance type.
2668   __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset));
2669   __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset));
2670   call_helper.AfterCall(masm);
2671   // If index is still not a smi, it must be out of range.
2672   STATIC_ASSERT(kSmiTag == 0);
2673   __ JumpIfNotSmi(index_, index_out_of_range_);
2674   // Otherwise, return to the fast path.
2675   __ jmp(&got_smi_index_);
2676
2677   // Call runtime. We get here when the receiver is a string and the
2678   // index is a number, but the code of getting the actual character
2679   // is too complex (e.g., when the string needs to be flattened).
2680   __ bind(&call_runtime_);
2681   call_helper.BeforeCall(masm);
2682   __ push(object_);
2683   __ SmiTag(index_);
2684   __ push(index_);
2685   __ CallRuntime(Runtime::kStringCharCodeAtRT, 2);
2686   if (!result_.is(eax)) {
2687     __ mov(result_, eax);
2688   }
2689   call_helper.AfterCall(masm);
2690   __ jmp(&exit_);
2691
2692   __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase);
2693 }
2694
2695
2696 // -------------------------------------------------------------------------
2697 // StringCharFromCodeGenerator
2698
2699 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
2700   // Fast case of Heap::LookupSingleCharacterStringFromCode.
2701   STATIC_ASSERT(kSmiTag == 0);
2702   STATIC_ASSERT(kSmiShiftSize == 0);
2703   DCHECK(base::bits::IsPowerOfTwo32(String::kMaxOneByteCharCode + 1));
2704   __ test(code_,
2705           Immediate(kSmiTagMask |
2706                     ((~String::kMaxOneByteCharCode) << kSmiTagSize)));
2707   __ j(not_zero, &slow_case_);
2708
2709   Factory* factory = masm->isolate()->factory();
2710   __ Move(result_, Immediate(factory->single_character_string_cache()));
2711   STATIC_ASSERT(kSmiTag == 0);
2712   STATIC_ASSERT(kSmiTagSize == 1);
2713   STATIC_ASSERT(kSmiShiftSize == 0);
2714   // At this point code register contains smi tagged one byte char code.
2715   __ mov(result_, FieldOperand(result_,
2716                                code_, times_half_pointer_size,
2717                                FixedArray::kHeaderSize));
2718   __ cmp(result_, factory->undefined_value());
2719   __ j(equal, &slow_case_);
2720   __ bind(&exit_);
2721 }
2722
2723
2724 void StringCharFromCodeGenerator::GenerateSlow(
2725     MacroAssembler* masm,
2726     const RuntimeCallHelper& call_helper) {
2727   __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase);
2728
2729   __ bind(&slow_case_);
2730   call_helper.BeforeCall(masm);
2731   __ push(code_);
2732   __ CallRuntime(Runtime::kCharFromCode, 1);
2733   if (!result_.is(eax)) {
2734     __ mov(result_, eax);
2735   }
2736   call_helper.AfterCall(masm);
2737   __ jmp(&exit_);
2738
2739   __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase);
2740 }
2741
2742
2743 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm,
2744                                           Register dest,
2745                                           Register src,
2746                                           Register count,
2747                                           Register scratch,
2748                                           String::Encoding encoding) {
2749   DCHECK(!scratch.is(dest));
2750   DCHECK(!scratch.is(src));
2751   DCHECK(!scratch.is(count));
2752
2753   // Nothing to do for zero characters.
2754   Label done;
2755   __ test(count, count);
2756   __ j(zero, &done);
2757
2758   // Make count the number of bytes to copy.
2759   if (encoding == String::TWO_BYTE_ENCODING) {
2760     __ shl(count, 1);
2761   }
2762
2763   Label loop;
2764   __ bind(&loop);
2765   __ mov_b(scratch, Operand(src, 0));
2766   __ mov_b(Operand(dest, 0), scratch);
2767   __ inc(src);
2768   __ inc(dest);
2769   __ dec(count);
2770   __ j(not_zero, &loop);
2771
2772   __ bind(&done);
2773 }
2774
2775
2776 void SubStringStub::Generate(MacroAssembler* masm) {
2777   Label runtime;
2778
2779   // Stack frame on entry.
2780   //  esp[0]: return address
2781   //  esp[4]: to
2782   //  esp[8]: from
2783   //  esp[12]: string
2784
2785   // Make sure first argument is a string.
2786   __ mov(eax, Operand(esp, 3 * kPointerSize));
2787   STATIC_ASSERT(kSmiTag == 0);
2788   __ JumpIfSmi(eax, &runtime);
2789   Condition is_string = masm->IsObjectStringType(eax, ebx, ebx);
2790   __ j(NegateCondition(is_string), &runtime);
2791
2792   // eax: string
2793   // ebx: instance type
2794
2795   // Calculate length of sub string using the smi values.
2796   __ mov(ecx, Operand(esp, 1 * kPointerSize));  // To index.
2797   __ JumpIfNotSmi(ecx, &runtime);
2798   __ mov(edx, Operand(esp, 2 * kPointerSize));  // From index.
2799   __ JumpIfNotSmi(edx, &runtime);
2800   __ sub(ecx, edx);
2801   __ cmp(ecx, FieldOperand(eax, String::kLengthOffset));
2802   Label not_original_string;
2803   // Shorter than original string's length: an actual substring.
2804   __ j(below, &not_original_string, Label::kNear);
2805   // Longer than original string's length or negative: unsafe arguments.
2806   __ j(above, &runtime);
2807   // Return original string.
2808   Counters* counters = isolate()->counters();
2809   __ IncrementCounter(counters->sub_string_native(), 1);
2810   __ ret(3 * kPointerSize);
2811   __ bind(&not_original_string);
2812
2813   Label single_char;
2814   __ cmp(ecx, Immediate(Smi::FromInt(1)));
2815   __ j(equal, &single_char);
2816
2817   // eax: string
2818   // ebx: instance type
2819   // ecx: sub string length (smi)
2820   // edx: from index (smi)
2821   // Deal with different string types: update the index if necessary
2822   // and put the underlying string into edi.
2823   Label underlying_unpacked, sliced_string, seq_or_external_string;
2824   // If the string is not indirect, it can only be sequential or external.
2825   STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
2826   STATIC_ASSERT(kIsIndirectStringMask != 0);
2827   __ test(ebx, Immediate(kIsIndirectStringMask));
2828   __ j(zero, &seq_or_external_string, Label::kNear);
2829
2830   Factory* factory = isolate()->factory();
2831   __ test(ebx, Immediate(kSlicedNotConsMask));
2832   __ j(not_zero, &sliced_string, Label::kNear);
2833   // Cons string.  Check whether it is flat, then fetch first part.
2834   // Flat cons strings have an empty second part.
2835   __ cmp(FieldOperand(eax, ConsString::kSecondOffset),
2836          factory->empty_string());
2837   __ j(not_equal, &runtime);
2838   __ mov(edi, FieldOperand(eax, ConsString::kFirstOffset));
2839   // Update instance type.
2840   __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset));
2841   __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
2842   __ jmp(&underlying_unpacked, Label::kNear);
2843
2844   __ bind(&sliced_string);
2845   // Sliced string.  Fetch parent and adjust start index by offset.
2846   __ add(edx, FieldOperand(eax, SlicedString::kOffsetOffset));
2847   __ mov(edi, FieldOperand(eax, SlicedString::kParentOffset));
2848   // Update instance type.
2849   __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset));
2850   __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
2851   __ jmp(&underlying_unpacked, Label::kNear);
2852
2853   __ bind(&seq_or_external_string);
2854   // Sequential or external string.  Just move string to the expected register.
2855   __ mov(edi, eax);
2856
2857   __ bind(&underlying_unpacked);
2858
2859   if (FLAG_string_slices) {
2860     Label copy_routine;
2861     // edi: underlying subject string
2862     // ebx: instance type of underlying subject string
2863     // edx: adjusted start index (smi)
2864     // ecx: length (smi)
2865     __ cmp(ecx, Immediate(Smi::FromInt(SlicedString::kMinLength)));
2866     // Short slice.  Copy instead of slicing.
2867     __ j(less, &copy_routine);
2868     // Allocate new sliced string.  At this point we do not reload the instance
2869     // type including the string encoding because we simply rely on the info
2870     // provided by the original string.  It does not matter if the original
2871     // string's encoding is wrong because we always have to recheck encoding of
2872     // the newly created string's parent anyways due to externalized strings.
2873     Label two_byte_slice, set_slice_header;
2874     STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
2875     STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
2876     __ test(ebx, Immediate(kStringEncodingMask));
2877     __ j(zero, &two_byte_slice, Label::kNear);
2878     __ AllocateOneByteSlicedString(eax, ebx, no_reg, &runtime);
2879     __ jmp(&set_slice_header, Label::kNear);
2880     __ bind(&two_byte_slice);
2881     __ AllocateTwoByteSlicedString(eax, ebx, no_reg, &runtime);
2882     __ bind(&set_slice_header);
2883     __ mov(FieldOperand(eax, SlicedString::kLengthOffset), ecx);
2884     __ mov(FieldOperand(eax, SlicedString::kHashFieldOffset),
2885            Immediate(String::kEmptyHashField));
2886     __ mov(FieldOperand(eax, SlicedString::kParentOffset), edi);
2887     __ mov(FieldOperand(eax, SlicedString::kOffsetOffset), edx);
2888     __ IncrementCounter(counters->sub_string_native(), 1);
2889     __ ret(3 * kPointerSize);
2890
2891     __ bind(&copy_routine);
2892   }
2893
2894   // edi: underlying subject string
2895   // ebx: instance type of underlying subject string
2896   // edx: adjusted start index (smi)
2897   // ecx: length (smi)
2898   // The subject string can only be external or sequential string of either
2899   // encoding at this point.
2900   Label two_byte_sequential, runtime_drop_two, sequential_string;
2901   STATIC_ASSERT(kExternalStringTag != 0);
2902   STATIC_ASSERT(kSeqStringTag == 0);
2903   __ test_b(ebx, kExternalStringTag);
2904   __ j(zero, &sequential_string);
2905
2906   // Handle external string.
2907   // Rule out short external strings.
2908   STATIC_ASSERT(kShortExternalStringTag != 0);
2909   __ test_b(ebx, kShortExternalStringMask);
2910   __ j(not_zero, &runtime);
2911   __ mov(edi, FieldOperand(edi, ExternalString::kResourceDataOffset));
2912   // Move the pointer so that offset-wise, it looks like a sequential string.
2913   STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
2914   __ sub(edi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
2915
2916   __ bind(&sequential_string);
2917   // Stash away (adjusted) index and (underlying) string.
2918   __ push(edx);
2919   __ push(edi);
2920   __ SmiUntag(ecx);
2921   STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0);
2922   __ test_b(ebx, kStringEncodingMask);
2923   __ j(zero, &two_byte_sequential);
2924
2925   // Sequential one byte string.  Allocate the result.
2926   __ AllocateOneByteString(eax, ecx, ebx, edx, edi, &runtime_drop_two);
2927
2928   // eax: result string
2929   // ecx: result string length
2930   // Locate first character of result.
2931   __ mov(edi, eax);
2932   __ add(edi, Immediate(SeqOneByteString::kHeaderSize - kHeapObjectTag));
2933   // Load string argument and locate character of sub string start.
2934   __ pop(edx);
2935   __ pop(ebx);
2936   __ SmiUntag(ebx);
2937   __ lea(edx, FieldOperand(edx, ebx, times_1, SeqOneByteString::kHeaderSize));
2938
2939   // eax: result string
2940   // ecx: result length
2941   // edi: first character of result
2942   // edx: character of sub string start
2943   StringHelper::GenerateCopyCharacters(
2944       masm, edi, edx, ecx, ebx, String::ONE_BYTE_ENCODING);
2945   __ IncrementCounter(counters->sub_string_native(), 1);
2946   __ ret(3 * kPointerSize);
2947
2948   __ bind(&two_byte_sequential);
2949   // Sequential two-byte string.  Allocate the result.
2950   __ AllocateTwoByteString(eax, ecx, ebx, edx, edi, &runtime_drop_two);
2951
2952   // eax: result string
2953   // ecx: result string length
2954   // Locate first character of result.
2955   __ mov(edi, eax);
2956   __ add(edi,
2957          Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
2958   // Load string argument and locate character of sub string start.
2959   __ pop(edx);
2960   __ pop(ebx);
2961   // As from is a smi it is 2 times the value which matches the size of a two
2962   // byte character.
2963   STATIC_ASSERT(kSmiTag == 0);
2964   STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
2965   __ lea(edx, FieldOperand(edx, ebx, times_1, SeqTwoByteString::kHeaderSize));
2966
2967   // eax: result string
2968   // ecx: result length
2969   // edi: first character of result
2970   // edx: character of sub string start
2971   StringHelper::GenerateCopyCharacters(
2972       masm, edi, edx, ecx, ebx, String::TWO_BYTE_ENCODING);
2973   __ IncrementCounter(counters->sub_string_native(), 1);
2974   __ ret(3 * kPointerSize);
2975
2976   // Drop pushed values on the stack before tail call.
2977   __ bind(&runtime_drop_two);
2978   __ Drop(2);
2979
2980   // Just jump to runtime to create the sub string.
2981   __ bind(&runtime);
2982   __ TailCallRuntime(Runtime::kSubStringRT, 3, 1);
2983
2984   __ bind(&single_char);
2985   // eax: string
2986   // ebx: instance type
2987   // ecx: sub string length (smi)
2988   // edx: from index (smi)
2989   StringCharAtGenerator generator(eax, edx, ecx, eax, &runtime, &runtime,
2990                                   &runtime, STRING_INDEX_IS_NUMBER,
2991                                   RECEIVER_IS_STRING);
2992   generator.GenerateFast(masm);
2993   __ ret(3 * kPointerSize);
2994   generator.SkipSlow(masm, &runtime);
2995 }
2996
2997
2998 void ToNumberStub::Generate(MacroAssembler* masm) {
2999   // The ToNumber stub takes one argument in eax.
3000   Label not_smi;
3001   __ JumpIfNotSmi(eax, &not_smi, Label::kNear);
3002   __ Ret();
3003   __ bind(&not_smi);
3004
3005   Label not_heap_number;
3006   __ CompareMap(eax, masm->isolate()->factory()->heap_number_map());
3007   __ j(not_equal, &not_heap_number, Label::kNear);
3008   __ Ret();
3009   __ bind(&not_heap_number);
3010
3011   Label not_string, slow_string;
3012   __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edi);
3013   // eax: object
3014   // edi: object map
3015   __ j(above_equal, &not_string, Label::kNear);
3016   // Check if string has a cached array index.
3017   __ test(FieldOperand(eax, String::kHashFieldOffset),
3018           Immediate(String::kContainsCachedArrayIndexMask));
3019   __ j(not_zero, &slow_string, Label::kNear);
3020   __ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
3021   __ IndexFromHash(eax, eax);
3022   __ Ret();
3023   __ bind(&slow_string);
3024   __ pop(ecx);   // Pop return address.
3025   __ push(eax);  // Push argument.
3026   __ push(ecx);  // Push return address.
3027   __ TailCallRuntime(Runtime::kStringToNumber, 1, 1);
3028   __ bind(&not_string);
3029
3030   Label not_oddball;
3031   __ CmpInstanceType(edi, ODDBALL_TYPE);
3032   __ j(not_equal, &not_oddball, Label::kNear);
3033   __ mov(eax, FieldOperand(eax, Oddball::kToNumberOffset));
3034   __ Ret();
3035   __ bind(&not_oddball);
3036
3037   __ pop(ecx);   // Pop return address.
3038   __ push(eax);  // Push argument.
3039   __ push(ecx);  // Push return address.
3040   __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION);
3041 }
3042
3043
3044 void StringHelper::GenerateFlatOneByteStringEquals(MacroAssembler* masm,
3045                                                    Register left,
3046                                                    Register right,
3047                                                    Register scratch1,
3048                                                    Register scratch2) {
3049   Register length = scratch1;
3050
3051   // Compare lengths.
3052   Label strings_not_equal, check_zero_length;
3053   __ mov(length, FieldOperand(left, String::kLengthOffset));
3054   __ cmp(length, FieldOperand(right, String::kLengthOffset));
3055   __ j(equal, &check_zero_length, Label::kNear);
3056   __ bind(&strings_not_equal);
3057   __ Move(eax, Immediate(Smi::FromInt(NOT_EQUAL)));
3058   __ ret(0);
3059
3060   // Check if the length is zero.
3061   Label compare_chars;
3062   __ bind(&check_zero_length);
3063   STATIC_ASSERT(kSmiTag == 0);
3064   __ test(length, length);
3065   __ j(not_zero, &compare_chars, Label::kNear);
3066   __ Move(eax, Immediate(Smi::FromInt(EQUAL)));
3067   __ ret(0);
3068
3069   // Compare characters.
3070   __ bind(&compare_chars);
3071   GenerateOneByteCharsCompareLoop(masm, left, right, length, scratch2,
3072                                   &strings_not_equal, Label::kNear);
3073
3074   // Characters are equal.
3075   __ Move(eax, Immediate(Smi::FromInt(EQUAL)));
3076   __ ret(0);
3077 }
3078
3079
3080 void StringHelper::GenerateCompareFlatOneByteStrings(
3081     MacroAssembler* masm, Register left, Register right, Register scratch1,
3082     Register scratch2, Register scratch3) {
3083   Counters* counters = masm->isolate()->counters();
3084   __ IncrementCounter(counters->string_compare_native(), 1);
3085
3086   // Find minimum length.
3087   Label left_shorter;
3088   __ mov(scratch1, FieldOperand(left, String::kLengthOffset));
3089   __ mov(scratch3, scratch1);
3090   __ sub(scratch3, FieldOperand(right, String::kLengthOffset));
3091
3092   Register length_delta = scratch3;
3093
3094   __ j(less_equal, &left_shorter, Label::kNear);
3095   // Right string is shorter. Change scratch1 to be length of right string.
3096   __ sub(scratch1, length_delta);
3097   __ bind(&left_shorter);
3098
3099   Register min_length = scratch1;
3100
3101   // If either length is zero, just compare lengths.
3102   Label compare_lengths;
3103   __ test(min_length, min_length);
3104   __ j(zero, &compare_lengths, Label::kNear);
3105
3106   // Compare characters.
3107   Label result_not_equal;
3108   GenerateOneByteCharsCompareLoop(masm, left, right, min_length, scratch2,
3109                                   &result_not_equal, Label::kNear);
3110
3111   // Compare lengths -  strings up to min-length are equal.
3112   __ bind(&compare_lengths);
3113   __ test(length_delta, length_delta);
3114   Label length_not_equal;
3115   __ j(not_zero, &length_not_equal, Label::kNear);
3116
3117   // Result is EQUAL.
3118   STATIC_ASSERT(EQUAL == 0);
3119   STATIC_ASSERT(kSmiTag == 0);
3120   __ Move(eax, Immediate(Smi::FromInt(EQUAL)));
3121   __ ret(0);
3122
3123   Label result_greater;
3124   Label result_less;
3125   __ bind(&length_not_equal);
3126   __ j(greater, &result_greater, Label::kNear);
3127   __ jmp(&result_less, Label::kNear);
3128   __ bind(&result_not_equal);
3129   __ j(above, &result_greater, Label::kNear);
3130   __ bind(&result_less);
3131
3132   // Result is LESS.
3133   __ Move(eax, Immediate(Smi::FromInt(LESS)));
3134   __ ret(0);
3135
3136   // Result is GREATER.
3137   __ bind(&result_greater);
3138   __ Move(eax, Immediate(Smi::FromInt(GREATER)));
3139   __ ret(0);
3140 }
3141
3142
3143 void StringHelper::GenerateOneByteCharsCompareLoop(
3144     MacroAssembler* masm, Register left, Register right, Register length,
3145     Register scratch, Label* chars_not_equal,
3146     Label::Distance chars_not_equal_near) {
3147   // Change index to run from -length to -1 by adding length to string
3148   // start. This means that loop ends when index reaches zero, which
3149   // doesn't need an additional compare.
3150   __ SmiUntag(length);
3151   __ lea(left,
3152          FieldOperand(left, length, times_1, SeqOneByteString::kHeaderSize));
3153   __ lea(right,
3154          FieldOperand(right, length, times_1, SeqOneByteString::kHeaderSize));
3155   __ neg(length);
3156   Register index = length;  // index = -length;
3157
3158   // Compare loop.
3159   Label loop;
3160   __ bind(&loop);
3161   __ mov_b(scratch, Operand(left, index, times_1, 0));
3162   __ cmpb(scratch, Operand(right, index, times_1, 0));
3163   __ j(not_equal, chars_not_equal, chars_not_equal_near);
3164   __ inc(index);
3165   __ j(not_zero, &loop);
3166 }
3167
3168
3169 void StringCompareStub::Generate(MacroAssembler* masm) {
3170   Label runtime;
3171
3172   // Stack frame on entry.
3173   //  esp[0]: return address
3174   //  esp[4]: right string
3175   //  esp[8]: left string
3176
3177   __ mov(edx, Operand(esp, 2 * kPointerSize));  // left
3178   __ mov(eax, Operand(esp, 1 * kPointerSize));  // right
3179
3180   Label not_same;
3181   __ cmp(edx, eax);
3182   __ j(not_equal, &not_same, Label::kNear);
3183   STATIC_ASSERT(EQUAL == 0);
3184   STATIC_ASSERT(kSmiTag == 0);
3185   __ Move(eax, Immediate(Smi::FromInt(EQUAL)));
3186   __ IncrementCounter(isolate()->counters()->string_compare_native(), 1);
3187   __ ret(2 * kPointerSize);
3188
3189   __ bind(&not_same);
3190
3191   // Check that both objects are sequential one-byte strings.
3192   __ JumpIfNotBothSequentialOneByteStrings(edx, eax, ecx, ebx, &runtime);
3193
3194   // Compare flat one-byte strings.
3195   // Drop arguments from the stack.
3196   __ pop(ecx);
3197   __ add(esp, Immediate(2 * kPointerSize));
3198   __ push(ecx);
3199   StringHelper::GenerateCompareFlatOneByteStrings(masm, edx, eax, ecx, ebx,
3200                                                   edi);
3201
3202   // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
3203   // tagged as a small integer.
3204   __ bind(&runtime);
3205   __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1);
3206 }
3207
3208
3209 void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
3210   // ----------- S t a t e -------------
3211   //  -- edx    : left
3212   //  -- eax    : right
3213   //  -- esp[0] : return address
3214   // -----------------------------------
3215
3216   // Load ecx with the allocation site.  We stick an undefined dummy value here
3217   // and replace it with the real allocation site later when we instantiate this
3218   // stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
3219   __ mov(ecx, handle(isolate()->heap()->undefined_value()));
3220
3221   // Make sure that we actually patched the allocation site.
3222   if (FLAG_debug_code) {
3223     __ test(ecx, Immediate(kSmiTagMask));
3224     __ Assert(not_equal, kExpectedAllocationSite);
3225     __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
3226            isolate()->factory()->allocation_site_map());
3227     __ Assert(equal, kExpectedAllocationSite);
3228   }
3229
3230   // Tail call into the stub that handles binary operations with allocation
3231   // sites.
3232   BinaryOpWithAllocationSiteStub stub(isolate(), state());
3233   __ TailCallStub(&stub);
3234 }
3235
3236
3237 void CompareICStub::GenerateSmis(MacroAssembler* masm) {
3238   DCHECK(state() == CompareICState::SMI);
3239   Label miss;
3240   __ mov(ecx, edx);
3241   __ or_(ecx, eax);
3242   __ JumpIfNotSmi(ecx, &miss, Label::kNear);
3243
3244   if (GetCondition() == equal) {
3245     // For equality we do not care about the sign of the result.
3246     __ sub(eax, edx);
3247   } else {
3248     Label done;
3249     __ sub(edx, eax);
3250     __ j(no_overflow, &done, Label::kNear);
3251     // Correct sign of result in case of overflow.
3252     __ not_(edx);
3253     __ bind(&done);
3254     __ mov(eax, edx);
3255   }
3256   __ ret(0);
3257
3258   __ bind(&miss);
3259   GenerateMiss(masm);
3260 }
3261
3262
3263 void CompareICStub::GenerateNumbers(MacroAssembler* masm) {
3264   DCHECK(state() == CompareICState::NUMBER);
3265
3266   Label generic_stub, check_left;
3267   Label unordered, maybe_undefined1, maybe_undefined2;
3268   Label miss;
3269
3270   if (left() == CompareICState::SMI) {
3271     __ JumpIfNotSmi(edx, &miss);
3272   }
3273   if (right() == CompareICState::SMI) {
3274     __ JumpIfNotSmi(eax, &miss);
3275   }
3276
3277   // Inlining the double comparison and falling back to the general compare
3278   // stub if NaN is involved or SSE2 or CMOV is unsupported.
3279   __ JumpIfSmi(eax, &check_left, Label::kNear);
3280   __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
3281          isolate()->factory()->heap_number_map());
3282   __ j(not_equal, &maybe_undefined1, Label::kNear);
3283
3284   __ bind(&check_left);
3285   __ JumpIfSmi(edx, &generic_stub, Label::kNear);
3286   __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
3287          isolate()->factory()->heap_number_map());
3288   __ j(not_equal, &maybe_undefined2, Label::kNear);
3289
3290   __ bind(&unordered);
3291   __ bind(&generic_stub);
3292   CompareICStub stub(isolate(), op(), CompareICState::GENERIC,
3293                      CompareICState::GENERIC, CompareICState::GENERIC);
3294   __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
3295
3296   __ bind(&maybe_undefined1);
3297   if (Token::IsOrderedRelationalCompareOp(op())) {
3298     __ cmp(eax, Immediate(isolate()->factory()->undefined_value()));
3299     __ j(not_equal, &miss);
3300     __ JumpIfSmi(edx, &unordered);
3301     __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx);
3302     __ j(not_equal, &maybe_undefined2, Label::kNear);
3303     __ jmp(&unordered);
3304   }
3305
3306   __ bind(&maybe_undefined2);
3307   if (Token::IsOrderedRelationalCompareOp(op())) {
3308     __ cmp(edx, Immediate(isolate()->factory()->undefined_value()));
3309     __ j(equal, &unordered);
3310   }
3311
3312   __ bind(&miss);
3313   GenerateMiss(masm);
3314 }
3315
3316
3317 void CompareICStub::GenerateInternalizedStrings(MacroAssembler* masm) {
3318   DCHECK(state() == CompareICState::INTERNALIZED_STRING);
3319   DCHECK(GetCondition() == equal);
3320
3321   // Registers containing left and right operands respectively.
3322   Register left = edx;
3323   Register right = eax;
3324   Register tmp1 = ecx;
3325   Register tmp2 = ebx;
3326
3327   // Check that both operands are heap objects.
3328   Label miss;
3329   __ mov(tmp1, left);
3330   STATIC_ASSERT(kSmiTag == 0);
3331   __ and_(tmp1, right);
3332   __ JumpIfSmi(tmp1, &miss, Label::kNear);
3333
3334   // Check that both operands are internalized strings.
3335   __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset));
3336   __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset));
3337   __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
3338   __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
3339   STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
3340   __ or_(tmp1, tmp2);
3341   __ test(tmp1, Immediate(kIsNotStringMask | kIsNotInternalizedMask));
3342   __ j(not_zero, &miss, Label::kNear);
3343
3344   // Internalized strings are compared by identity.
3345   Label done;
3346   __ cmp(left, right);
3347   // Make sure eax is non-zero. At this point input operands are
3348   // guaranteed to be non-zero.
3349   DCHECK(right.is(eax));
3350   __ j(not_equal, &done, Label::kNear);
3351   STATIC_ASSERT(EQUAL == 0);
3352   STATIC_ASSERT(kSmiTag == 0);
3353   __ Move(eax, Immediate(Smi::FromInt(EQUAL)));
3354   __ bind(&done);
3355   __ ret(0);
3356
3357   __ bind(&miss);
3358   GenerateMiss(masm);
3359 }
3360
3361
3362 void CompareICStub::GenerateUniqueNames(MacroAssembler* masm) {
3363   DCHECK(state() == CompareICState::UNIQUE_NAME);
3364   DCHECK(GetCondition() == equal);
3365
3366   // Registers containing left and right operands respectively.
3367   Register left = edx;
3368   Register right = eax;
3369   Register tmp1 = ecx;
3370   Register tmp2 = ebx;
3371
3372   // Check that both operands are heap objects.
3373   Label miss;
3374   __ mov(tmp1, left);
3375   STATIC_ASSERT(kSmiTag == 0);
3376   __ and_(tmp1, right);
3377   __ JumpIfSmi(tmp1, &miss, Label::kNear);
3378
3379   // Check that both operands are unique names. This leaves the instance
3380   // types loaded in tmp1 and tmp2.
3381   __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset));
3382   __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset));
3383   __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
3384   __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
3385
3386   __ JumpIfNotUniqueNameInstanceType(tmp1, &miss, Label::kNear);
3387   __ JumpIfNotUniqueNameInstanceType(tmp2, &miss, Label::kNear);
3388
3389   // Unique names are compared by identity.
3390   Label done;
3391   __ cmp(left, right);
3392   // Make sure eax is non-zero. At this point input operands are
3393   // guaranteed to be non-zero.
3394   DCHECK(right.is(eax));
3395   __ j(not_equal, &done, Label::kNear);
3396   STATIC_ASSERT(EQUAL == 0);
3397   STATIC_ASSERT(kSmiTag == 0);
3398   __ Move(eax, Immediate(Smi::FromInt(EQUAL)));
3399   __ bind(&done);
3400   __ ret(0);
3401
3402   __ bind(&miss);
3403   GenerateMiss(masm);
3404 }
3405
3406
3407 void CompareICStub::GenerateStrings(MacroAssembler* masm) {
3408   DCHECK(state() == CompareICState::STRING);
3409   Label miss;
3410
3411   bool equality = Token::IsEqualityOp(op());
3412
3413   // Registers containing left and right operands respectively.
3414   Register left = edx;
3415   Register right = eax;
3416   Register tmp1 = ecx;
3417   Register tmp2 = ebx;
3418   Register tmp3 = edi;
3419
3420   // Check that both operands are heap objects.
3421   __ mov(tmp1, left);
3422   STATIC_ASSERT(kSmiTag == 0);
3423   __ and_(tmp1, right);
3424   __ JumpIfSmi(tmp1, &miss);
3425
3426   // Check that both operands are strings. This leaves the instance
3427   // types loaded in tmp1 and tmp2.
3428   __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset));
3429   __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset));
3430   __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset));
3431   __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset));
3432   __ mov(tmp3, tmp1);
3433   STATIC_ASSERT(kNotStringTag != 0);
3434   __ or_(tmp3, tmp2);
3435   __ test(tmp3, Immediate(kIsNotStringMask));
3436   __ j(not_zero, &miss);
3437
3438   // Fast check for identical strings.
3439   Label not_same;
3440   __ cmp(left, right);
3441   __ j(not_equal, &not_same, Label::kNear);
3442   STATIC_ASSERT(EQUAL == 0);
3443   STATIC_ASSERT(kSmiTag == 0);
3444   __ Move(eax, Immediate(Smi::FromInt(EQUAL)));
3445   __ ret(0);
3446
3447   // Handle not identical strings.
3448   __ bind(&not_same);
3449
3450   // Check that both strings are internalized. If they are, we're done
3451   // because we already know they are not identical.  But in the case of
3452   // non-equality compare, we still need to determine the order. We
3453   // also know they are both strings.
3454   if (equality) {
3455     Label do_compare;
3456     STATIC_ASSERT(kInternalizedTag == 0);
3457     __ or_(tmp1, tmp2);
3458     __ test(tmp1, Immediate(kIsNotInternalizedMask));
3459     __ j(not_zero, &do_compare, Label::kNear);
3460     // Make sure eax is non-zero. At this point input operands are
3461     // guaranteed to be non-zero.
3462     DCHECK(right.is(eax));
3463     __ ret(0);
3464     __ bind(&do_compare);
3465   }
3466
3467   // Check that both strings are sequential one-byte.
3468   Label runtime;
3469   __ JumpIfNotBothSequentialOneByteStrings(left, right, tmp1, tmp2, &runtime);
3470
3471   // Compare flat one byte strings. Returns when done.
3472   if (equality) {
3473     StringHelper::GenerateFlatOneByteStringEquals(masm, left, right, tmp1,
3474                                                   tmp2);
3475   } else {
3476     StringHelper::GenerateCompareFlatOneByteStrings(masm, left, right, tmp1,
3477                                                     tmp2, tmp3);
3478   }
3479
3480   // Handle more complex cases in runtime.
3481   __ bind(&runtime);
3482   __ pop(tmp1);  // Return address.
3483   __ push(left);
3484   __ push(right);
3485   __ push(tmp1);
3486   if (equality) {
3487     __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
3488   } else {
3489     __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1);
3490   }
3491
3492   __ bind(&miss);
3493   GenerateMiss(masm);
3494 }
3495
3496
3497 void CompareICStub::GenerateObjects(MacroAssembler* masm) {
3498   DCHECK(state() == CompareICState::OBJECT);
3499   Label miss;
3500   __ mov(ecx, edx);
3501   __ and_(ecx, eax);
3502   __ JumpIfSmi(ecx, &miss, Label::kNear);
3503
3504   __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx);
3505   __ j(not_equal, &miss, Label::kNear);
3506   __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx);
3507   __ j(not_equal, &miss, Label::kNear);
3508
3509   DCHECK(GetCondition() == equal);
3510   __ sub(eax, edx);
3511   __ ret(0);
3512
3513   __ bind(&miss);
3514   GenerateMiss(masm);
3515 }
3516
3517
3518 void CompareICStub::GenerateKnownObjects(MacroAssembler* masm) {
3519   Label miss;
3520   Handle<WeakCell> cell = Map::WeakCellForMap(known_map_);
3521   __ mov(ecx, edx);
3522   __ and_(ecx, eax);
3523   __ JumpIfSmi(ecx, &miss, Label::kNear);
3524
3525   __ GetWeakValue(edi, cell);
3526   __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
3527   __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
3528   __ cmp(ecx, edi);
3529   __ j(not_equal, &miss, Label::kNear);
3530   __ cmp(ebx, edi);
3531   __ j(not_equal, &miss, Label::kNear);
3532
3533   __ sub(eax, edx);
3534   __ ret(0);
3535
3536   __ bind(&miss);
3537   GenerateMiss(masm);
3538 }
3539
3540
3541 void CompareICStub::GenerateMiss(MacroAssembler* masm) {
3542   {
3543     // Call the runtime system in a fresh internal frame.
3544     ExternalReference miss = ExternalReference(IC_Utility(IC::kCompareIC_Miss),
3545                                                isolate());
3546     FrameScope scope(masm, StackFrame::INTERNAL);
3547     __ push(edx);  // Preserve edx and eax.
3548     __ push(eax);
3549     __ push(edx);  // And also use them as the arguments.
3550     __ push(eax);
3551     __ push(Immediate(Smi::FromInt(op())));
3552     __ CallExternalReference(miss, 3);
3553     // Compute the entry point of the rewritten stub.
3554     __ lea(edi, FieldOperand(eax, Code::kHeaderSize));
3555     __ pop(eax);
3556     __ pop(edx);
3557   }
3558
3559   // Do a tail call to the rewritten stub.
3560   __ jmp(edi);
3561 }
3562
3563
3564 // Helper function used to check that the dictionary doesn't contain
3565 // the property. This function may return false negatives, so miss_label
3566 // must always call a backup property check that is complete.
3567 // This function is safe to call if the receiver has fast properties.
3568 // Name must be a unique name and receiver must be a heap object.
3569 void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
3570                                                       Label* miss,
3571                                                       Label* done,
3572                                                       Register properties,
3573                                                       Handle<Name> name,
3574                                                       Register r0) {
3575   DCHECK(name->IsUniqueName());
3576
3577   // If names of slots in range from 1 to kProbes - 1 for the hash value are
3578   // not equal to the name and kProbes-th slot is not used (its name is the
3579   // undefined value), it guarantees the hash table doesn't contain the
3580   // property. It's true even if some slots represent deleted properties
3581   // (their names are the hole value).
3582   for (int i = 0; i < kInlinedProbes; i++) {
3583     // Compute the masked index: (hash + i + i * i) & mask.
3584     Register index = r0;
3585     // Capacity is smi 2^n.
3586     __ mov(index, FieldOperand(properties, kCapacityOffset));
3587     __ dec(index);
3588     __ and_(index,
3589             Immediate(Smi::FromInt(name->Hash() +
3590                                    NameDictionary::GetProbeOffset(i))));
3591
3592     // Scale the index by multiplying by the entry size.
3593     DCHECK(NameDictionary::kEntrySize == 3);
3594     __ lea(index, Operand(index, index, times_2, 0));  // index *= 3.
3595     Register entity_name = r0;
3596     // Having undefined at this place means the name is not contained.
3597     DCHECK_EQ(kSmiTagSize, 1);
3598     __ mov(entity_name, Operand(properties, index, times_half_pointer_size,
3599                                 kElementsStartOffset - kHeapObjectTag));
3600     __ cmp(entity_name, masm->isolate()->factory()->undefined_value());
3601     __ j(equal, done);
3602
3603     // Stop if found the property.
3604     __ cmp(entity_name, Handle<Name>(name));
3605     __ j(equal, miss);
3606
3607     Label good;
3608     // Check for the hole and skip.
3609     __ cmp(entity_name, masm->isolate()->factory()->the_hole_value());
3610     __ j(equal, &good, Label::kNear);
3611
3612     // Check if the entry name is not a unique name.
3613     __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset));
3614     __ JumpIfNotUniqueNameInstanceType(
3615         FieldOperand(entity_name, Map::kInstanceTypeOffset), miss);
3616     __ bind(&good);
3617   }
3618
3619   NameDictionaryLookupStub stub(masm->isolate(), properties, r0, r0,
3620                                 NEGATIVE_LOOKUP);
3621   __ push(Immediate(Handle<Object>(name)));
3622   __ push(Immediate(name->Hash()));
3623   __ CallStub(&stub);
3624   __ test(r0, r0);
3625   __ j(not_zero, miss);
3626   __ jmp(done);
3627 }
3628
3629
3630 // Probe the name dictionary in the |elements| register. Jump to the
3631 // |done| label if a property with the given name is found leaving the
3632 // index into the dictionary in |r0|. Jump to the |miss| label
3633 // otherwise.
3634 void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
3635                                                       Label* miss,
3636                                                       Label* done,
3637                                                       Register elements,
3638                                                       Register name,
3639                                                       Register r0,
3640                                                       Register r1) {
3641   DCHECK(!elements.is(r0));
3642   DCHECK(!elements.is(r1));
3643   DCHECK(!name.is(r0));
3644   DCHECK(!name.is(r1));
3645
3646   __ AssertName(name);
3647
3648   __ mov(r1, FieldOperand(elements, kCapacityOffset));
3649   __ shr(r1, kSmiTagSize);  // convert smi to int
3650   __ dec(r1);
3651
3652   // Generate an unrolled loop that performs a few probes before
3653   // giving up. Measurements done on Gmail indicate that 2 probes
3654   // cover ~93% of loads from dictionaries.
3655   for (int i = 0; i < kInlinedProbes; i++) {
3656     // Compute the masked index: (hash + i + i * i) & mask.
3657     __ mov(r0, FieldOperand(name, Name::kHashFieldOffset));
3658     __ shr(r0, Name::kHashShift);
3659     if (i > 0) {
3660       __ add(r0, Immediate(NameDictionary::GetProbeOffset(i)));
3661     }
3662     __ and_(r0, r1);
3663
3664     // Scale the index by multiplying by the entry size.
3665     DCHECK(NameDictionary::kEntrySize == 3);
3666     __ lea(r0, Operand(r0, r0, times_2, 0));  // r0 = r0 * 3
3667
3668     // Check if the key is identical to the name.
3669     __ cmp(name, Operand(elements,
3670                          r0,
3671                          times_4,
3672                          kElementsStartOffset - kHeapObjectTag));
3673     __ j(equal, done);
3674   }
3675
3676   NameDictionaryLookupStub stub(masm->isolate(), elements, r1, r0,
3677                                 POSITIVE_LOOKUP);
3678   __ push(name);
3679   __ mov(r0, FieldOperand(name, Name::kHashFieldOffset));
3680   __ shr(r0, Name::kHashShift);
3681   __ push(r0);
3682   __ CallStub(&stub);
3683
3684   __ test(r1, r1);
3685   __ j(zero, miss);
3686   __ jmp(done);
3687 }
3688
3689
3690 void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
3691   // This stub overrides SometimesSetsUpAFrame() to return false.  That means
3692   // we cannot call anything that could cause a GC from this stub.
3693   // Stack frame on entry:
3694   //  esp[0 * kPointerSize]: return address.
3695   //  esp[1 * kPointerSize]: key's hash.
3696   //  esp[2 * kPointerSize]: key.
3697   // Registers:
3698   //  dictionary_: NameDictionary to probe.
3699   //  result_: used as scratch.
3700   //  index_: will hold an index of entry if lookup is successful.
3701   //          might alias with result_.
3702   // Returns:
3703   //  result_ is zero if lookup failed, non zero otherwise.
3704
3705   Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
3706
3707   Register scratch = result();
3708
3709   __ mov(scratch, FieldOperand(dictionary(), kCapacityOffset));
3710   __ dec(scratch);
3711   __ SmiUntag(scratch);
3712   __ push(scratch);
3713
3714   // If names of slots in range from 1 to kProbes - 1 for the hash value are
3715   // not equal to the name and kProbes-th slot is not used (its name is the
3716   // undefined value), it guarantees the hash table doesn't contain the
3717   // property. It's true even if some slots represent deleted properties
3718   // (their names are the null value).
3719   for (int i = kInlinedProbes; i < kTotalProbes; i++) {
3720     // Compute the masked index: (hash + i + i * i) & mask.
3721     __ mov(scratch, Operand(esp, 2 * kPointerSize));
3722     if (i > 0) {
3723       __ add(scratch, Immediate(NameDictionary::GetProbeOffset(i)));
3724     }
3725     __ and_(scratch, Operand(esp, 0));
3726
3727     // Scale the index by multiplying by the entry size.
3728     DCHECK(NameDictionary::kEntrySize == 3);
3729     __ lea(index(), Operand(scratch, scratch, times_2, 0));  // index *= 3.
3730
3731     // Having undefined at this place means the name is not contained.
3732     DCHECK_EQ(kSmiTagSize, 1);
3733     __ mov(scratch, Operand(dictionary(), index(), times_pointer_size,
3734                             kElementsStartOffset - kHeapObjectTag));
3735     __ cmp(scratch, isolate()->factory()->undefined_value());
3736     __ j(equal, &not_in_dictionary);
3737
3738     // Stop if found the property.
3739     __ cmp(scratch, Operand(esp, 3 * kPointerSize));
3740     __ j(equal, &in_dictionary);
3741
3742     if (i != kTotalProbes - 1 && mode() == NEGATIVE_LOOKUP) {
3743       // If we hit a key that is not a unique name during negative
3744       // lookup we have to bailout as this key might be equal to the
3745       // key we are looking for.
3746
3747       // Check if the entry name is not a unique name.
3748       __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset));
3749       __ JumpIfNotUniqueNameInstanceType(
3750           FieldOperand(scratch, Map::kInstanceTypeOffset),
3751           &maybe_in_dictionary);
3752     }
3753   }
3754
3755   __ bind(&maybe_in_dictionary);
3756   // If we are doing negative lookup then probing failure should be
3757   // treated as a lookup success. For positive lookup probing failure
3758   // should be treated as lookup failure.
3759   if (mode() == POSITIVE_LOOKUP) {
3760     __ mov(result(), Immediate(0));
3761     __ Drop(1);
3762     __ ret(2 * kPointerSize);
3763   }
3764
3765   __ bind(&in_dictionary);
3766   __ mov(result(), Immediate(1));
3767   __ Drop(1);
3768   __ ret(2 * kPointerSize);
3769
3770   __ bind(&not_in_dictionary);
3771   __ mov(result(), Immediate(0));
3772   __ Drop(1);
3773   __ ret(2 * kPointerSize);
3774 }
3775
3776
3777 void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(
3778     Isolate* isolate) {
3779   StoreBufferOverflowStub stub(isolate, kDontSaveFPRegs);
3780   stub.GetCode();
3781   StoreBufferOverflowStub stub2(isolate, kSaveFPRegs);
3782   stub2.GetCode();
3783 }
3784
3785
3786 // Takes the input in 3 registers: address_ value_ and object_.  A pointer to
3787 // the value has just been written into the object, now this stub makes sure
3788 // we keep the GC informed.  The word in the object where the value has been
3789 // written is in the address register.
3790 void RecordWriteStub::Generate(MacroAssembler* masm) {
3791   Label skip_to_incremental_noncompacting;
3792   Label skip_to_incremental_compacting;
3793
3794   // The first two instructions are generated with labels so as to get the
3795   // offset fixed up correctly by the bind(Label*) call.  We patch it back and
3796   // forth between a compare instructions (a nop in this position) and the
3797   // real branch when we start and stop incremental heap marking.
3798   __ jmp(&skip_to_incremental_noncompacting, Label::kNear);
3799   __ jmp(&skip_to_incremental_compacting, Label::kFar);
3800
3801   if (remembered_set_action() == EMIT_REMEMBERED_SET) {
3802     __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
3803                            MacroAssembler::kReturnAtEnd);
3804   } else {
3805     __ ret(0);
3806   }
3807
3808   __ bind(&skip_to_incremental_noncompacting);
3809   GenerateIncremental(masm, INCREMENTAL);
3810
3811   __ bind(&skip_to_incremental_compacting);
3812   GenerateIncremental(masm, INCREMENTAL_COMPACTION);
3813
3814   // Initial mode of the stub is expected to be STORE_BUFFER_ONLY.
3815   // Will be checked in IncrementalMarking::ActivateGeneratedStub.
3816   masm->set_byte_at(0, kTwoByteNopInstruction);
3817   masm->set_byte_at(2, kFiveByteNopInstruction);
3818 }
3819
3820
3821 void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
3822   regs_.Save(masm);
3823
3824   if (remembered_set_action() == EMIT_REMEMBERED_SET) {
3825     Label dont_need_remembered_set;
3826
3827     __ mov(regs_.scratch0(), Operand(regs_.address(), 0));
3828     __ JumpIfNotInNewSpace(regs_.scratch0(),  // Value.
3829                            regs_.scratch0(),
3830                            &dont_need_remembered_set);
3831
3832     __ CheckPageFlag(regs_.object(),
3833                      regs_.scratch0(),
3834                      1 << MemoryChunk::SCAN_ON_SCAVENGE,
3835                      not_zero,
3836                      &dont_need_remembered_set);
3837
3838     // First notify the incremental marker if necessary, then update the
3839     // remembered set.
3840     CheckNeedsToInformIncrementalMarker(
3841         masm,
3842         kUpdateRememberedSetOnNoNeedToInformIncrementalMarker,
3843         mode);
3844     InformIncrementalMarker(masm);
3845     regs_.Restore(masm);
3846     __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
3847                            MacroAssembler::kReturnAtEnd);
3848
3849     __ bind(&dont_need_remembered_set);
3850   }
3851
3852   CheckNeedsToInformIncrementalMarker(
3853       masm,
3854       kReturnOnNoNeedToInformIncrementalMarker,
3855       mode);
3856   InformIncrementalMarker(masm);
3857   regs_.Restore(masm);
3858   __ ret(0);
3859 }
3860
3861
3862 void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) {
3863   regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode());
3864   int argument_count = 3;
3865   __ PrepareCallCFunction(argument_count, regs_.scratch0());
3866   __ mov(Operand(esp, 0 * kPointerSize), regs_.object());
3867   __ mov(Operand(esp, 1 * kPointerSize), regs_.address());  // Slot.
3868   __ mov(Operand(esp, 2 * kPointerSize),
3869          Immediate(ExternalReference::isolate_address(isolate())));
3870
3871   AllowExternalCallThatCantCauseGC scope(masm);
3872   __ CallCFunction(
3873       ExternalReference::incremental_marking_record_write_function(isolate()),
3874       argument_count);
3875
3876   regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode());
3877 }
3878
3879
3880 void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
3881     MacroAssembler* masm,
3882     OnNoNeedToInformIncrementalMarker on_no_need,
3883     Mode mode) {
3884   Label object_is_black, need_incremental, need_incremental_pop_object;
3885
3886   __ mov(regs_.scratch0(), Immediate(~Page::kPageAlignmentMask));
3887   __ and_(regs_.scratch0(), regs_.object());
3888   __ mov(regs_.scratch1(),
3889          Operand(regs_.scratch0(),
3890                  MemoryChunk::kWriteBarrierCounterOffset));
3891   __ sub(regs_.scratch1(), Immediate(1));
3892   __ mov(Operand(regs_.scratch0(),
3893                  MemoryChunk::kWriteBarrierCounterOffset),
3894          regs_.scratch1());
3895   __ j(negative, &need_incremental);
3896
3897   // Let's look at the color of the object:  If it is not black we don't have
3898   // to inform the incremental marker.
3899   __ JumpIfBlack(regs_.object(),
3900                  regs_.scratch0(),
3901                  regs_.scratch1(),
3902                  &object_is_black,
3903                  Label::kNear);
3904
3905   regs_.Restore(masm);
3906   if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
3907     __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
3908                            MacroAssembler::kReturnAtEnd);
3909   } else {
3910     __ ret(0);
3911   }
3912
3913   __ bind(&object_is_black);
3914
3915   // Get the value from the slot.
3916   __ mov(regs_.scratch0(), Operand(regs_.address(), 0));
3917
3918   if (mode == INCREMENTAL_COMPACTION) {
3919     Label ensure_not_white;
3920
3921     __ CheckPageFlag(regs_.scratch0(),  // Contains value.
3922                      regs_.scratch1(),  // Scratch.
3923                      MemoryChunk::kEvacuationCandidateMask,
3924                      zero,
3925                      &ensure_not_white,
3926                      Label::kNear);
3927
3928     __ CheckPageFlag(regs_.object(),
3929                      regs_.scratch1(),  // Scratch.
3930                      MemoryChunk::kSkipEvacuationSlotsRecordingMask,
3931                      not_zero,
3932                      &ensure_not_white,
3933                      Label::kNear);
3934
3935     __ jmp(&need_incremental);
3936
3937     __ bind(&ensure_not_white);
3938   }
3939
3940   // We need an extra register for this, so we push the object register
3941   // temporarily.
3942   __ push(regs_.object());
3943   __ EnsureNotWhite(regs_.scratch0(),  // The value.
3944                     regs_.scratch1(),  // Scratch.
3945                     regs_.object(),  // Scratch.
3946                     &need_incremental_pop_object,
3947                     Label::kNear);
3948   __ pop(regs_.object());
3949
3950   regs_.Restore(masm);
3951   if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
3952     __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
3953                            MacroAssembler::kReturnAtEnd);
3954   } else {
3955     __ ret(0);
3956   }
3957
3958   __ bind(&need_incremental_pop_object);
3959   __ pop(regs_.object());
3960
3961   __ bind(&need_incremental);
3962
3963   // Fall through when we need to inform the incremental marker.
3964 }
3965
3966
3967 void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
3968   // ----------- S t a t e -------------
3969   //  -- eax    : element value to store
3970   //  -- ecx    : element index as smi
3971   //  -- esp[0] : return address
3972   //  -- esp[4] : array literal index in function
3973   //  -- esp[8] : array literal
3974   // clobbers ebx, edx, edi
3975   // -----------------------------------
3976
3977   Label element_done;
3978   Label double_elements;
3979   Label smi_element;
3980   Label slow_elements;
3981   Label slow_elements_from_double;
3982   Label fast_elements;
3983
3984   // Get array literal index, array literal and its map.
3985   __ mov(edx, Operand(esp, 1 * kPointerSize));
3986   __ mov(ebx, Operand(esp, 2 * kPointerSize));
3987   __ mov(edi, FieldOperand(ebx, JSObject::kMapOffset));
3988
3989   __ CheckFastElements(edi, &double_elements);
3990
3991   // Check for FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS elements
3992   __ JumpIfSmi(eax, &smi_element);
3993   __ CheckFastSmiElements(edi, &fast_elements, Label::kNear);
3994
3995   // Store into the array literal requires a elements transition. Call into
3996   // the runtime.
3997
3998   __ bind(&slow_elements);
3999   __ pop(edi);  // Pop return address and remember to put back later for tail
4000                 // call.
4001   __ push(ebx);
4002   __ push(ecx);
4003   __ push(eax);
4004   __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
4005   __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
4006   __ push(edx);
4007   __ push(edi);  // Return return address so that tail call returns to right
4008                  // place.
4009   __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1);
4010
4011   __ bind(&slow_elements_from_double);
4012   __ pop(edx);
4013   __ jmp(&slow_elements);
4014
4015   // Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object.
4016   __ bind(&fast_elements);
4017   __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
4018   __ lea(ecx, FieldOperand(ebx, ecx, times_half_pointer_size,
4019                            FixedArrayBase::kHeaderSize));
4020   __ mov(Operand(ecx, 0), eax);
4021   // Update the write barrier for the array store.
4022   __ RecordWrite(ebx, ecx, eax, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
4023                  OMIT_SMI_CHECK);
4024   __ ret(0);
4025
4026   // Array literal has ElementsKind of FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS,
4027   // and value is Smi.
4028   __ bind(&smi_element);
4029   __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
4030   __ mov(FieldOperand(ebx, ecx, times_half_pointer_size,
4031                       FixedArrayBase::kHeaderSize), eax);
4032   __ ret(0);
4033
4034   // Array literal has ElementsKind of FAST_*_DOUBLE_ELEMENTS.
4035   __ bind(&double_elements);
4036
4037   __ push(edx);
4038   __ mov(edx, FieldOperand(ebx, JSObject::kElementsOffset));
4039   __ StoreNumberToDoubleElements(eax,
4040                                  edx,
4041                                  ecx,
4042                                  edi,
4043                                  &slow_elements_from_double,
4044                                  false);
4045   __ pop(edx);
4046   __ ret(0);
4047 }
4048
4049
4050 void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
4051   CEntryStub ces(isolate(), 1, kSaveFPRegs);
4052   __ call(ces.GetCode(), RelocInfo::CODE_TARGET);
4053   int parameter_count_offset =
4054       StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
4055   __ mov(ebx, MemOperand(ebp, parameter_count_offset));
4056   masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
4057   __ pop(ecx);
4058   int additional_offset =
4059       function_mode() == JS_FUNCTION_STUB_MODE ? kPointerSize : 0;
4060   __ lea(esp, MemOperand(esp, ebx, times_pointer_size, additional_offset));
4061   __ jmp(ecx);  // Return to IC Miss stub, continuation still on stack.
4062 }
4063
4064
4065 void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
4066   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
4067   VectorRawLoadStub stub(isolate(), state());
4068   stub.GenerateForTrampoline(masm);
4069 }
4070
4071
4072 void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
4073   EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
4074   VectorRawKeyedLoadStub stub(isolate());
4075   stub.GenerateForTrampoline(masm);
4076 }
4077
4078
4079 static void HandleArrayCases(MacroAssembler* masm, Register receiver,
4080                              Register key, Register vector, Register slot,
4081                              Register feedback, bool is_polymorphic,
4082                              Label* miss) {
4083   // feedback initially contains the feedback array
4084   Label next, next_loop, prepare_next;
4085   Label load_smi_map, compare_map;
4086   Label start_polymorphic;
4087
4088   __ push(receiver);
4089   __ push(vector);
4090
4091   Register receiver_map = receiver;
4092   Register cached_map = vector;
4093
4094   // Receiver might not be a heap object.
4095   __ JumpIfSmi(receiver, &load_smi_map);
4096   __ mov(receiver_map, FieldOperand(receiver, 0));
4097   __ bind(&compare_map);
4098   __ mov(cached_map, FieldOperand(feedback, FixedArray::OffsetOfElementAt(0)));
4099
4100   // A named keyed load might have a 2 element array, all other cases can count
4101   // on an array with at least 2 {map, handler} pairs, so they can go right
4102   // into polymorphic array handling.
4103   __ cmp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
4104   __ j(not_equal, is_polymorphic ? &start_polymorphic : &next);
4105
4106   // found, now call handler.
4107   Register handler = feedback;
4108   __ mov(handler, FieldOperand(feedback, FixedArray::OffsetOfElementAt(1)));
4109   __ pop(vector);
4110   __ pop(receiver);
4111   __ lea(handler, FieldOperand(handler, Code::kHeaderSize));
4112   __ jmp(handler);
4113
4114   if (!is_polymorphic) {
4115     __ bind(&next);
4116     __ cmp(FieldOperand(feedback, FixedArray::kLengthOffset),
4117            Immediate(Smi::FromInt(2)));
4118     __ j(not_equal, &start_polymorphic);
4119     __ pop(vector);
4120     __ pop(receiver);
4121     __ jmp(miss);
4122   }
4123
4124   // Polymorphic, we have to loop from 2 to N
4125   __ bind(&start_polymorphic);
4126   __ push(key);
4127   Register counter = key;
4128   __ mov(counter, Immediate(Smi::FromInt(2)));
4129   __ bind(&next_loop);
4130   __ mov(cached_map, FieldOperand(feedback, counter, times_half_pointer_size,
4131                                   FixedArray::kHeaderSize));
4132   __ cmp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
4133   __ j(not_equal, &prepare_next);
4134   __ mov(handler, FieldOperand(feedback, counter, times_half_pointer_size,
4135                                FixedArray::kHeaderSize + kPointerSize));
4136   __ pop(key);
4137   __ pop(vector);
4138   __ pop(receiver);
4139   __ lea(handler, FieldOperand(handler, Code::kHeaderSize));
4140   __ jmp(handler);
4141
4142   __ bind(&prepare_next);
4143   __ add(counter, Immediate(Smi::FromInt(2)));
4144   __ cmp(counter, FieldOperand(feedback, FixedArray::kLengthOffset));
4145   __ j(less, &next_loop);
4146
4147   // We exhausted our array of map handler pairs.
4148   __ pop(key);
4149   __ pop(vector);
4150   __ pop(receiver);
4151   __ jmp(miss);
4152
4153   __ bind(&load_smi_map);
4154   __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
4155   __ jmp(&compare_map);
4156 }
4157
4158
4159 static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver,
4160                                   Register key, Register vector, Register slot,
4161                                   Register weak_cell, Label* miss) {
4162   // feedback initially contains the feedback array
4163   Label compare_smi_map;
4164
4165   // Move the weak map into the weak_cell register.
4166   Register ic_map = weak_cell;
4167   __ mov(ic_map, FieldOperand(weak_cell, WeakCell::kValueOffset));
4168
4169   // Receiver might not be a heap object.
4170   __ JumpIfSmi(receiver, &compare_smi_map);
4171   __ cmp(ic_map, FieldOperand(receiver, 0));
4172   __ j(not_equal, miss);
4173   Register handler = weak_cell;
4174   __ mov(handler, FieldOperand(vector, slot, times_half_pointer_size,
4175                                FixedArray::kHeaderSize + kPointerSize));
4176   __ lea(handler, FieldOperand(handler, Code::kHeaderSize));
4177   __ jmp(handler);
4178
4179   // In microbenchmarks, it made sense to unroll this code so that the call to
4180   // the handler is duplicated for a HeapObject receiver and a Smi receiver.
4181   __ bind(&compare_smi_map);
4182   __ CompareRoot(ic_map, Heap::kHeapNumberMapRootIndex);
4183   __ j(not_equal, miss);
4184   __ mov(handler, FieldOperand(vector, slot, times_half_pointer_size,
4185                                FixedArray::kHeaderSize + kPointerSize));
4186   __ lea(handler, FieldOperand(handler, Code::kHeaderSize));
4187   __ jmp(handler);
4188 }
4189
4190
4191 void VectorRawLoadStub::Generate(MacroAssembler* masm) {
4192   GenerateImpl(masm, false);
4193 }
4194
4195
4196 void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
4197   GenerateImpl(masm, true);
4198 }
4199
4200
4201 void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
4202   Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // edx
4203   Register name = VectorLoadICDescriptor::NameRegister();          // ecx
4204   Register vector = VectorLoadICDescriptor::VectorRegister();      // ebx
4205   Register slot = VectorLoadICDescriptor::SlotRegister();          // eax
4206   Register scratch = edi;
4207   __ mov(scratch, FieldOperand(vector, slot, times_half_pointer_size,
4208                                FixedArray::kHeaderSize));
4209
4210   // Is it a weak cell?
4211   Label try_array;
4212   Label not_array, smi_key, key_okay, miss;
4213   __ CompareRoot(FieldOperand(scratch, 0), Heap::kWeakCellMapRootIndex);
4214   __ j(not_equal, &try_array);
4215   HandleMonomorphicCase(masm, receiver, name, vector, slot, scratch, &miss);
4216
4217   // Is it a fixed array?
4218   __ bind(&try_array);
4219   __ CompareRoot(FieldOperand(scratch, 0), Heap::kFixedArrayMapRootIndex);
4220   __ j(not_equal, &not_array);
4221   HandleArrayCases(masm, receiver, name, vector, slot, scratch, true, &miss);
4222
4223   __ bind(&not_array);
4224   __ CompareRoot(scratch, Heap::kmegamorphic_symbolRootIndex);
4225   __ j(not_equal, &miss);
4226   __ push(slot);
4227   __ push(vector);
4228   Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
4229       Code::ComputeHandlerFlags(Code::LOAD_IC));
4230   masm->isolate()->stub_cache()->GenerateProbe(
4231       masm, Code::LOAD_IC, code_flags, false, receiver, name, vector, scratch);
4232   __ pop(vector);
4233   __ pop(slot);
4234
4235   __ bind(&miss);
4236   LoadIC::GenerateMiss(masm);
4237 }
4238
4239
4240 void VectorRawKeyedLoadStub::Generate(MacroAssembler* masm) {
4241   GenerateImpl(masm, false);
4242 }
4243
4244
4245 void VectorRawKeyedLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
4246   GenerateImpl(masm, true);
4247 }
4248
4249
4250 void VectorRawKeyedLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
4251   Register receiver = VectorLoadICDescriptor::ReceiverRegister();  // edx
4252   Register key = VectorLoadICDescriptor::NameRegister();           // ecx
4253   Register vector = VectorLoadICDescriptor::VectorRegister();      // ebx
4254   Register slot = VectorLoadICDescriptor::SlotRegister();          // eax
4255   Register feedback = edi;
4256   __ mov(feedback, FieldOperand(vector, slot, times_half_pointer_size,
4257                                 FixedArray::kHeaderSize));
4258   // Is it a weak cell?
4259   Label try_array;
4260   Label not_array, smi_key, key_okay, miss;
4261   __ CompareRoot(FieldOperand(feedback, 0), Heap::kWeakCellMapRootIndex);
4262   __ j(not_equal, &try_array);
4263   HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback, &miss);
4264
4265   __ bind(&try_array);
4266   // Is it a fixed array?
4267   __ CompareRoot(FieldOperand(feedback, 0), Heap::kFixedArrayMapRootIndex);
4268   __ j(not_equal, &not_array);
4269
4270   // We have a polymorphic element handler.
4271   Label polymorphic, try_poly_name;
4272   __ bind(&polymorphic);
4273   HandleArrayCases(masm, receiver, key, vector, slot, feedback, true, &miss);
4274
4275   __ bind(&not_array);
4276   // Is it generic?
4277   __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
4278   __ j(not_equal, &try_poly_name);
4279   Handle<Code> megamorphic_stub =
4280       KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
4281   __ jmp(megamorphic_stub, RelocInfo::CODE_TARGET);
4282
4283   __ bind(&try_poly_name);
4284   // We might have a name in feedback, and a fixed array in the next slot.
4285   __ cmp(key, feedback);
4286   __ j(not_equal, &miss);
4287   // If the name comparison succeeded, we know we have a fixed array with
4288   // at least one map/handler pair.
4289   __ mov(feedback, FieldOperand(vector, slot, times_half_pointer_size,
4290                                 FixedArray::kHeaderSize + kPointerSize));
4291   HandleArrayCases(masm, receiver, key, vector, slot, feedback, false, &miss);
4292
4293   __ bind(&miss);
4294   KeyedLoadIC::GenerateMiss(masm);
4295 }
4296
4297
4298 void CallICTrampolineStub::Generate(MacroAssembler* masm) {
4299   EmitLoadTypeFeedbackVector(masm, ebx);
4300   CallICStub stub(isolate(), state());
4301   __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
4302 }
4303
4304
4305 void CallIC_ArrayTrampolineStub::Generate(MacroAssembler* masm) {
4306   EmitLoadTypeFeedbackVector(masm, ebx);
4307   CallIC_ArrayStub stub(isolate(), state());
4308   __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
4309 }
4310
4311
4312 void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
4313   if (masm->isolate()->function_entry_hook() != NULL) {
4314     ProfileEntryHookStub stub(masm->isolate());
4315     masm->CallStub(&stub);
4316   }
4317 }
4318
4319
4320 void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
4321   // Save volatile registers.
4322   const int kNumSavedRegisters = 3;
4323   __ push(eax);
4324   __ push(ecx);
4325   __ push(edx);
4326
4327   // Calculate and push the original stack pointer.
4328   __ lea(eax, Operand(esp, (kNumSavedRegisters + 1) * kPointerSize));
4329   __ push(eax);
4330
4331   // Retrieve our return address and use it to calculate the calling
4332   // function's address.
4333   __ mov(eax, Operand(esp, (kNumSavedRegisters + 1) * kPointerSize));
4334   __ sub(eax, Immediate(Assembler::kCallInstructionLength));
4335   __ push(eax);
4336
4337   // Call the entry hook.
4338   DCHECK(isolate()->function_entry_hook() != NULL);
4339   __ call(FUNCTION_ADDR(isolate()->function_entry_hook()),
4340           RelocInfo::RUNTIME_ENTRY);
4341   __ add(esp, Immediate(2 * kPointerSize));
4342
4343   // Restore ecx.
4344   __ pop(edx);
4345   __ pop(ecx);
4346   __ pop(eax);
4347
4348   __ ret(0);
4349 }
4350
4351
4352 template<class T>
4353 static void CreateArrayDispatch(MacroAssembler* masm,
4354                                 AllocationSiteOverrideMode mode) {
4355   if (mode == DISABLE_ALLOCATION_SITES) {
4356     T stub(masm->isolate(),
4357            GetInitialFastElementsKind(),
4358            mode);
4359     __ TailCallStub(&stub);
4360   } else if (mode == DONT_OVERRIDE) {
4361     int last_index = GetSequenceIndexFromFastElementsKind(
4362         TERMINAL_FAST_ELEMENTS_KIND);
4363     for (int i = 0; i <= last_index; ++i) {
4364       Label next;
4365       ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
4366       __ cmp(edx, kind);
4367       __ j(not_equal, &next);
4368       T stub(masm->isolate(), kind);
4369       __ TailCallStub(&stub);
4370       __ bind(&next);
4371     }
4372
4373     // If we reached this point there is a problem.
4374     __ Abort(kUnexpectedElementsKindInArrayConstructor);
4375   } else {
4376     UNREACHABLE();
4377   }
4378 }
4379
4380
4381 static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
4382                                            AllocationSiteOverrideMode mode) {
4383   // ebx - allocation site (if mode != DISABLE_ALLOCATION_SITES)
4384   // edx - kind (if mode != DISABLE_ALLOCATION_SITES)
4385   // eax - number of arguments
4386   // edi - constructor?
4387   // esp[0] - return address
4388   // esp[4] - last argument
4389   Label normal_sequence;
4390   if (mode == DONT_OVERRIDE) {
4391     DCHECK(FAST_SMI_ELEMENTS == 0);
4392     DCHECK(FAST_HOLEY_SMI_ELEMENTS == 1);
4393     DCHECK(FAST_ELEMENTS == 2);
4394     DCHECK(FAST_HOLEY_ELEMENTS == 3);
4395     DCHECK(FAST_DOUBLE_ELEMENTS == 4);
4396     DCHECK(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
4397
4398     // is the low bit set? If so, we are holey and that is good.
4399     __ test_b(edx, 1);
4400     __ j(not_zero, &normal_sequence);
4401   }
4402
4403   // look at the first argument
4404   __ mov(ecx, Operand(esp, kPointerSize));
4405   __ test(ecx, ecx);
4406   __ j(zero, &normal_sequence);
4407
4408   if (mode == DISABLE_ALLOCATION_SITES) {
4409     ElementsKind initial = GetInitialFastElementsKind();
4410     ElementsKind holey_initial = GetHoleyElementsKind(initial);
4411
4412     ArraySingleArgumentConstructorStub stub_holey(masm->isolate(),
4413                                                   holey_initial,
4414                                                   DISABLE_ALLOCATION_SITES);
4415     __ TailCallStub(&stub_holey);
4416
4417     __ bind(&normal_sequence);
4418     ArraySingleArgumentConstructorStub stub(masm->isolate(),
4419                                             initial,
4420                                             DISABLE_ALLOCATION_SITES);
4421     __ TailCallStub(&stub);
4422   } else if (mode == DONT_OVERRIDE) {
4423     // We are going to create a holey array, but our kind is non-holey.
4424     // Fix kind and retry.
4425     __ inc(edx);
4426
4427     if (FLAG_debug_code) {
4428       Handle<Map> allocation_site_map =
4429           masm->isolate()->factory()->allocation_site_map();
4430       __ cmp(FieldOperand(ebx, 0), Immediate(allocation_site_map));
4431       __ Assert(equal, kExpectedAllocationSite);
4432     }
4433
4434     // Save the resulting elements kind in type info. We can't just store r3
4435     // in the AllocationSite::transition_info field because elements kind is
4436     // restricted to a portion of the field...upper bits need to be left alone.
4437     STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
4438     __ add(FieldOperand(ebx, AllocationSite::kTransitionInfoOffset),
4439            Immediate(Smi::FromInt(kFastElementsKindPackedToHoley)));
4440
4441     __ bind(&normal_sequence);
4442     int last_index = GetSequenceIndexFromFastElementsKind(
4443         TERMINAL_FAST_ELEMENTS_KIND);
4444     for (int i = 0; i <= last_index; ++i) {
4445       Label next;
4446       ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
4447       __ cmp(edx, kind);
4448       __ j(not_equal, &next);
4449       ArraySingleArgumentConstructorStub stub(masm->isolate(), kind);
4450       __ TailCallStub(&stub);
4451       __ bind(&next);
4452     }
4453
4454     // If we reached this point there is a problem.
4455     __ Abort(kUnexpectedElementsKindInArrayConstructor);
4456   } else {
4457     UNREACHABLE();
4458   }
4459 }
4460
4461
4462 template<class T>
4463 static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) {
4464   int to_index = GetSequenceIndexFromFastElementsKind(
4465       TERMINAL_FAST_ELEMENTS_KIND);
4466   for (int i = 0; i <= to_index; ++i) {
4467     ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
4468     T stub(isolate, kind);
4469     stub.GetCode();
4470     if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
4471       T stub1(isolate, kind, DISABLE_ALLOCATION_SITES);
4472       stub1.GetCode();
4473     }
4474   }
4475 }
4476
4477
4478 void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) {
4479   ArrayConstructorStubAheadOfTimeHelper<ArrayNoArgumentConstructorStub>(
4480       isolate);
4481   ArrayConstructorStubAheadOfTimeHelper<ArraySingleArgumentConstructorStub>(
4482       isolate);
4483   ArrayConstructorStubAheadOfTimeHelper<ArrayNArgumentsConstructorStub>(
4484       isolate);
4485 }
4486
4487
4488 void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(
4489     Isolate* isolate) {
4490   ElementsKind kinds[2] = { FAST_ELEMENTS, FAST_HOLEY_ELEMENTS };
4491   for (int i = 0; i < 2; i++) {
4492     // For internal arrays we only need a few things
4493     InternalArrayNoArgumentConstructorStub stubh1(isolate, kinds[i]);
4494     stubh1.GetCode();
4495     InternalArraySingleArgumentConstructorStub stubh2(isolate, kinds[i]);
4496     stubh2.GetCode();
4497     InternalArrayNArgumentsConstructorStub stubh3(isolate, kinds[i]);
4498     stubh3.GetCode();
4499   }
4500 }
4501
4502
4503 void ArrayConstructorStub::GenerateDispatchToArrayStub(
4504     MacroAssembler* masm,
4505     AllocationSiteOverrideMode mode) {
4506   if (argument_count() == ANY) {
4507     Label not_zero_case, not_one_case;
4508     __ test(eax, eax);
4509     __ j(not_zero, &not_zero_case);
4510     CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
4511
4512     __ bind(&not_zero_case);
4513     __ cmp(eax, 1);
4514     __ j(greater, &not_one_case);
4515     CreateArrayDispatchOneArgument(masm, mode);
4516
4517     __ bind(&not_one_case);
4518     CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
4519   } else if (argument_count() == NONE) {
4520     CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
4521   } else if (argument_count() == ONE) {
4522     CreateArrayDispatchOneArgument(masm, mode);
4523   } else if (argument_count() == MORE_THAN_ONE) {
4524     CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
4525   } else {
4526     UNREACHABLE();
4527   }
4528 }
4529
4530
4531 void ArrayConstructorStub::Generate(MacroAssembler* masm) {
4532   // ----------- S t a t e -------------
4533   //  -- eax : argc (only if argument_count() is ANY or MORE_THAN_ONE)
4534   //  -- ebx : AllocationSite or undefined
4535   //  -- edi : constructor
4536   //  -- edx : Original constructor
4537   //  -- esp[0] : return address
4538   //  -- esp[4] : last argument
4539   // -----------------------------------
4540   if (FLAG_debug_code) {
4541     // The array construct code is only set for the global and natives
4542     // builtin Array functions which always have maps.
4543
4544     // Initial map for the builtin Array function should be a map.
4545     __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
4546     // Will both indicate a NULL and a Smi.
4547     __ test(ecx, Immediate(kSmiTagMask));
4548     __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
4549     __ CmpObjectType(ecx, MAP_TYPE, ecx);
4550     __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
4551
4552     // We should either have undefined in ebx or a valid AllocationSite
4553     __ AssertUndefinedOrAllocationSite(ebx);
4554   }
4555
4556   Label subclassing;
4557
4558   __ cmp(edx, edi);
4559   __ j(not_equal, &subclassing);
4560
4561   Label no_info;
4562   // If the feedback vector is the undefined value call an array constructor
4563   // that doesn't use AllocationSites.
4564   __ cmp(ebx, isolate()->factory()->undefined_value());
4565   __ j(equal, &no_info);
4566
4567   // Only look at the lower 16 bits of the transition info.
4568   __ mov(edx, FieldOperand(ebx, AllocationSite::kTransitionInfoOffset));
4569   __ SmiUntag(edx);
4570   STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
4571   __ and_(edx, Immediate(AllocationSite::ElementsKindBits::kMask));
4572   GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
4573
4574   __ bind(&no_info);
4575   GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
4576
4577   // Subclassing.
4578   __ bind(&subclassing);
4579   __ pop(ecx);  // return address.
4580   __ push(edi);
4581   __ push(edx);
4582
4583   // Adjust argc.
4584   switch (argument_count()) {
4585     case ANY:
4586     case MORE_THAN_ONE:
4587       __ add(eax, Immediate(2));
4588       break;
4589     case NONE:
4590       __ mov(eax, Immediate(2));
4591       break;
4592     case ONE:
4593       __ mov(eax, Immediate(3));
4594       break;
4595   }
4596
4597   __ push(ecx);
4598   __ JumpToExternalReference(
4599       ExternalReference(Runtime::kArrayConstructorWithSubclassing, isolate()));
4600 }
4601
4602
4603 void InternalArrayConstructorStub::GenerateCase(
4604     MacroAssembler* masm, ElementsKind kind) {
4605   Label not_zero_case, not_one_case;
4606   Label normal_sequence;
4607
4608   __ test(eax, eax);
4609   __ j(not_zero, &not_zero_case);
4610   InternalArrayNoArgumentConstructorStub stub0(isolate(), kind);
4611   __ TailCallStub(&stub0);
4612
4613   __ bind(&not_zero_case);
4614   __ cmp(eax, 1);
4615   __ j(greater, &not_one_case);
4616
4617   if (IsFastPackedElementsKind(kind)) {
4618     // We might need to create a holey array
4619     // look at the first argument
4620     __ mov(ecx, Operand(esp, kPointerSize));
4621     __ test(ecx, ecx);
4622     __ j(zero, &normal_sequence);
4623
4624     InternalArraySingleArgumentConstructorStub
4625         stub1_holey(isolate(), GetHoleyElementsKind(kind));
4626     __ TailCallStub(&stub1_holey);
4627   }
4628
4629   __ bind(&normal_sequence);
4630   InternalArraySingleArgumentConstructorStub stub1(isolate(), kind);
4631   __ TailCallStub(&stub1);
4632
4633   __ bind(&not_one_case);
4634   InternalArrayNArgumentsConstructorStub stubN(isolate(), kind);
4635   __ TailCallStub(&stubN);
4636 }
4637
4638
4639 void InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
4640   // ----------- S t a t e -------------
4641   //  -- eax : argc
4642   //  -- edi : constructor
4643   //  -- esp[0] : return address
4644   //  -- esp[4] : last argument
4645   // -----------------------------------
4646
4647   if (FLAG_debug_code) {
4648     // The array construct code is only set for the global and natives
4649     // builtin Array functions which always have maps.
4650
4651     // Initial map for the builtin Array function should be a map.
4652     __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
4653     // Will both indicate a NULL and a Smi.
4654     __ test(ecx, Immediate(kSmiTagMask));
4655     __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction);
4656     __ CmpObjectType(ecx, MAP_TYPE, ecx);
4657     __ Assert(equal, kUnexpectedInitialMapForArrayFunction);
4658   }
4659
4660   // Figure out the right elements kind
4661   __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
4662
4663   // Load the map's "bit field 2" into |result|. We only need the first byte,
4664   // but the following masking takes care of that anyway.
4665   __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
4666   // Retrieve elements_kind from bit field 2.
4667   __ DecodeField<Map::ElementsKindBits>(ecx);
4668
4669   if (FLAG_debug_code) {
4670     Label done;
4671     __ cmp(ecx, Immediate(FAST_ELEMENTS));
4672     __ j(equal, &done);
4673     __ cmp(ecx, Immediate(FAST_HOLEY_ELEMENTS));
4674     __ Assert(equal,
4675               kInvalidElementsKindForInternalArrayOrInternalPackedArray);
4676     __ bind(&done);
4677   }
4678
4679   Label fast_elements_case;
4680   __ cmp(ecx, Immediate(FAST_ELEMENTS));
4681   __ j(equal, &fast_elements_case);
4682   GenerateCase(masm, FAST_HOLEY_ELEMENTS);
4683
4684   __ bind(&fast_elements_case);
4685   GenerateCase(masm, FAST_ELEMENTS);
4686 }
4687
4688
4689 // Generates an Operand for saving parameters after PrepareCallApiFunction.
4690 static Operand ApiParameterOperand(int index) {
4691   return Operand(esp, index * kPointerSize);
4692 }
4693
4694
4695 // Prepares stack to put arguments (aligns and so on). Reserves
4696 // space for return value if needed (assumes the return value is a handle).
4697 // Arguments must be stored in ApiParameterOperand(0), ApiParameterOperand(1)
4698 // etc. Saves context (esi). If space was reserved for return value then
4699 // stores the pointer to the reserved slot into esi.
4700 static void PrepareCallApiFunction(MacroAssembler* masm, int argc) {
4701   __ EnterApiExitFrame(argc);
4702   if (__ emit_debug_code()) {
4703     __ mov(esi, Immediate(bit_cast<int32_t>(kZapValue)));
4704   }
4705 }
4706
4707
4708 // Calls an API function.  Allocates HandleScope, extracts returned value
4709 // from handle and propagates exceptions.  Clobbers ebx, edi and
4710 // caller-save registers.  Restores context.  On return removes
4711 // stack_space * kPointerSize (GCed).
4712 static void CallApiFunctionAndReturn(MacroAssembler* masm,
4713                                      Register function_address,
4714                                      ExternalReference thunk_ref,
4715                                      Operand thunk_last_arg, int stack_space,
4716                                      Operand* stack_space_operand,
4717                                      Operand return_value_operand,
4718                                      Operand* context_restore_operand) {
4719   Isolate* isolate = masm->isolate();
4720
4721   ExternalReference next_address =
4722       ExternalReference::handle_scope_next_address(isolate);
4723   ExternalReference limit_address =
4724       ExternalReference::handle_scope_limit_address(isolate);
4725   ExternalReference level_address =
4726       ExternalReference::handle_scope_level_address(isolate);
4727
4728   DCHECK(edx.is(function_address));
4729   // Allocate HandleScope in callee-save registers.
4730   __ mov(ebx, Operand::StaticVariable(next_address));
4731   __ mov(edi, Operand::StaticVariable(limit_address));
4732   __ add(Operand::StaticVariable(level_address), Immediate(1));
4733
4734   if (FLAG_log_timer_events) {
4735     FrameScope frame(masm, StackFrame::MANUAL);
4736     __ PushSafepointRegisters();
4737     __ PrepareCallCFunction(1, eax);
4738     __ mov(Operand(esp, 0),
4739            Immediate(ExternalReference::isolate_address(isolate)));
4740     __ CallCFunction(ExternalReference::log_enter_external_function(isolate),
4741                      1);
4742     __ PopSafepointRegisters();
4743   }
4744
4745
4746   Label profiler_disabled;
4747   Label end_profiler_check;
4748   __ mov(eax, Immediate(ExternalReference::is_profiling_address(isolate)));
4749   __ cmpb(Operand(eax, 0), 0);
4750   __ j(zero, &profiler_disabled);
4751
4752   // Additional parameter is the address of the actual getter function.
4753   __ mov(thunk_last_arg, function_address);
4754   // Call the api function.
4755   __ mov(eax, Immediate(thunk_ref));
4756   __ call(eax);
4757   __ jmp(&end_profiler_check);
4758
4759   __ bind(&profiler_disabled);
4760   // Call the api function.
4761   __ call(function_address);
4762   __ bind(&end_profiler_check);
4763
4764   if (FLAG_log_timer_events) {
4765     FrameScope frame(masm, StackFrame::MANUAL);
4766     __ PushSafepointRegisters();
4767     __ PrepareCallCFunction(1, eax);
4768     __ mov(Operand(esp, 0),
4769            Immediate(ExternalReference::isolate_address(isolate)));
4770     __ CallCFunction(ExternalReference::log_leave_external_function(isolate),
4771                      1);
4772     __ PopSafepointRegisters();
4773   }
4774
4775   Label prologue;
4776   // Load the value from ReturnValue
4777   __ mov(eax, return_value_operand);
4778
4779   Label promote_scheduled_exception;
4780   Label delete_allocated_handles;
4781   Label leave_exit_frame;
4782
4783   __ bind(&prologue);
4784   // No more valid handles (the result handle was the last one). Restore
4785   // previous handle scope.
4786   __ mov(Operand::StaticVariable(next_address), ebx);
4787   __ sub(Operand::StaticVariable(level_address), Immediate(1));
4788   __ Assert(above_equal, kInvalidHandleScopeLevel);
4789   __ cmp(edi, Operand::StaticVariable(limit_address));
4790   __ j(not_equal, &delete_allocated_handles);
4791
4792   // Leave the API exit frame.
4793   __ bind(&leave_exit_frame);
4794   bool restore_context = context_restore_operand != NULL;
4795   if (restore_context) {
4796     __ mov(esi, *context_restore_operand);
4797   }
4798   if (stack_space_operand != nullptr) {
4799     __ mov(ebx, *stack_space_operand);
4800   }
4801   __ LeaveApiExitFrame(!restore_context);
4802
4803   // Check if the function scheduled an exception.
4804   ExternalReference scheduled_exception_address =
4805       ExternalReference::scheduled_exception_address(isolate);
4806   __ cmp(Operand::StaticVariable(scheduled_exception_address),
4807          Immediate(isolate->factory()->the_hole_value()));
4808   __ j(not_equal, &promote_scheduled_exception);
4809
4810 #if DEBUG
4811   // Check if the function returned a valid JavaScript value.
4812   Label ok;
4813   Register return_value = eax;
4814   Register map = ecx;
4815
4816   __ JumpIfSmi(return_value, &ok, Label::kNear);
4817   __ mov(map, FieldOperand(return_value, HeapObject::kMapOffset));
4818
4819   __ CmpInstanceType(map, LAST_NAME_TYPE);
4820   __ j(below_equal, &ok, Label::kNear);
4821
4822   __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
4823   __ j(above_equal, &ok, Label::kNear);
4824
4825   __ cmp(map, isolate->factory()->heap_number_map());
4826   __ j(equal, &ok, Label::kNear);
4827
4828   __ cmp(return_value, isolate->factory()->undefined_value());
4829   __ j(equal, &ok, Label::kNear);
4830
4831   __ cmp(return_value, isolate->factory()->true_value());
4832   __ j(equal, &ok, Label::kNear);
4833
4834   __ cmp(return_value, isolate->factory()->false_value());
4835   __ j(equal, &ok, Label::kNear);
4836
4837   __ cmp(return_value, isolate->factory()->null_value());
4838   __ j(equal, &ok, Label::kNear);
4839
4840   __ Abort(kAPICallReturnedInvalidObject);
4841
4842   __ bind(&ok);
4843 #endif
4844
4845   if (stack_space_operand != nullptr) {
4846     DCHECK_EQ(0, stack_space);
4847     __ pop(ecx);
4848     __ add(esp, ebx);
4849     __ jmp(ecx);
4850   } else {
4851     __ ret(stack_space * kPointerSize);
4852   }
4853
4854   // Re-throw by promoting a scheduled exception.
4855   __ bind(&promote_scheduled_exception);
4856   __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1);
4857
4858   // HandleScope limit has changed. Delete allocated extensions.
4859   ExternalReference delete_extensions =
4860       ExternalReference::delete_handle_scope_extensions(isolate);
4861   __ bind(&delete_allocated_handles);
4862   __ mov(Operand::StaticVariable(limit_address), edi);
4863   __ mov(edi, eax);
4864   __ mov(Operand(esp, 0),
4865          Immediate(ExternalReference::isolate_address(isolate)));
4866   __ mov(eax, Immediate(delete_extensions));
4867   __ call(eax);
4868   __ mov(eax, edi);
4869   __ jmp(&leave_exit_frame);
4870 }
4871
4872
4873 static void CallApiFunctionStubHelper(MacroAssembler* masm,
4874                                       const ParameterCount& argc,
4875                                       bool return_first_arg,
4876                                       bool call_data_undefined) {
4877   // ----------- S t a t e -------------
4878   //  -- edi                 : callee
4879   //  -- ebx                 : call_data
4880   //  -- ecx                 : holder
4881   //  -- edx                 : api_function_address
4882   //  -- esi                 : context
4883   //  -- eax                 : number of arguments if argc is a register
4884   //  --
4885   //  -- esp[0]              : return address
4886   //  -- esp[4]              : last argument
4887   //  -- ...
4888   //  -- esp[argc * 4]       : first argument
4889   //  -- esp[(argc + 1) * 4] : receiver
4890   // -----------------------------------
4891
4892   Register callee = edi;
4893   Register call_data = ebx;
4894   Register holder = ecx;
4895   Register api_function_address = edx;
4896   Register context = esi;
4897   Register return_address = eax;
4898
4899   typedef FunctionCallbackArguments FCA;
4900
4901   STATIC_ASSERT(FCA::kContextSaveIndex == 6);
4902   STATIC_ASSERT(FCA::kCalleeIndex == 5);
4903   STATIC_ASSERT(FCA::kDataIndex == 4);
4904   STATIC_ASSERT(FCA::kReturnValueOffset == 3);
4905   STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2);
4906   STATIC_ASSERT(FCA::kIsolateIndex == 1);
4907   STATIC_ASSERT(FCA::kHolderIndex == 0);
4908   STATIC_ASSERT(FCA::kArgsLength == 7);
4909
4910   DCHECK(argc.is_immediate() || eax.is(argc.reg()));
4911
4912   if (argc.is_immediate()) {
4913     __ pop(return_address);
4914     // context save.
4915     __ push(context);
4916   } else {
4917     // pop return address and save context
4918     __ xchg(context, Operand(esp, 0));
4919     return_address = context;
4920   }
4921
4922   // callee
4923   __ push(callee);
4924
4925   // call data
4926   __ push(call_data);
4927
4928   Register scratch = call_data;
4929   if (!call_data_undefined) {
4930     // return value
4931     __ push(Immediate(masm->isolate()->factory()->undefined_value()));
4932     // return value default
4933     __ push(Immediate(masm->isolate()->factory()->undefined_value()));
4934   } else {
4935     // return value
4936     __ push(scratch);
4937     // return value default
4938     __ push(scratch);
4939   }
4940   // isolate
4941   __ push(Immediate(reinterpret_cast<int>(masm->isolate())));
4942   // holder
4943   __ push(holder);
4944
4945   __ mov(scratch, esp);
4946
4947   // push return address
4948   __ push(return_address);
4949
4950   // load context from callee
4951   __ mov(context, FieldOperand(callee, JSFunction::kContextOffset));
4952
4953   // API function gets reference to the v8::Arguments. If CPU profiler
4954   // is enabled wrapper function will be called and we need to pass
4955   // address of the callback as additional parameter, always allocate
4956   // space for it.
4957   const int kApiArgc = 1 + 1;
4958
4959   // Allocate the v8::Arguments structure in the arguments' space since
4960   // it's not controlled by GC.
4961   const int kApiStackSpace = 4;
4962
4963   PrepareCallApiFunction(masm, kApiArgc + kApiStackSpace);
4964
4965   // FunctionCallbackInfo::implicit_args_.
4966   __ mov(ApiParameterOperand(2), scratch);
4967   if (argc.is_immediate()) {
4968     __ add(scratch,
4969            Immediate((argc.immediate() + FCA::kArgsLength - 1) * kPointerSize));
4970     // FunctionCallbackInfo::values_.
4971     __ mov(ApiParameterOperand(3), scratch);
4972     // FunctionCallbackInfo::length_.
4973     __ Move(ApiParameterOperand(4), Immediate(argc.immediate()));
4974     // FunctionCallbackInfo::is_construct_call_.
4975     __ Move(ApiParameterOperand(5), Immediate(0));
4976   } else {
4977     __ lea(scratch, Operand(scratch, argc.reg(), times_pointer_size,
4978                             (FCA::kArgsLength - 1) * kPointerSize));
4979     // FunctionCallbackInfo::values_.
4980     __ mov(ApiParameterOperand(3), scratch);
4981     // FunctionCallbackInfo::length_.
4982     __ mov(ApiParameterOperand(4), argc.reg());
4983     // FunctionCallbackInfo::is_construct_call_.
4984     __ lea(argc.reg(), Operand(argc.reg(), times_pointer_size,
4985                                (FCA::kArgsLength + 1) * kPointerSize));
4986     __ mov(ApiParameterOperand(5), argc.reg());
4987   }
4988
4989   // v8::InvocationCallback's argument.
4990   __ lea(scratch, ApiParameterOperand(2));
4991   __ mov(ApiParameterOperand(0), scratch);
4992
4993   ExternalReference thunk_ref =
4994       ExternalReference::invoke_function_callback(masm->isolate());
4995
4996   Operand context_restore_operand(ebp,
4997                                   (2 + FCA::kContextSaveIndex) * kPointerSize);
4998   // Stores return the first js argument
4999   int return_value_offset = 0;
5000   if (return_first_arg) {
5001     return_value_offset = 2 + FCA::kArgsLength;
5002   } else {
5003     return_value_offset = 2 + FCA::kReturnValueOffset;
5004   }
5005   Operand return_value_operand(ebp, return_value_offset * kPointerSize);
5006   int stack_space = 0;
5007   Operand is_construct_call_operand = ApiParameterOperand(5);
5008   Operand* stack_space_operand = &is_construct_call_operand;
5009   if (argc.is_immediate()) {
5010     stack_space = argc.immediate() + FCA::kArgsLength + 1;
5011     stack_space_operand = nullptr;
5012   }
5013   CallApiFunctionAndReturn(masm, api_function_address, thunk_ref,
5014                            ApiParameterOperand(1), stack_space,
5015                            stack_space_operand, return_value_operand,
5016                            &context_restore_operand);
5017 }
5018
5019
5020 void CallApiFunctionStub::Generate(MacroAssembler* masm) {
5021   bool call_data_undefined = this->call_data_undefined();
5022   CallApiFunctionStubHelper(masm, ParameterCount(eax), false,
5023                             call_data_undefined);
5024 }
5025
5026
5027 void CallApiAccessorStub::Generate(MacroAssembler* masm) {
5028   bool is_store = this->is_store();
5029   int argc = this->argc();
5030   bool call_data_undefined = this->call_data_undefined();
5031   CallApiFunctionStubHelper(masm, ParameterCount(argc), is_store,
5032                             call_data_undefined);
5033 }
5034
5035
5036 void CallApiGetterStub::Generate(MacroAssembler* masm) {
5037   // ----------- S t a t e -------------
5038   //  -- esp[0]                  : return address
5039   //  -- esp[4]                  : name
5040   //  -- esp[8 - kArgsLength*4]  : PropertyCallbackArguments object
5041   //  -- ...
5042   //  -- edx                    : api_function_address
5043   // -----------------------------------
5044   DCHECK(edx.is(ApiGetterDescriptor::function_address()));
5045
5046   // array for v8::Arguments::values_, handler for name and pointer
5047   // to the values (it considered as smi in GC).
5048   const int kStackSpace = PropertyCallbackArguments::kArgsLength + 2;
5049   // Allocate space for opional callback address parameter in case
5050   // CPU profiler is active.
5051   const int kApiArgc = 2 + 1;
5052
5053   Register api_function_address = edx;
5054   Register scratch = ebx;
5055
5056   // load address of name
5057   __ lea(scratch, Operand(esp, 1 * kPointerSize));
5058
5059   PrepareCallApiFunction(masm, kApiArgc);
5060   __ mov(ApiParameterOperand(0), scratch);  // name.
5061   __ add(scratch, Immediate(kPointerSize));
5062   __ mov(ApiParameterOperand(1), scratch);  // arguments pointer.
5063
5064   ExternalReference thunk_ref =
5065       ExternalReference::invoke_accessor_getter_callback(isolate());
5066
5067   CallApiFunctionAndReturn(masm, api_function_address, thunk_ref,
5068                            ApiParameterOperand(2), kStackSpace, nullptr,
5069                            Operand(ebp, 7 * kPointerSize), NULL);
5070 }
5071
5072
5073 #undef __
5074
5075 } }  // namespace v8::internal
5076
5077 #endif  // V8_TARGET_ARCH_X87