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#if V8_TARGET_ARCH_X87
6
7#include "src/base/bits.h"
8#include "src/base/division-by-constant.h"
9#include "src/bootstrapper.h"
10#include "src/codegen.h"
11#include "src/debug/debug.h"
12#include "src/runtime/runtime.h"
13#include "src/x87/frames-x87.h"
14#include "src/x87/macro-assembler-x87.h"
15
16namespace v8 {
17namespace internal {
18
19// -------------------------------------------------------------------------
20// MacroAssembler implementation.
21
22MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size,
23                               CodeObjectRequired create_code_object)
24    : Assembler(arg_isolate, buffer, size),
25      generating_stub_(false),
26      has_frame_(false) {
27  if (create_code_object == CodeObjectRequired::kYes) {
28    code_object_ =
29        Handle<Object>::New(isolate()->heap()->undefined_value(), isolate());
30  }
31}
32
33
34void MacroAssembler::Load(Register dst, const Operand& src, Representation r) {
35  DCHECK(!r.IsDouble());
36  if (r.IsInteger8()) {
37    movsx_b(dst, src);
38  } else if (r.IsUInteger8()) {
39    movzx_b(dst, src);
40  } else if (r.IsInteger16()) {
41    movsx_w(dst, src);
42  } else if (r.IsUInteger16()) {
43    movzx_w(dst, src);
44  } else {
45    mov(dst, src);
46  }
47}
48
49
50void MacroAssembler::Store(Register src, const Operand& dst, Representation r) {
51  DCHECK(!r.IsDouble());
52  if (r.IsInteger8() || r.IsUInteger8()) {
53    mov_b(dst, src);
54  } else if (r.IsInteger16() || r.IsUInteger16()) {
55    mov_w(dst, src);
56  } else {
57    if (r.IsHeapObject()) {
58      AssertNotSmi(src);
59    } else if (r.IsSmi()) {
60      AssertSmi(src);
61    }
62    mov(dst, src);
63  }
64}
65
66
67void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index) {
68  if (isolate()->heap()->RootCanBeTreatedAsConstant(index)) {
69    mov(destination, isolate()->heap()->root_handle(index));
70    return;
71  }
72  ExternalReference roots_array_start =
73      ExternalReference::roots_array_start(isolate());
74  mov(destination, Immediate(index));
75  mov(destination, Operand::StaticArray(destination,
76                                        times_pointer_size,
77                                        roots_array_start));
78}
79
80
81void MacroAssembler::StoreRoot(Register source,
82                               Register scratch,
83                               Heap::RootListIndex index) {
84  DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
85  ExternalReference roots_array_start =
86      ExternalReference::roots_array_start(isolate());
87  mov(scratch, Immediate(index));
88  mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start),
89      source);
90}
91
92
93void MacroAssembler::CompareRoot(Register with,
94                                 Register scratch,
95                                 Heap::RootListIndex index) {
96  ExternalReference roots_array_start =
97      ExternalReference::roots_array_start(isolate());
98  mov(scratch, Immediate(index));
99  cmp(with, Operand::StaticArray(scratch,
100                                times_pointer_size,
101                                roots_array_start));
102}
103
104
105void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) {
106  DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index));
107  cmp(with, isolate()->heap()->root_handle(index));
108}
109
110
111void MacroAssembler::CompareRoot(const Operand& with,
112                                 Heap::RootListIndex index) {
113  DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index));
114  cmp(with, isolate()->heap()->root_handle(index));
115}
116
117
118void MacroAssembler::PushRoot(Heap::RootListIndex index) {
119  DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index));
120  Push(isolate()->heap()->root_handle(index));
121}
122
123#define REG(Name) \
124  { Register::kCode_##Name }
125
126static const Register saved_regs[] = {REG(eax), REG(ecx), REG(edx)};
127
128#undef REG
129
130static const int kNumberOfSavedRegs = sizeof(saved_regs) / sizeof(Register);
131
132void MacroAssembler::PushCallerSaved(SaveFPRegsMode fp_mode,
133                                     Register exclusion1, Register exclusion2,
134                                     Register exclusion3) {
135  // We don't allow a GC during a store buffer overflow so there is no need to
136  // store the registers in any particular way, but we do have to store and
137  // restore them.
138  for (int i = 0; i < kNumberOfSavedRegs; i++) {
139    Register reg = saved_regs[i];
140    if (!reg.is(exclusion1) && !reg.is(exclusion2) && !reg.is(exclusion3)) {
141      push(reg);
142    }
143  }
144  if (fp_mode == kSaveFPRegs) {
145    // Save FPU state in m108byte.
146    sub(esp, Immediate(108));
147    fnsave(Operand(esp, 0));
148  }
149}
150
151void MacroAssembler::PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1,
152                                    Register exclusion2, Register exclusion3) {
153  if (fp_mode == kSaveFPRegs) {
154    // Restore FPU state in m108byte.
155    frstor(Operand(esp, 0));
156    add(esp, Immediate(108));
157  }
158
159  for (int i = kNumberOfSavedRegs - 1; i >= 0; i--) {
160    Register reg = saved_regs[i];
161    if (!reg.is(exclusion1) && !reg.is(exclusion2) && !reg.is(exclusion3)) {
162      pop(reg);
163    }
164  }
165}
166
167void MacroAssembler::InNewSpace(Register object, Register scratch, Condition cc,
168                                Label* condition_met,
169                                Label::Distance distance) {
170  CheckPageFlag(object, scratch, MemoryChunk::kIsInNewSpaceMask, cc,
171                condition_met, distance);
172}
173
174
175void MacroAssembler::RememberedSetHelper(
176    Register object,  // Only used for debug checks.
177    Register addr, Register scratch, SaveFPRegsMode save_fp,
178    MacroAssembler::RememberedSetFinalAction and_then) {
179  Label done;
180  if (emit_debug_code()) {
181    Label ok;
182    JumpIfNotInNewSpace(object, scratch, &ok, Label::kNear);
183    int3();
184    bind(&ok);
185  }
186  // Load store buffer top.
187  ExternalReference store_buffer =
188      ExternalReference::store_buffer_top(isolate());
189  mov(scratch, Operand::StaticVariable(store_buffer));
190  // Store pointer to buffer.
191  mov(Operand(scratch, 0), addr);
192  // Increment buffer top.
193  add(scratch, Immediate(kPointerSize));
194  // Write back new top of buffer.
195  mov(Operand::StaticVariable(store_buffer), scratch);
196  // Call stub on end of buffer.
197  // Check for end of buffer.
198  test(scratch, Immediate(StoreBuffer::kStoreBufferMask));
199  if (and_then == kReturnAtEnd) {
200    Label buffer_overflowed;
201    j(equal, &buffer_overflowed, Label::kNear);
202    ret(0);
203    bind(&buffer_overflowed);
204  } else {
205    DCHECK(and_then == kFallThroughAtEnd);
206    j(not_equal, &done, Label::kNear);
207  }
208  StoreBufferOverflowStub store_buffer_overflow(isolate(), save_fp);
209  CallStub(&store_buffer_overflow);
210  if (and_then == kReturnAtEnd) {
211    ret(0);
212  } else {
213    DCHECK(and_then == kFallThroughAtEnd);
214    bind(&done);
215  }
216}
217
218
219void MacroAssembler::ClampTOSToUint8(Register result_reg) {
220  Label done, conv_failure;
221  sub(esp, Immediate(kPointerSize));
222  fnclex();
223  fist_s(Operand(esp, 0));
224  pop(result_reg);
225  X87CheckIA();
226  j(equal, &conv_failure, Label::kNear);
227  test(result_reg, Immediate(0xFFFFFF00));
228  j(zero, &done, Label::kNear);
229  setcc(sign, result_reg);
230  sub(result_reg, Immediate(1));
231  and_(result_reg, Immediate(255));
232  jmp(&done, Label::kNear);
233  bind(&conv_failure);
234  fnclex();
235  fldz();
236  fld(1);
237  FCmp();
238  setcc(below, result_reg);  // 1 if negative, 0 if positive.
239  dec_b(result_reg);         // 0 if negative, 255 if positive.
240  bind(&done);
241}
242
243
244void MacroAssembler::ClampUint8(Register reg) {
245  Label done;
246  test(reg, Immediate(0xFFFFFF00));
247  j(zero, &done, Label::kNear);
248  setcc(negative, reg);  // 1 if negative, 0 if positive.
249  dec_b(reg);  // 0 if negative, 255 if positive.
250  bind(&done);
251}
252
253
254void MacroAssembler::SlowTruncateToI(Register result_reg,
255                                     Register input_reg,
256                                     int offset) {
257  DoubleToIStub stub(isolate(), input_reg, result_reg, offset, true);
258  call(stub.GetCode(), RelocInfo::CODE_TARGET);
259}
260
261
262void MacroAssembler::TruncateX87TOSToI(Register result_reg) {
263  sub(esp, Immediate(kDoubleSize));
264  fst_d(MemOperand(esp, 0));
265  SlowTruncateToI(result_reg, esp, 0);
266  add(esp, Immediate(kDoubleSize));
267}
268
269
270void MacroAssembler::X87TOSToI(Register result_reg,
271                               MinusZeroMode minus_zero_mode,
272                               Label* lost_precision, Label* is_nan,
273                               Label* minus_zero, Label::Distance dst) {
274  Label done;
275  sub(esp, Immediate(kPointerSize));
276  fld(0);
277  fist_s(MemOperand(esp, 0));
278  fild_s(MemOperand(esp, 0));
279  pop(result_reg);
280  FCmp();
281  j(not_equal, lost_precision, dst);
282  j(parity_even, is_nan, dst);
283  if (minus_zero_mode == FAIL_ON_MINUS_ZERO) {
284    test(result_reg, Operand(result_reg));
285    j(not_zero, &done, Label::kNear);
286    // To check for minus zero, we load the value again as float, and check
287    // if that is still 0.
288    sub(esp, Immediate(kPointerSize));
289    fst_s(MemOperand(esp, 0));
290    pop(result_reg);
291    test(result_reg, Operand(result_reg));
292    j(not_zero, minus_zero, dst);
293  }
294  bind(&done);
295}
296
297
298void MacroAssembler::TruncateHeapNumberToI(Register result_reg,
299                                           Register input_reg) {
300  Label done, slow_case;
301
302  SlowTruncateToI(result_reg, input_reg);
303  bind(&done);
304}
305
306
307void MacroAssembler::LoadUint32NoSSE2(const Operand& src) {
308  Label done;
309  push(src);
310  fild_s(Operand(esp, 0));
311  cmp(src, Immediate(0));
312  j(not_sign, &done, Label::kNear);
313  ExternalReference uint32_bias =
314        ExternalReference::address_of_uint32_bias();
315  fld_d(Operand::StaticVariable(uint32_bias));
316  faddp(1);
317  bind(&done);
318  add(esp, Immediate(kPointerSize));
319}
320
321
322void MacroAssembler::RecordWriteArray(
323    Register object, Register value, Register index, SaveFPRegsMode save_fp,
324    RememberedSetAction remembered_set_action, SmiCheck smi_check,
325    PointersToHereCheck pointers_to_here_check_for_value) {
326  // First, check if a write barrier is even needed. The tests below
327  // catch stores of Smis.
328  Label done;
329
330  // Skip barrier if writing a smi.
331  if (smi_check == INLINE_SMI_CHECK) {
332    DCHECK_EQ(0, kSmiTag);
333    test(value, Immediate(kSmiTagMask));
334    j(zero, &done);
335  }
336
337  // Array access: calculate the destination address in the same manner as
338  // KeyedStoreIC::GenerateGeneric.  Multiply a smi by 2 to get an offset
339  // into an array of words.
340  Register dst = index;
341  lea(dst, Operand(object, index, times_half_pointer_size,
342                   FixedArray::kHeaderSize - kHeapObjectTag));
343
344  RecordWrite(object, dst, value, save_fp, remembered_set_action,
345              OMIT_SMI_CHECK, pointers_to_here_check_for_value);
346
347  bind(&done);
348
349  // Clobber clobbered input registers when running with the debug-code flag
350  // turned on to provoke errors.
351  if (emit_debug_code()) {
352    mov(value, Immediate(bit_cast<int32_t>(kZapValue)));
353    mov(index, Immediate(bit_cast<int32_t>(kZapValue)));
354  }
355}
356
357
358void MacroAssembler::RecordWriteField(
359    Register object, int offset, Register value, Register dst,
360    SaveFPRegsMode save_fp, RememberedSetAction remembered_set_action,
361    SmiCheck smi_check, PointersToHereCheck pointers_to_here_check_for_value) {
362  // First, check if a write barrier is even needed. The tests below
363  // catch stores of Smis.
364  Label done;
365
366  // Skip barrier if writing a smi.
367  if (smi_check == INLINE_SMI_CHECK) {
368    JumpIfSmi(value, &done, Label::kNear);
369  }
370
371  // Although the object register is tagged, the offset is relative to the start
372  // of the object, so so offset must be a multiple of kPointerSize.
373  DCHECK(IsAligned(offset, kPointerSize));
374
375  lea(dst, FieldOperand(object, offset));
376  if (emit_debug_code()) {
377    Label ok;
378    test_b(dst, Immediate((1 << kPointerSizeLog2) - 1));
379    j(zero, &ok, Label::kNear);
380    int3();
381    bind(&ok);
382  }
383
384  RecordWrite(object, dst, value, save_fp, remembered_set_action,
385              OMIT_SMI_CHECK, pointers_to_here_check_for_value);
386
387  bind(&done);
388
389  // Clobber clobbered input registers when running with the debug-code flag
390  // turned on to provoke errors.
391  if (emit_debug_code()) {
392    mov(value, Immediate(bit_cast<int32_t>(kZapValue)));
393    mov(dst, Immediate(bit_cast<int32_t>(kZapValue)));
394  }
395}
396
397
398void MacroAssembler::RecordWriteForMap(Register object, Handle<Map> map,
399                                       Register scratch1, Register scratch2,
400                                       SaveFPRegsMode save_fp) {
401  Label done;
402
403  Register address = scratch1;
404  Register value = scratch2;
405  if (emit_debug_code()) {
406    Label ok;
407    lea(address, FieldOperand(object, HeapObject::kMapOffset));
408    test_b(address, Immediate((1 << kPointerSizeLog2) - 1));
409    j(zero, &ok, Label::kNear);
410    int3();
411    bind(&ok);
412  }
413
414  DCHECK(!object.is(value));
415  DCHECK(!object.is(address));
416  DCHECK(!value.is(address));
417  AssertNotSmi(object);
418
419  if (!FLAG_incremental_marking) {
420    return;
421  }
422
423  // Compute the address.
424  lea(address, FieldOperand(object, HeapObject::kMapOffset));
425
426  // A single check of the map's pages interesting flag suffices, since it is
427  // only set during incremental collection, and then it's also guaranteed that
428  // the from object's page's interesting flag is also set.  This optimization
429  // relies on the fact that maps can never be in new space.
430  DCHECK(!isolate()->heap()->InNewSpace(*map));
431  CheckPageFlagForMap(map,
432                      MemoryChunk::kPointersToHereAreInterestingMask,
433                      zero,
434                      &done,
435                      Label::kNear);
436
437  RecordWriteStub stub(isolate(), object, value, address, OMIT_REMEMBERED_SET,
438                       save_fp);
439  CallStub(&stub);
440
441  bind(&done);
442
443  // Count number of write barriers in generated code.
444  isolate()->counters()->write_barriers_static()->Increment();
445  IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1);
446
447  // Clobber clobbered input registers when running with the debug-code flag
448  // turned on to provoke errors.
449  if (emit_debug_code()) {
450    mov(value, Immediate(bit_cast<int32_t>(kZapValue)));
451    mov(scratch1, Immediate(bit_cast<int32_t>(kZapValue)));
452    mov(scratch2, Immediate(bit_cast<int32_t>(kZapValue)));
453  }
454}
455
456
457void MacroAssembler::RecordWrite(
458    Register object, Register address, Register value, SaveFPRegsMode fp_mode,
459    RememberedSetAction remembered_set_action, SmiCheck smi_check,
460    PointersToHereCheck pointers_to_here_check_for_value) {
461  DCHECK(!object.is(value));
462  DCHECK(!object.is(address));
463  DCHECK(!value.is(address));
464  AssertNotSmi(object);
465
466  if (remembered_set_action == OMIT_REMEMBERED_SET &&
467      !FLAG_incremental_marking) {
468    return;
469  }
470
471  if (emit_debug_code()) {
472    Label ok;
473    cmp(value, Operand(address, 0));
474    j(equal, &ok, Label::kNear);
475    int3();
476    bind(&ok);
477  }
478
479  // First, check if a write barrier is even needed. The tests below
480  // catch stores of Smis and stores into young gen.
481  Label done;
482
483  if (smi_check == INLINE_SMI_CHECK) {
484    // Skip barrier if writing a smi.
485    JumpIfSmi(value, &done, Label::kNear);
486  }
487
488  if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) {
489    CheckPageFlag(value,
490                  value,  // Used as scratch.
491                  MemoryChunk::kPointersToHereAreInterestingMask,
492                  zero,
493                  &done,
494                  Label::kNear);
495  }
496  CheckPageFlag(object,
497                value,  // Used as scratch.
498                MemoryChunk::kPointersFromHereAreInterestingMask,
499                zero,
500                &done,
501                Label::kNear);
502
503  RecordWriteStub stub(isolate(), object, value, address, remembered_set_action,
504                       fp_mode);
505  CallStub(&stub);
506
507  bind(&done);
508
509  // Count number of write barriers in generated code.
510  isolate()->counters()->write_barriers_static()->Increment();
511  IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1);
512
513  // Clobber clobbered registers when running with the debug-code flag
514  // turned on to provoke errors.
515  if (emit_debug_code()) {
516    mov(address, Immediate(bit_cast<int32_t>(kZapValue)));
517    mov(value, Immediate(bit_cast<int32_t>(kZapValue)));
518  }
519}
520
521void MacroAssembler::RecordWriteCodeEntryField(Register js_function,
522                                               Register code_entry,
523                                               Register scratch) {
524  const int offset = JSFunction::kCodeEntryOffset;
525
526  // Since a code entry (value) is always in old space, we don't need to update
527  // remembered set. If incremental marking is off, there is nothing for us to
528  // do.
529  if (!FLAG_incremental_marking) return;
530
531  DCHECK(!js_function.is(code_entry));
532  DCHECK(!js_function.is(scratch));
533  DCHECK(!code_entry.is(scratch));
534  AssertNotSmi(js_function);
535
536  if (emit_debug_code()) {
537    Label ok;
538    lea(scratch, FieldOperand(js_function, offset));
539    cmp(code_entry, Operand(scratch, 0));
540    j(equal, &ok, Label::kNear);
541    int3();
542    bind(&ok);
543  }
544
545  // First, check if a write barrier is even needed. The tests below
546  // catch stores of Smis and stores into young gen.
547  Label done;
548
549  CheckPageFlag(code_entry, scratch,
550                MemoryChunk::kPointersToHereAreInterestingMask, zero, &done,
551                Label::kNear);
552  CheckPageFlag(js_function, scratch,
553                MemoryChunk::kPointersFromHereAreInterestingMask, zero, &done,
554                Label::kNear);
555
556  // Save input registers.
557  push(js_function);
558  push(code_entry);
559
560  const Register dst = scratch;
561  lea(dst, FieldOperand(js_function, offset));
562
563  // Save caller-saved registers.
564  PushCallerSaved(kDontSaveFPRegs, js_function, code_entry);
565
566  int argument_count = 3;
567  PrepareCallCFunction(argument_count, code_entry);
568  mov(Operand(esp, 0 * kPointerSize), js_function);
569  mov(Operand(esp, 1 * kPointerSize), dst);  // Slot.
570  mov(Operand(esp, 2 * kPointerSize),
571      Immediate(ExternalReference::isolate_address(isolate())));
572
573  {
574    AllowExternalCallThatCantCauseGC scope(this);
575    CallCFunction(
576        ExternalReference::incremental_marking_record_write_code_entry_function(
577            isolate()),
578        argument_count);
579  }
580
581  // Restore caller-saved registers.
582  PopCallerSaved(kDontSaveFPRegs, js_function, code_entry);
583
584  // Restore input registers.
585  pop(code_entry);
586  pop(js_function);
587
588  bind(&done);
589}
590
591void MacroAssembler::DebugBreak() {
592  Move(eax, Immediate(0));
593  mov(ebx, Immediate(ExternalReference(Runtime::kHandleDebuggerStatement,
594                                       isolate())));
595  CEntryStub ces(isolate(), 1);
596  call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT);
597}
598
599void MacroAssembler::ShlPair(Register high, Register low, uint8_t shift) {
600  if (shift >= 32) {
601    mov(high, low);
602    shl(high, shift - 32);
603    xor_(low, low);
604  } else {
605    shld(high, low, shift);
606    shl(low, shift);
607  }
608}
609
610void MacroAssembler::ShlPair_cl(Register high, Register low) {
611  shld_cl(high, low);
612  shl_cl(low);
613  Label done;
614  test(ecx, Immediate(0x20));
615  j(equal, &done, Label::kNear);
616  mov(high, low);
617  xor_(low, low);
618  bind(&done);
619}
620
621void MacroAssembler::ShrPair(Register high, Register low, uint8_t shift) {
622  if (shift >= 32) {
623    mov(low, high);
624    shr(low, shift - 32);
625    xor_(high, high);
626  } else {
627    shrd(high, low, shift);
628    shr(high, shift);
629  }
630}
631
632void MacroAssembler::ShrPair_cl(Register high, Register low) {
633  shrd_cl(low, high);
634  shr_cl(high);
635  Label done;
636  test(ecx, Immediate(0x20));
637  j(equal, &done, Label::kNear);
638  mov(low, high);
639  xor_(high, high);
640  bind(&done);
641}
642
643void MacroAssembler::SarPair(Register high, Register low, uint8_t shift) {
644  if (shift >= 32) {
645    mov(low, high);
646    sar(low, shift - 32);
647    sar(high, 31);
648  } else {
649    shrd(high, low, shift);
650    sar(high, shift);
651  }
652}
653
654void MacroAssembler::SarPair_cl(Register high, Register low) {
655  shrd_cl(low, high);
656  sar_cl(high);
657  Label done;
658  test(ecx, Immediate(0x20));
659  j(equal, &done, Label::kNear);
660  mov(low, high);
661  sar(high, 31);
662  bind(&done);
663}
664
665bool MacroAssembler::IsUnsafeImmediate(const Immediate& x) {
666  static const int kMaxImmediateBits = 17;
667  if (!RelocInfo::IsNone(x.rmode_)) return false;
668  return !is_intn(x.x_, kMaxImmediateBits);
669}
670
671
672void MacroAssembler::SafeMove(Register dst, const Immediate& x) {
673  if (IsUnsafeImmediate(x) && jit_cookie() != 0) {
674    Move(dst, Immediate(x.x_ ^ jit_cookie()));
675    xor_(dst, jit_cookie());
676  } else {
677    Move(dst, x);
678  }
679}
680
681
682void MacroAssembler::SafePush(const Immediate& x) {
683  if (IsUnsafeImmediate(x) && jit_cookie() != 0) {
684    push(Immediate(x.x_ ^ jit_cookie()));
685    xor_(Operand(esp, 0), Immediate(jit_cookie()));
686  } else {
687    push(x);
688  }
689}
690
691
692void MacroAssembler::CmpObjectType(Register heap_object,
693                                   InstanceType type,
694                                   Register map) {
695  mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
696  CmpInstanceType(map, type);
697}
698
699
700void MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
701  cmpb(FieldOperand(map, Map::kInstanceTypeOffset), Immediate(type));
702}
703
704void MacroAssembler::CompareMap(Register obj, Handle<Map> map) {
705  cmp(FieldOperand(obj, HeapObject::kMapOffset), map);
706}
707
708
709void MacroAssembler::CheckMap(Register obj,
710                              Handle<Map> map,
711                              Label* fail,
712                              SmiCheckType smi_check_type) {
713  if (smi_check_type == DO_SMI_CHECK) {
714    JumpIfSmi(obj, fail);
715  }
716
717  CompareMap(obj, map);
718  j(not_equal, fail);
719}
720
721
722void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1,
723                                     Register scratch2, Handle<WeakCell> cell,
724                                     Handle<Code> success,
725                                     SmiCheckType smi_check_type) {
726  Label fail;
727  if (smi_check_type == DO_SMI_CHECK) {
728    JumpIfSmi(obj, &fail);
729  }
730  mov(scratch1, FieldOperand(obj, HeapObject::kMapOffset));
731  CmpWeakValue(scratch1, cell, scratch2);
732  j(equal, success);
733
734  bind(&fail);
735}
736
737
738Condition MacroAssembler::IsObjectStringType(Register heap_object,
739                                             Register map,
740                                             Register instance_type) {
741  mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
742  movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
743  STATIC_ASSERT(kNotStringTag != 0);
744  test(instance_type, Immediate(kIsNotStringMask));
745  return zero;
746}
747
748
749Condition MacroAssembler::IsObjectNameType(Register heap_object,
750                                           Register map,
751                                           Register instance_type) {
752  mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
753  movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
754  cmpb(instance_type, Immediate(LAST_NAME_TYPE));
755  return below_equal;
756}
757
758
759void MacroAssembler::FCmp() {
760  fucompp();
761  push(eax);
762  fnstsw_ax();
763  sahf();
764  pop(eax);
765}
766
767
768void MacroAssembler::FXamMinusZero() {
769  fxam();
770  push(eax);
771  fnstsw_ax();
772  and_(eax, Immediate(0x4700));
773  // For minus zero, C3 == 1 && C1 == 1.
774  cmp(eax, Immediate(0x4200));
775  pop(eax);
776  fstp(0);
777}
778
779
780void MacroAssembler::FXamSign() {
781  fxam();
782  push(eax);
783  fnstsw_ax();
784  // For negative value (including -0.0), C1 == 1.
785  and_(eax, Immediate(0x0200));
786  pop(eax);
787  fstp(0);
788}
789
790
791void MacroAssembler::X87CheckIA() {
792  push(eax);
793  fnstsw_ax();
794  // For #IA, IE == 1 && SF == 0.
795  and_(eax, Immediate(0x0041));
796  cmp(eax, Immediate(0x0001));
797  pop(eax);
798}
799
800
801// rc=00B, round to nearest.
802// rc=01B, round down.
803// rc=10B, round up.
804// rc=11B, round toward zero.
805void MacroAssembler::X87SetRC(int rc) {
806  sub(esp, Immediate(kPointerSize));
807  fnstcw(MemOperand(esp, 0));
808  and_(MemOperand(esp, 0), Immediate(0xF3FF));
809  or_(MemOperand(esp, 0), Immediate(rc));
810  fldcw(MemOperand(esp, 0));
811  add(esp, Immediate(kPointerSize));
812}
813
814
815void MacroAssembler::X87SetFPUCW(int cw) {
816  RecordComment("-- X87SetFPUCW start --");
817  push(Immediate(cw));
818  fldcw(MemOperand(esp, 0));
819  add(esp, Immediate(kPointerSize));
820  RecordComment("-- X87SetFPUCW end--");
821}
822
823
824void MacroAssembler::AssertNumber(Register object) {
825  if (emit_debug_code()) {
826    Label ok;
827    JumpIfSmi(object, &ok);
828    cmp(FieldOperand(object, HeapObject::kMapOffset),
829        isolate()->factory()->heap_number_map());
830    Check(equal, kOperandNotANumber);
831    bind(&ok);
832  }
833}
834
835void MacroAssembler::AssertNotNumber(Register object) {
836  if (emit_debug_code()) {
837    test(object, Immediate(kSmiTagMask));
838    Check(not_equal, kOperandIsANumber);
839    cmp(FieldOperand(object, HeapObject::kMapOffset),
840        isolate()->factory()->heap_number_map());
841    Check(not_equal, kOperandIsANumber);
842  }
843}
844
845void MacroAssembler::AssertSmi(Register object) {
846  if (emit_debug_code()) {
847    test(object, Immediate(kSmiTagMask));
848    Check(equal, kOperandIsNotASmi);
849  }
850}
851
852
853void MacroAssembler::AssertString(Register object) {
854  if (emit_debug_code()) {
855    test(object, Immediate(kSmiTagMask));
856    Check(not_equal, kOperandIsASmiAndNotAString);
857    push(object);
858    mov(object, FieldOperand(object, HeapObject::kMapOffset));
859    CmpInstanceType(object, FIRST_NONSTRING_TYPE);
860    pop(object);
861    Check(below, kOperandIsNotAString);
862  }
863}
864
865
866void MacroAssembler::AssertName(Register object) {
867  if (emit_debug_code()) {
868    test(object, Immediate(kSmiTagMask));
869    Check(not_equal, kOperandIsASmiAndNotAName);
870    push(object);
871    mov(object, FieldOperand(object, HeapObject::kMapOffset));
872    CmpInstanceType(object, LAST_NAME_TYPE);
873    pop(object);
874    Check(below_equal, kOperandIsNotAName);
875  }
876}
877
878
879void MacroAssembler::AssertFunction(Register object) {
880  if (emit_debug_code()) {
881    test(object, Immediate(kSmiTagMask));
882    Check(not_equal, kOperandIsASmiAndNotAFunction);
883    Push(object);
884    CmpObjectType(object, JS_FUNCTION_TYPE, object);
885    Pop(object);
886    Check(equal, kOperandIsNotAFunction);
887  }
888}
889
890
891void MacroAssembler::AssertBoundFunction(Register object) {
892  if (emit_debug_code()) {
893    test(object, Immediate(kSmiTagMask));
894    Check(not_equal, kOperandIsASmiAndNotABoundFunction);
895    Push(object);
896    CmpObjectType(object, JS_BOUND_FUNCTION_TYPE, object);
897    Pop(object);
898    Check(equal, kOperandIsNotABoundFunction);
899  }
900}
901
902void MacroAssembler::AssertGeneratorObject(Register object) {
903  if (emit_debug_code()) {
904    test(object, Immediate(kSmiTagMask));
905    Check(not_equal, kOperandIsASmiAndNotAGeneratorObject);
906    Push(object);
907    CmpObjectType(object, JS_GENERATOR_OBJECT_TYPE, object);
908    Pop(object);
909    Check(equal, kOperandIsNotAGeneratorObject);
910  }
911}
912
913void MacroAssembler::AssertReceiver(Register object) {
914  if (emit_debug_code()) {
915    test(object, Immediate(kSmiTagMask));
916    Check(not_equal, kOperandIsASmiAndNotAReceiver);
917    Push(object);
918    STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
919    CmpObjectType(object, FIRST_JS_RECEIVER_TYPE, object);
920    Pop(object);
921    Check(above_equal, kOperandIsNotAReceiver);
922  }
923}
924
925void MacroAssembler::AssertUndefinedOrAllocationSite(Register object) {
926  if (emit_debug_code()) {
927    Label done_checking;
928    AssertNotSmi(object);
929    cmp(object, isolate()->factory()->undefined_value());
930    j(equal, &done_checking);
931    cmp(FieldOperand(object, 0),
932        Immediate(isolate()->factory()->allocation_site_map()));
933    Assert(equal, kExpectedUndefinedOrCell);
934    bind(&done_checking);
935  }
936}
937
938
939void MacroAssembler::AssertNotSmi(Register object) {
940  if (emit_debug_code()) {
941    test(object, Immediate(kSmiTagMask));
942    Check(not_equal, kOperandIsASmi);
943  }
944}
945
946void MacroAssembler::StubPrologue(StackFrame::Type type) {
947  push(ebp);  // Caller's frame pointer.
948  mov(ebp, esp);
949  push(Immediate(Smi::FromInt(type)));
950}
951
952
953void MacroAssembler::Prologue(bool code_pre_aging) {
954  PredictableCodeSizeScope predictible_code_size_scope(this,
955      kNoCodeAgeSequenceLength);
956  if (code_pre_aging) {
957      // Pre-age the code.
958    call(isolate()->builtins()->MarkCodeAsExecutedOnce(),
959        RelocInfo::CODE_AGE_SEQUENCE);
960    Nop(kNoCodeAgeSequenceLength - Assembler::kCallInstructionLength);
961  } else {
962    push(ebp);  // Caller's frame pointer.
963    mov(ebp, esp);
964    push(esi);  // Callee's context.
965    push(edi);  // Callee's JS function.
966  }
967}
968
969void MacroAssembler::EmitLoadFeedbackVector(Register vector) {
970  mov(vector, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
971  mov(vector, FieldOperand(vector, JSFunction::kFeedbackVectorOffset));
972  mov(vector, FieldOperand(vector, Cell::kValueOffset));
973}
974
975
976void MacroAssembler::EnterFrame(StackFrame::Type type,
977                                bool load_constant_pool_pointer_reg) {
978  // Out-of-line constant pool not implemented on x87.
979  UNREACHABLE();
980}
981
982
983void MacroAssembler::EnterFrame(StackFrame::Type type) {
984  push(ebp);
985  mov(ebp, esp);
986  push(Immediate(Smi::FromInt(type)));
987  if (type == StackFrame::INTERNAL) {
988    push(Immediate(CodeObject()));
989  }
990  if (emit_debug_code()) {
991    cmp(Operand(esp, 0), Immediate(isolate()->factory()->undefined_value()));
992    Check(not_equal, kCodeObjectNotProperlyPatched);
993  }
994}
995
996
997void MacroAssembler::LeaveFrame(StackFrame::Type type) {
998  if (emit_debug_code()) {
999    cmp(Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset),
1000        Immediate(Smi::FromInt(type)));
1001    Check(equal, kStackFrameTypesMustMatch);
1002  }
1003  leave();
1004}
1005
1006void MacroAssembler::EnterBuiltinFrame(Register context, Register target,
1007                                       Register argc) {
1008  Push(ebp);
1009  Move(ebp, esp);
1010  Push(context);
1011  Push(target);
1012  Push(argc);
1013}
1014
1015void MacroAssembler::LeaveBuiltinFrame(Register context, Register target,
1016                                       Register argc) {
1017  Pop(argc);
1018  Pop(target);
1019  Pop(context);
1020  leave();
1021}
1022
1023void MacroAssembler::EnterExitFramePrologue(StackFrame::Type frame_type) {
1024  DCHECK(frame_type == StackFrame::EXIT ||
1025         frame_type == StackFrame::BUILTIN_EXIT);
1026
1027  // Set up the frame structure on the stack.
1028  DCHECK_EQ(+2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement);
1029  DCHECK_EQ(+1 * kPointerSize, ExitFrameConstants::kCallerPCOffset);
1030  DCHECK_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset);
1031  push(ebp);
1032  mov(ebp, esp);
1033
1034  // Reserve room for entry stack pointer and push the code object.
1035  push(Immediate(Smi::FromInt(frame_type)));
1036  DCHECK_EQ(-2 * kPointerSize, ExitFrameConstants::kSPOffset);
1037  push(Immediate(0));  // Saved entry sp, patched before call.
1038  DCHECK_EQ(-3 * kPointerSize, ExitFrameConstants::kCodeOffset);
1039  push(Immediate(CodeObject()));  // Accessed from ExitFrame::code_slot.
1040
1041  // Save the frame pointer and the context in top.
1042  ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress, isolate());
1043  ExternalReference context_address(Isolate::kContextAddress, isolate());
1044  ExternalReference c_function_address(Isolate::kCFunctionAddress, isolate());
1045  mov(Operand::StaticVariable(c_entry_fp_address), ebp);
1046  mov(Operand::StaticVariable(context_address), esi);
1047  mov(Operand::StaticVariable(c_function_address), ebx);
1048}
1049
1050
1051void MacroAssembler::EnterExitFrameEpilogue(int argc, bool save_doubles) {
1052  // Optionally save FPU state.
1053  if (save_doubles) {
1054    // Store FPU state to m108byte.
1055    int space = 108 + argc * kPointerSize;
1056    sub(esp, Immediate(space));
1057    const int offset = -ExitFrameConstants::kFixedFrameSizeFromFp;
1058    fnsave(MemOperand(ebp, offset - 108));
1059  } else {
1060    sub(esp, Immediate(argc * kPointerSize));
1061  }
1062
1063  // Get the required frame alignment for the OS.
1064  const int kFrameAlignment = base::OS::ActivationFrameAlignment();
1065  if (kFrameAlignment > 0) {
1066    DCHECK(base::bits::IsPowerOfTwo32(kFrameAlignment));
1067    and_(esp, -kFrameAlignment);
1068  }
1069
1070  // Patch the saved entry sp.
1071  mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp);
1072}
1073
1074void MacroAssembler::EnterExitFrame(int argc, bool save_doubles,
1075                                    StackFrame::Type frame_type) {
1076  EnterExitFramePrologue(frame_type);
1077
1078  // Set up argc and argv in callee-saved registers.
1079  int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
1080  mov(edi, eax);
1081  lea(esi, Operand(ebp, eax, times_4, offset));
1082
1083  // Reserve space for argc, argv and isolate.
1084  EnterExitFrameEpilogue(argc, save_doubles);
1085}
1086
1087
1088void MacroAssembler::EnterApiExitFrame(int argc) {
1089  EnterExitFramePrologue(StackFrame::EXIT);
1090  EnterExitFrameEpilogue(argc, false);
1091}
1092
1093
1094void MacroAssembler::LeaveExitFrame(bool save_doubles, bool pop_arguments) {
1095  // Optionally restore FPU state.
1096  if (save_doubles) {
1097    const int offset = -ExitFrameConstants::kFixedFrameSizeFromFp;
1098    frstor(MemOperand(ebp, offset - 108));
1099  }
1100
1101  if (pop_arguments) {
1102    // Get the return address from the stack and restore the frame pointer.
1103    mov(ecx, Operand(ebp, 1 * kPointerSize));
1104    mov(ebp, Operand(ebp, 0 * kPointerSize));
1105
1106    // Pop the arguments and the receiver from the caller stack.
1107    lea(esp, Operand(esi, 1 * kPointerSize));
1108
1109    // Push the return address to get ready to return.
1110    push(ecx);
1111  } else {
1112    // Otherwise just leave the exit frame.
1113    leave();
1114  }
1115
1116  LeaveExitFrameEpilogue(true);
1117}
1118
1119
1120void MacroAssembler::LeaveExitFrameEpilogue(bool restore_context) {
1121  // Restore current context from top and clear it in debug mode.
1122  ExternalReference context_address(Isolate::kContextAddress, isolate());
1123  if (restore_context) {
1124    mov(esi, Operand::StaticVariable(context_address));
1125  }
1126#ifdef DEBUG
1127  mov(Operand::StaticVariable(context_address), Immediate(0));
1128#endif
1129
1130  // Clear the top frame.
1131  ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress,
1132                                       isolate());
1133  mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0));
1134}
1135
1136
1137void MacroAssembler::LeaveApiExitFrame(bool restore_context) {
1138  mov(esp, ebp);
1139  pop(ebp);
1140
1141  LeaveExitFrameEpilogue(restore_context);
1142}
1143
1144
1145void MacroAssembler::PushStackHandler() {
1146  // Adjust this code if not the case.
1147  STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize);
1148  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
1149
1150  // Link the current handler as the next handler.
1151  ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
1152  push(Operand::StaticVariable(handler_address));
1153
1154  // Set this new handler as the current one.
1155  mov(Operand::StaticVariable(handler_address), esp);
1156}
1157
1158
1159void MacroAssembler::PopStackHandler() {
1160  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
1161  ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
1162  pop(Operand::StaticVariable(handler_address));
1163  add(esp, Immediate(StackHandlerConstants::kSize - kPointerSize));
1164}
1165
1166
1167// Compute the hash code from the untagged key.  This must be kept in sync with
1168// ComputeIntegerHash in utils.h and KeyedLoadGenericStub in
1169// code-stub-hydrogen.cc
1170//
1171// Note: r0 will contain hash code
1172void MacroAssembler::GetNumberHash(Register r0, Register scratch) {
1173  // Xor original key with a seed.
1174  if (serializer_enabled()) {
1175    ExternalReference roots_array_start =
1176        ExternalReference::roots_array_start(isolate());
1177    mov(scratch, Immediate(Heap::kHashSeedRootIndex));
1178    mov(scratch,
1179        Operand::StaticArray(scratch, times_pointer_size, roots_array_start));
1180    SmiUntag(scratch);
1181    xor_(r0, scratch);
1182  } else {
1183    int32_t seed = isolate()->heap()->HashSeed();
1184    xor_(r0, Immediate(seed));
1185  }
1186
1187  // hash = ~hash + (hash << 15);
1188  mov(scratch, r0);
1189  not_(r0);
1190  shl(scratch, 15);
1191  add(r0, scratch);
1192  // hash = hash ^ (hash >> 12);
1193  mov(scratch, r0);
1194  shr(scratch, 12);
1195  xor_(r0, scratch);
1196  // hash = hash + (hash << 2);
1197  lea(r0, Operand(r0, r0, times_4, 0));
1198  // hash = hash ^ (hash >> 4);
1199  mov(scratch, r0);
1200  shr(scratch, 4);
1201  xor_(r0, scratch);
1202  // hash = hash * 2057;
1203  imul(r0, r0, 2057);
1204  // hash = hash ^ (hash >> 16);
1205  mov(scratch, r0);
1206  shr(scratch, 16);
1207  xor_(r0, scratch);
1208  and_(r0, 0x3fffffff);
1209}
1210
1211void MacroAssembler::LoadAllocationTopHelper(Register result,
1212                                             Register scratch,
1213                                             AllocationFlags flags) {
1214  ExternalReference allocation_top =
1215      AllocationUtils::GetAllocationTopReference(isolate(), flags);
1216
1217  // Just return if allocation top is already known.
1218  if ((flags & RESULT_CONTAINS_TOP) != 0) {
1219    // No use of scratch if allocation top is provided.
1220    DCHECK(scratch.is(no_reg));
1221#ifdef DEBUG
1222    // Assert that result actually contains top on entry.
1223    cmp(result, Operand::StaticVariable(allocation_top));
1224    Check(equal, kUnexpectedAllocationTop);
1225#endif
1226    return;
1227  }
1228
1229  // Move address of new object to result. Use scratch register if available.
1230  if (scratch.is(no_reg)) {
1231    mov(result, Operand::StaticVariable(allocation_top));
1232  } else {
1233    mov(scratch, Immediate(allocation_top));
1234    mov(result, Operand(scratch, 0));
1235  }
1236}
1237
1238
1239void MacroAssembler::UpdateAllocationTopHelper(Register result_end,
1240                                               Register scratch,
1241                                               AllocationFlags flags) {
1242  if (emit_debug_code()) {
1243    test(result_end, Immediate(kObjectAlignmentMask));
1244    Check(zero, kUnalignedAllocationInNewSpace);
1245  }
1246
1247  ExternalReference allocation_top =
1248      AllocationUtils::GetAllocationTopReference(isolate(), flags);
1249
1250  // Update new top. Use scratch if available.
1251  if (scratch.is(no_reg)) {
1252    mov(Operand::StaticVariable(allocation_top), result_end);
1253  } else {
1254    mov(Operand(scratch, 0), result_end);
1255  }
1256}
1257
1258
1259void MacroAssembler::Allocate(int object_size,
1260                              Register result,
1261                              Register result_end,
1262                              Register scratch,
1263                              Label* gc_required,
1264                              AllocationFlags flags) {
1265  DCHECK((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0);
1266  DCHECK(object_size <= kMaxRegularHeapObjectSize);
1267  DCHECK((flags & ALLOCATION_FOLDED) == 0);
1268  if (!FLAG_inline_new) {
1269    if (emit_debug_code()) {
1270      // Trash the registers to simulate an allocation failure.
1271      mov(result, Immediate(0x7091));
1272      if (result_end.is_valid()) {
1273        mov(result_end, Immediate(0x7191));
1274      }
1275      if (scratch.is_valid()) {
1276        mov(scratch, Immediate(0x7291));
1277      }
1278    }
1279    jmp(gc_required);
1280    return;
1281  }
1282  DCHECK(!result.is(result_end));
1283
1284  // Load address of new object into result.
1285  LoadAllocationTopHelper(result, scratch, flags);
1286
1287  ExternalReference allocation_limit =
1288      AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1289
1290  // Align the next allocation. Storing the filler map without checking top is
1291  // safe in new-space because the limit of the heap is aligned there.
1292  if ((flags & DOUBLE_ALIGNMENT) != 0) {
1293    DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
1294    Label aligned;
1295    test(result, Immediate(kDoubleAlignmentMask));
1296    j(zero, &aligned, Label::kNear);
1297    if ((flags & PRETENURE) != 0) {
1298      cmp(result, Operand::StaticVariable(allocation_limit));
1299      j(above_equal, gc_required);
1300    }
1301    mov(Operand(result, 0),
1302        Immediate(isolate()->factory()->one_pointer_filler_map()));
1303    add(result, Immediate(kDoubleSize / 2));
1304    bind(&aligned);
1305  }
1306
1307  // Calculate new top and bail out if space is exhausted.
1308  Register top_reg = result_end.is_valid() ? result_end : result;
1309
1310  if (!top_reg.is(result)) {
1311    mov(top_reg, result);
1312  }
1313  add(top_reg, Immediate(object_size));
1314  cmp(top_reg, Operand::StaticVariable(allocation_limit));
1315  j(above, gc_required);
1316
1317  if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) {
1318    // The top pointer is not updated for allocation folding dominators.
1319    UpdateAllocationTopHelper(top_reg, scratch, flags);
1320  }
1321
1322  if (top_reg.is(result)) {
1323    sub(result, Immediate(object_size - kHeapObjectTag));
1324  } else {
1325    // Tag the result.
1326    DCHECK(kHeapObjectTag == 1);
1327    inc(result);
1328  }
1329}
1330
1331
1332void MacroAssembler::Allocate(int header_size,
1333                              ScaleFactor element_size,
1334                              Register element_count,
1335                              RegisterValueType element_count_type,
1336                              Register result,
1337                              Register result_end,
1338                              Register scratch,
1339                              Label* gc_required,
1340                              AllocationFlags flags) {
1341  DCHECK((flags & SIZE_IN_WORDS) == 0);
1342  DCHECK((flags & ALLOCATION_FOLDING_DOMINATOR) == 0);
1343  DCHECK((flags & ALLOCATION_FOLDED) == 0);
1344  if (!FLAG_inline_new) {
1345    if (emit_debug_code()) {
1346      // Trash the registers to simulate an allocation failure.
1347      mov(result, Immediate(0x7091));
1348      mov(result_end, Immediate(0x7191));
1349      if (scratch.is_valid()) {
1350        mov(scratch, Immediate(0x7291));
1351      }
1352      // Register element_count is not modified by the function.
1353    }
1354    jmp(gc_required);
1355    return;
1356  }
1357  DCHECK(!result.is(result_end));
1358
1359  // Load address of new object into result.
1360  LoadAllocationTopHelper(result, scratch, flags);
1361
1362  ExternalReference allocation_limit =
1363      AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1364
1365  // Align the next allocation. Storing the filler map without checking top is
1366  // safe in new-space because the limit of the heap is aligned there.
1367  if ((flags & DOUBLE_ALIGNMENT) != 0) {
1368    DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
1369    Label aligned;
1370    test(result, Immediate(kDoubleAlignmentMask));
1371    j(zero, &aligned, Label::kNear);
1372    if ((flags & PRETENURE) != 0) {
1373      cmp(result, Operand::StaticVariable(allocation_limit));
1374      j(above_equal, gc_required);
1375    }
1376    mov(Operand(result, 0),
1377        Immediate(isolate()->factory()->one_pointer_filler_map()));
1378    add(result, Immediate(kDoubleSize / 2));
1379    bind(&aligned);
1380  }
1381
1382  // Calculate new top and bail out if space is exhausted.
1383  // We assume that element_count*element_size + header_size does not
1384  // overflow.
1385  if (element_count_type == REGISTER_VALUE_IS_SMI) {
1386    STATIC_ASSERT(static_cast<ScaleFactor>(times_2 - 1) == times_1);
1387    STATIC_ASSERT(static_cast<ScaleFactor>(times_4 - 1) == times_2);
1388    STATIC_ASSERT(static_cast<ScaleFactor>(times_8 - 1) == times_4);
1389    DCHECK(element_size >= times_2);
1390    DCHECK(kSmiTagSize == 1);
1391    element_size = static_cast<ScaleFactor>(element_size - 1);
1392  } else {
1393    DCHECK(element_count_type == REGISTER_VALUE_IS_INT32);
1394  }
1395  lea(result_end, Operand(element_count, element_size, header_size));
1396  add(result_end, result);
1397  j(carry, gc_required);
1398  cmp(result_end, Operand::StaticVariable(allocation_limit));
1399  j(above, gc_required);
1400
1401  // Tag result.
1402  DCHECK(kHeapObjectTag == 1);
1403  inc(result);
1404
1405  // Update allocation top.
1406  UpdateAllocationTopHelper(result_end, scratch, flags);
1407}
1408
1409void MacroAssembler::Allocate(Register object_size,
1410                              Register result,
1411                              Register result_end,
1412                              Register scratch,
1413                              Label* gc_required,
1414                              AllocationFlags flags) {
1415  DCHECK((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0);
1416  DCHECK((flags & ALLOCATION_FOLDED) == 0);
1417  if (!FLAG_inline_new) {
1418    if (emit_debug_code()) {
1419      // Trash the registers to simulate an allocation failure.
1420      mov(result, Immediate(0x7091));
1421      mov(result_end, Immediate(0x7191));
1422      if (scratch.is_valid()) {
1423        mov(scratch, Immediate(0x7291));
1424      }
1425      // object_size is left unchanged by this function.
1426    }
1427    jmp(gc_required);
1428    return;
1429  }
1430  DCHECK(!result.is(result_end));
1431
1432  // Load address of new object into result.
1433  LoadAllocationTopHelper(result, scratch, flags);
1434
1435  ExternalReference allocation_limit =
1436      AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1437
1438  // Align the next allocation. Storing the filler map without checking top is
1439  // safe in new-space because the limit of the heap is aligned there.
1440  if ((flags & DOUBLE_ALIGNMENT) != 0) {
1441    DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
1442    Label aligned;
1443    test(result, Immediate(kDoubleAlignmentMask));
1444    j(zero, &aligned, Label::kNear);
1445    if ((flags & PRETENURE) != 0) {
1446      cmp(result, Operand::StaticVariable(allocation_limit));
1447      j(above_equal, gc_required);
1448    }
1449    mov(Operand(result, 0),
1450        Immediate(isolate()->factory()->one_pointer_filler_map()));
1451    add(result, Immediate(kDoubleSize / 2));
1452    bind(&aligned);
1453  }
1454
1455  // Calculate new top and bail out if space is exhausted.
1456  if (!object_size.is(result_end)) {
1457    mov(result_end, object_size);
1458  }
1459  add(result_end, result);
1460  cmp(result_end, Operand::StaticVariable(allocation_limit));
1461  j(above, gc_required);
1462
1463  // Tag result.
1464  DCHECK(kHeapObjectTag == 1);
1465  inc(result);
1466
1467  if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) {
1468    // The top pointer is not updated for allocation folding dominators.
1469    UpdateAllocationTopHelper(result_end, scratch, flags);
1470  }
1471}
1472
1473void MacroAssembler::FastAllocate(int object_size, Register result,
1474                                  Register result_end, AllocationFlags flags) {
1475  DCHECK(!result.is(result_end));
1476  // Load address of new object into result.
1477  LoadAllocationTopHelper(result, no_reg, flags);
1478
1479  if ((flags & DOUBLE_ALIGNMENT) != 0) {
1480    DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
1481    Label aligned;
1482    test(result, Immediate(kDoubleAlignmentMask));
1483    j(zero, &aligned, Label::kNear);
1484    mov(Operand(result, 0),
1485        Immediate(isolate()->factory()->one_pointer_filler_map()));
1486    add(result, Immediate(kDoubleSize / 2));
1487    bind(&aligned);
1488  }
1489
1490  lea(result_end, Operand(result, object_size));
1491  UpdateAllocationTopHelper(result_end, no_reg, flags);
1492
1493  DCHECK(kHeapObjectTag == 1);
1494  inc(result);
1495}
1496
1497void MacroAssembler::FastAllocate(Register object_size, Register result,
1498                                  Register result_end, AllocationFlags flags) {
1499  DCHECK(!result.is(result_end));
1500  // Load address of new object into result.
1501  LoadAllocationTopHelper(result, no_reg, flags);
1502
1503  if ((flags & DOUBLE_ALIGNMENT) != 0) {
1504    DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
1505    Label aligned;
1506    test(result, Immediate(kDoubleAlignmentMask));
1507    j(zero, &aligned, Label::kNear);
1508    mov(Operand(result, 0),
1509        Immediate(isolate()->factory()->one_pointer_filler_map()));
1510    add(result, Immediate(kDoubleSize / 2));
1511    bind(&aligned);
1512  }
1513
1514  lea(result_end, Operand(result, object_size, times_1, 0));
1515  UpdateAllocationTopHelper(result_end, no_reg, flags);
1516
1517  DCHECK(kHeapObjectTag == 1);
1518  inc(result);
1519}
1520
1521void MacroAssembler::AllocateHeapNumber(Register result,
1522                                        Register scratch1,
1523                                        Register scratch2,
1524                                        Label* gc_required,
1525                                        MutableMode mode) {
1526  // Allocate heap number in new space.
1527  Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required,
1528           NO_ALLOCATION_FLAGS);
1529
1530  Handle<Map> map = mode == MUTABLE
1531      ? isolate()->factory()->mutable_heap_number_map()
1532      : isolate()->factory()->heap_number_map();
1533
1534  // Set the map.
1535  mov(FieldOperand(result, HeapObject::kMapOffset), Immediate(map));
1536}
1537
1538void MacroAssembler::AllocateJSValue(Register result, Register constructor,
1539                                     Register value, Register scratch,
1540                                     Label* gc_required) {
1541  DCHECK(!result.is(constructor));
1542  DCHECK(!result.is(scratch));
1543  DCHECK(!result.is(value));
1544
1545  // Allocate JSValue in new space.
1546  Allocate(JSValue::kSize, result, scratch, no_reg, gc_required,
1547           NO_ALLOCATION_FLAGS);
1548
1549  // Initialize the JSValue.
1550  LoadGlobalFunctionInitialMap(constructor, scratch);
1551  mov(FieldOperand(result, HeapObject::kMapOffset), scratch);
1552  LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex);
1553  mov(FieldOperand(result, JSObject::kPropertiesOffset), scratch);
1554  mov(FieldOperand(result, JSObject::kElementsOffset), scratch);
1555  mov(FieldOperand(result, JSValue::kValueOffset), value);
1556  STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
1557}
1558
1559void MacroAssembler::InitializeFieldsWithFiller(Register current_address,
1560                                                Register end_address,
1561                                                Register filler) {
1562  Label loop, entry;
1563  jmp(&entry, Label::kNear);
1564  bind(&loop);
1565  mov(Operand(current_address, 0), filler);
1566  add(current_address, Immediate(kPointerSize));
1567  bind(&entry);
1568  cmp(current_address, end_address);
1569  j(below, &loop, Label::kNear);
1570}
1571
1572
1573void MacroAssembler::BooleanBitTest(Register object,
1574                                    int field_offset,
1575                                    int bit_index) {
1576  bit_index += kSmiTagSize + kSmiShiftSize;
1577  DCHECK(base::bits::IsPowerOfTwo32(kBitsPerByte));
1578  int byte_index = bit_index / kBitsPerByte;
1579  int byte_bit_index = bit_index & (kBitsPerByte - 1);
1580  test_b(FieldOperand(object, field_offset + byte_index),
1581         Immediate(1 << byte_bit_index));
1582}
1583
1584
1585
1586void MacroAssembler::NegativeZeroTest(Register result,
1587                                      Register op,
1588                                      Label* then_label) {
1589  Label ok;
1590  test(result, result);
1591  j(not_zero, &ok, Label::kNear);
1592  test(op, op);
1593  j(sign, then_label, Label::kNear);
1594  bind(&ok);
1595}
1596
1597
1598void MacroAssembler::NegativeZeroTest(Register result,
1599                                      Register op1,
1600                                      Register op2,
1601                                      Register scratch,
1602                                      Label* then_label) {
1603  Label ok;
1604  test(result, result);
1605  j(not_zero, &ok, Label::kNear);
1606  mov(scratch, op1);
1607  or_(scratch, op2);
1608  j(sign, then_label, Label::kNear);
1609  bind(&ok);
1610}
1611
1612
1613void MacroAssembler::GetMapConstructor(Register result, Register map,
1614                                       Register temp) {
1615  Label done, loop;
1616  mov(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset));
1617  bind(&loop);
1618  JumpIfSmi(result, &done, Label::kNear);
1619  CmpObjectType(result, MAP_TYPE, temp);
1620  j(not_equal, &done, Label::kNear);
1621  mov(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset));
1622  jmp(&loop);
1623  bind(&done);
1624}
1625
1626void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id) {
1627  DCHECK(AllowThisStubCall(stub));  // Calls are not allowed in some stubs.
1628  call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id);
1629}
1630
1631
1632void MacroAssembler::TailCallStub(CodeStub* stub) {
1633  jmp(stub->GetCode(), RelocInfo::CODE_TARGET);
1634}
1635
1636
1637void MacroAssembler::StubReturn(int argc) {
1638  DCHECK(argc >= 1 && generating_stub());
1639  ret((argc - 1) * kPointerSize);
1640}
1641
1642
1643bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
1644  return has_frame_ || !stub->SometimesSetsUpAFrame();
1645}
1646
1647void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments,
1648                                 SaveFPRegsMode save_doubles) {
1649  // If the expected number of arguments of the runtime function is
1650  // constant, we check that the actual number of arguments match the
1651  // expectation.
1652  CHECK(f->nargs < 0 || f->nargs == num_arguments);
1653
1654  // TODO(1236192): Most runtime routines don't need the number of
1655  // arguments passed in because it is constant. At some point we
1656  // should remove this need and make the runtime routine entry code
1657  // smarter.
1658  Move(eax, Immediate(num_arguments));
1659  mov(ebx, Immediate(ExternalReference(f, isolate())));
1660  CEntryStub ces(isolate(), 1, save_doubles);
1661  CallStub(&ces);
1662}
1663
1664
1665void MacroAssembler::CallExternalReference(ExternalReference ref,
1666                                           int num_arguments) {
1667  mov(eax, Immediate(num_arguments));
1668  mov(ebx, Immediate(ref));
1669
1670  CEntryStub stub(isolate(), 1);
1671  CallStub(&stub);
1672}
1673
1674
1675void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
1676  // ----------- S t a t e -------------
1677  //  -- esp[0]                 : return address
1678  //  -- esp[8]                 : argument num_arguments - 1
1679  //  ...
1680  //  -- esp[8 * num_arguments] : argument 0 (receiver)
1681  //
1682  //  For runtime functions with variable arguments:
1683  //  -- eax                    : number of  arguments
1684  // -----------------------------------
1685
1686  const Runtime::Function* function = Runtime::FunctionForId(fid);
1687  DCHECK_EQ(1, function->result_size);
1688  if (function->nargs >= 0) {
1689    // TODO(1236192): Most runtime routines don't need the number of
1690    // arguments passed in because it is constant. At some point we
1691    // should remove this need and make the runtime routine entry code
1692    // smarter.
1693    mov(eax, Immediate(function->nargs));
1694  }
1695  JumpToExternalReference(ExternalReference(fid, isolate()));
1696}
1697
1698void MacroAssembler::JumpToExternalReference(const ExternalReference& ext,
1699                                             bool builtin_exit_frame) {
1700  // Set the entry point and jump to the C entry runtime stub.
1701  mov(ebx, Immediate(ext));
1702  CEntryStub ces(isolate(), 1, kDontSaveFPRegs, kArgvOnStack,
1703                 builtin_exit_frame);
1704  jmp(ces.GetCode(), RelocInfo::CODE_TARGET);
1705}
1706
1707void MacroAssembler::PrepareForTailCall(
1708    const ParameterCount& callee_args_count, Register caller_args_count_reg,
1709    Register scratch0, Register scratch1, ReturnAddressState ra_state,
1710    int number_of_temp_values_after_return_address) {
1711#if DEBUG
1712  if (callee_args_count.is_reg()) {
1713    DCHECK(!AreAliased(callee_args_count.reg(), caller_args_count_reg, scratch0,
1714                       scratch1));
1715  } else {
1716    DCHECK(!AreAliased(caller_args_count_reg, scratch0, scratch1));
1717  }
1718  DCHECK(ra_state != ReturnAddressState::kNotOnStack ||
1719         number_of_temp_values_after_return_address == 0);
1720#endif
1721
1722  // Calculate the destination address where we will put the return address
1723  // after we drop current frame.
1724  Register new_sp_reg = scratch0;
1725  if (callee_args_count.is_reg()) {
1726    sub(caller_args_count_reg, callee_args_count.reg());
1727    lea(new_sp_reg,
1728        Operand(ebp, caller_args_count_reg, times_pointer_size,
1729                StandardFrameConstants::kCallerPCOffset -
1730                    number_of_temp_values_after_return_address * kPointerSize));
1731  } else {
1732    lea(new_sp_reg, Operand(ebp, caller_args_count_reg, times_pointer_size,
1733                            StandardFrameConstants::kCallerPCOffset -
1734                                (callee_args_count.immediate() +
1735                                 number_of_temp_values_after_return_address) *
1736                                    kPointerSize));
1737  }
1738
1739  if (FLAG_debug_code) {
1740    cmp(esp, new_sp_reg);
1741    Check(below, kStackAccessBelowStackPointer);
1742  }
1743
1744  // Copy return address from caller's frame to current frame's return address
1745  // to avoid its trashing and let the following loop copy it to the right
1746  // place.
1747  Register tmp_reg = scratch1;
1748  if (ra_state == ReturnAddressState::kOnStack) {
1749    mov(tmp_reg, Operand(ebp, StandardFrameConstants::kCallerPCOffset));
1750    mov(Operand(esp, number_of_temp_values_after_return_address * kPointerSize),
1751        tmp_reg);
1752  } else {
1753    DCHECK(ReturnAddressState::kNotOnStack == ra_state);
1754    DCHECK_EQ(0, number_of_temp_values_after_return_address);
1755    Push(Operand(ebp, StandardFrameConstants::kCallerPCOffset));
1756  }
1757
1758  // Restore caller's frame pointer now as it could be overwritten by
1759  // the copying loop.
1760  mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
1761
1762  // +2 here is to copy both receiver and return address.
1763  Register count_reg = caller_args_count_reg;
1764  if (callee_args_count.is_reg()) {
1765    lea(count_reg, Operand(callee_args_count.reg(),
1766                           2 + number_of_temp_values_after_return_address));
1767  } else {
1768    mov(count_reg, Immediate(callee_args_count.immediate() + 2 +
1769                             number_of_temp_values_after_return_address));
1770    // TODO(ishell): Unroll copying loop for small immediate values.
1771  }
1772
1773  // Now copy callee arguments to the caller frame going backwards to avoid
1774  // callee arguments corruption (source and destination areas could overlap).
1775  Label loop, entry;
1776  jmp(&entry, Label::kNear);
1777  bind(&loop);
1778  dec(count_reg);
1779  mov(tmp_reg, Operand(esp, count_reg, times_pointer_size, 0));
1780  mov(Operand(new_sp_reg, count_reg, times_pointer_size, 0), tmp_reg);
1781  bind(&entry);
1782  cmp(count_reg, Immediate(0));
1783  j(not_equal, &loop, Label::kNear);
1784
1785  // Leave current frame.
1786  mov(esp, new_sp_reg);
1787}
1788
1789void MacroAssembler::InvokePrologue(const ParameterCount& expected,
1790                                    const ParameterCount& actual,
1791                                    Label* done,
1792                                    bool* definitely_mismatches,
1793                                    InvokeFlag flag,
1794                                    Label::Distance done_near,
1795                                    const CallWrapper& call_wrapper) {
1796  bool definitely_matches = false;
1797  *definitely_mismatches = false;
1798  Label invoke;
1799  if (expected.is_immediate()) {
1800    DCHECK(actual.is_immediate());
1801    mov(eax, actual.immediate());
1802    if (expected.immediate() == actual.immediate()) {
1803      definitely_matches = true;
1804    } else {
1805      const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
1806      if (expected.immediate() == sentinel) {
1807        // Don't worry about adapting arguments for builtins that
1808        // don't want that done. Skip adaption code by making it look
1809        // like we have a match between expected and actual number of
1810        // arguments.
1811        definitely_matches = true;
1812      } else {
1813        *definitely_mismatches = true;
1814        mov(ebx, expected.immediate());
1815      }
1816    }
1817  } else {
1818    if (actual.is_immediate()) {
1819      // Expected is in register, actual is immediate. This is the
1820      // case when we invoke function values without going through the
1821      // IC mechanism.
1822      mov(eax, actual.immediate());
1823      cmp(expected.reg(), actual.immediate());
1824      j(equal, &invoke);
1825      DCHECK(expected.reg().is(ebx));
1826    } else if (!expected.reg().is(actual.reg())) {
1827      // Both expected and actual are in (different) registers. This
1828      // is the case when we invoke functions using call and apply.
1829      cmp(expected.reg(), actual.reg());
1830      j(equal, &invoke);
1831      DCHECK(actual.reg().is(eax));
1832      DCHECK(expected.reg().is(ebx));
1833    } else {
1834      Move(eax, actual.reg());
1835    }
1836  }
1837
1838  if (!definitely_matches) {
1839    Handle<Code> adaptor =
1840        isolate()->builtins()->ArgumentsAdaptorTrampoline();
1841    if (flag == CALL_FUNCTION) {
1842      call_wrapper.BeforeCall(CallSize(adaptor, RelocInfo::CODE_TARGET));
1843      call(adaptor, RelocInfo::CODE_TARGET);
1844      call_wrapper.AfterCall();
1845      if (!*definitely_mismatches) {
1846        jmp(done, done_near);
1847      }
1848    } else {
1849      jmp(adaptor, RelocInfo::CODE_TARGET);
1850    }
1851    bind(&invoke);
1852  }
1853}
1854
1855void MacroAssembler::CheckDebugHook(Register fun, Register new_target,
1856                                    const ParameterCount& expected,
1857                                    const ParameterCount& actual) {
1858  Label skip_hook;
1859  ExternalReference debug_hook_active =
1860      ExternalReference::debug_hook_on_function_call_address(isolate());
1861  cmpb(Operand::StaticVariable(debug_hook_active), Immediate(0));
1862  j(equal, &skip_hook);
1863  {
1864    FrameScope frame(this,
1865                     has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
1866    if (expected.is_reg()) {
1867      SmiTag(expected.reg());
1868      Push(expected.reg());
1869    }
1870    if (actual.is_reg()) {
1871      SmiTag(actual.reg());
1872      Push(actual.reg());
1873    }
1874    if (new_target.is_valid()) {
1875      Push(new_target);
1876    }
1877    Push(fun);
1878    Push(fun);
1879    CallRuntime(Runtime::kDebugOnFunctionCall);
1880    Pop(fun);
1881    if (new_target.is_valid()) {
1882      Pop(new_target);
1883    }
1884    if (actual.is_reg()) {
1885      Pop(actual.reg());
1886      SmiUntag(actual.reg());
1887    }
1888    if (expected.is_reg()) {
1889      Pop(expected.reg());
1890      SmiUntag(expected.reg());
1891    }
1892  }
1893  bind(&skip_hook);
1894}
1895
1896
1897void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
1898                                        const ParameterCount& expected,
1899                                        const ParameterCount& actual,
1900                                        InvokeFlag flag,
1901                                        const CallWrapper& call_wrapper) {
1902  // You can't call a function without a valid frame.
1903  DCHECK(flag == JUMP_FUNCTION || has_frame());
1904  DCHECK(function.is(edi));
1905  DCHECK_IMPLIES(new_target.is_valid(), new_target.is(edx));
1906
1907  if (call_wrapper.NeedsDebugHookCheck()) {
1908    CheckDebugHook(function, new_target, expected, actual);
1909  }
1910
1911  // Clear the new.target register if not given.
1912  if (!new_target.is_valid()) {
1913    mov(edx, isolate()->factory()->undefined_value());
1914  }
1915
1916  Label done;
1917  bool definitely_mismatches = false;
1918  InvokePrologue(expected, actual, &done, &definitely_mismatches, flag,
1919                 Label::kNear, call_wrapper);
1920  if (!definitely_mismatches) {
1921    // We call indirectly through the code field in the function to
1922    // allow recompilation to take effect without changing any of the
1923    // call sites.
1924    Operand code = FieldOperand(function, JSFunction::kCodeEntryOffset);
1925    if (flag == CALL_FUNCTION) {
1926      call_wrapper.BeforeCall(CallSize(code));
1927      call(code);
1928      call_wrapper.AfterCall();
1929    } else {
1930      DCHECK(flag == JUMP_FUNCTION);
1931      jmp(code);
1932    }
1933    bind(&done);
1934  }
1935}
1936
1937
1938void MacroAssembler::InvokeFunction(Register fun, Register new_target,
1939                                    const ParameterCount& actual,
1940                                    InvokeFlag flag,
1941                                    const CallWrapper& call_wrapper) {
1942  // You can't call a function without a valid frame.
1943  DCHECK(flag == JUMP_FUNCTION || has_frame());
1944
1945  DCHECK(fun.is(edi));
1946  mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
1947  mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1948  mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kFormalParameterCountOffset));
1949  SmiUntag(ebx);
1950
1951  ParameterCount expected(ebx);
1952  InvokeFunctionCode(edi, new_target, expected, actual, flag, call_wrapper);
1953}
1954
1955
1956void MacroAssembler::InvokeFunction(Register fun,
1957                                    const ParameterCount& expected,
1958                                    const ParameterCount& actual,
1959                                    InvokeFlag flag,
1960                                    const CallWrapper& call_wrapper) {
1961  // You can't call a function without a valid frame.
1962  DCHECK(flag == JUMP_FUNCTION || has_frame());
1963
1964  DCHECK(fun.is(edi));
1965  mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
1966
1967  InvokeFunctionCode(edi, no_reg, expected, actual, flag, call_wrapper);
1968}
1969
1970
1971void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
1972                                    const ParameterCount& expected,
1973                                    const ParameterCount& actual,
1974                                    InvokeFlag flag,
1975                                    const CallWrapper& call_wrapper) {
1976  LoadHeapObject(edi, function);
1977  InvokeFunction(edi, expected, actual, flag, call_wrapper);
1978}
1979
1980
1981void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
1982  if (context_chain_length > 0) {
1983    // Move up the chain of contexts to the context containing the slot.
1984    mov(dst, Operand(esi, Context::SlotOffset(Context::PREVIOUS_INDEX)));
1985    for (int i = 1; i < context_chain_length; i++) {
1986      mov(dst, Operand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX)));
1987    }
1988  } else {
1989    // Slot is in the current function context.  Move it into the
1990    // destination register in case we store into it (the write barrier
1991    // cannot be allowed to destroy the context in esi).
1992    mov(dst, esi);
1993  }
1994
1995  // We should not have found a with context by walking the context chain
1996  // (i.e., the static scope chain and runtime context chain do not agree).
1997  // A variable occurring in such a scope should have slot type LOOKUP and
1998  // not CONTEXT.
1999  if (emit_debug_code()) {
2000    cmp(FieldOperand(dst, HeapObject::kMapOffset),
2001        isolate()->factory()->with_context_map());
2002    Check(not_equal, kVariableResolvedToWithContext);
2003  }
2004}
2005
2006
2007void MacroAssembler::LoadGlobalProxy(Register dst) {
2008  mov(dst, NativeContextOperand());
2009  mov(dst, ContextOperand(dst, Context::GLOBAL_PROXY_INDEX));
2010}
2011
2012void MacroAssembler::LoadGlobalFunction(int index, Register function) {
2013  // Load the native context from the current context.
2014  mov(function, NativeContextOperand());
2015  // Load the function from the native context.
2016  mov(function, ContextOperand(function, index));
2017}
2018
2019
2020void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
2021                                                  Register map) {
2022  // Load the initial map.  The global functions all have initial maps.
2023  mov(map, FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2024  if (emit_debug_code()) {
2025    Label ok, fail;
2026    CheckMap(map, isolate()->factory()->meta_map(), &fail, DO_SMI_CHECK);
2027    jmp(&ok);
2028    bind(&fail);
2029    Abort(kGlobalFunctionsMustHaveInitialMap);
2030    bind(&ok);
2031  }
2032}
2033
2034
2035// Store the value in register src in the safepoint register stack
2036// slot for register dst.
2037void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, Register src) {
2038  mov(SafepointRegisterSlot(dst), src);
2039}
2040
2041
2042void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, Immediate src) {
2043  mov(SafepointRegisterSlot(dst), src);
2044}
2045
2046
2047void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) {
2048  mov(dst, SafepointRegisterSlot(src));
2049}
2050
2051
2052Operand MacroAssembler::SafepointRegisterSlot(Register reg) {
2053  return Operand(esp, SafepointRegisterStackIndex(reg.code()) * kPointerSize);
2054}
2055
2056
2057int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
2058  // The registers are pushed starting with the lowest encoding,
2059  // which means that lowest encodings are furthest away from
2060  // the stack pointer.
2061  DCHECK(reg_code >= 0 && reg_code < kNumSafepointRegisters);
2062  return kNumSafepointRegisters - reg_code - 1;
2063}
2064
2065
2066void MacroAssembler::LoadHeapObject(Register result,
2067                                    Handle<HeapObject> object) {
2068  mov(result, object);
2069}
2070
2071
2072void MacroAssembler::CmpHeapObject(Register reg, Handle<HeapObject> object) {
2073  cmp(reg, object);
2074}
2075
2076void MacroAssembler::PushHeapObject(Handle<HeapObject> object) { Push(object); }
2077
2078void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell,
2079                                  Register scratch) {
2080  mov(scratch, cell);
2081  cmp(value, FieldOperand(scratch, WeakCell::kValueOffset));
2082}
2083
2084
2085void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) {
2086  mov(value, cell);
2087  mov(value, FieldOperand(value, WeakCell::kValueOffset));
2088}
2089
2090
2091void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
2092                                   Label* miss) {
2093  GetWeakValue(value, cell);
2094  JumpIfSmi(value, miss);
2095}
2096
2097
2098void MacroAssembler::Ret() {
2099  ret(0);
2100}
2101
2102
2103void MacroAssembler::Ret(int bytes_dropped, Register scratch) {
2104  if (is_uint16(bytes_dropped)) {
2105    ret(bytes_dropped);
2106  } else {
2107    pop(scratch);
2108    add(esp, Immediate(bytes_dropped));
2109    push(scratch);
2110    ret(0);
2111  }
2112}
2113
2114
2115void MacroAssembler::VerifyX87StackDepth(uint32_t depth) {
2116  // Turn off the stack depth check when serializer is enabled to reduce the
2117  // code size.
2118  if (serializer_enabled()) return;
2119  // Make sure the floating point stack is either empty or has depth items.
2120  DCHECK(depth <= 7);
2121  // This is very expensive.
2122  DCHECK(FLAG_debug_code && FLAG_enable_slow_asserts);
2123
2124  // The top-of-stack (tos) is 7 if there is one item pushed.
2125  int tos = (8 - depth) % 8;
2126  const int kTopMask = 0x3800;
2127  push(eax);
2128  fwait();
2129  fnstsw_ax();
2130  and_(eax, kTopMask);
2131  shr(eax, 11);
2132  cmp(eax, Immediate(tos));
2133  Check(equal, kUnexpectedFPUStackDepthAfterInstruction);
2134  fnclex();
2135  pop(eax);
2136}
2137
2138
2139void MacroAssembler::Drop(int stack_elements) {
2140  if (stack_elements > 0) {
2141    add(esp, Immediate(stack_elements * kPointerSize));
2142  }
2143}
2144
2145
2146void MacroAssembler::Move(Register dst, Register src) {
2147  if (!dst.is(src)) {
2148    mov(dst, src);
2149  }
2150}
2151
2152
2153void MacroAssembler::Move(Register dst, const Immediate& x) {
2154  if (x.is_zero() && RelocInfo::IsNone(x.rmode_)) {
2155    xor_(dst, dst);  // Shorter than mov of 32-bit immediate 0.
2156  } else {
2157    mov(dst, x);
2158  }
2159}
2160
2161
2162void MacroAssembler::Move(const Operand& dst, const Immediate& x) {
2163  mov(dst, x);
2164}
2165
2166
2167void MacroAssembler::Lzcnt(Register dst, const Operand& src) {
2168  // TODO(intel): Add support for LZCNT (with ABM/BMI1).
2169  Label not_zero_src;
2170  bsr(dst, src);
2171  j(not_zero, &not_zero_src, Label::kNear);
2172  Move(dst, Immediate(63));  // 63^31 == 32
2173  bind(&not_zero_src);
2174  xor_(dst, Immediate(31));  // for x in [0..31], 31^x == 31-x.
2175}
2176
2177
2178void MacroAssembler::Tzcnt(Register dst, const Operand& src) {
2179  // TODO(intel): Add support for TZCNT (with ABM/BMI1).
2180  Label not_zero_src;
2181  bsf(dst, src);
2182  j(not_zero, &not_zero_src, Label::kNear);
2183  Move(dst, Immediate(32));  // The result of tzcnt is 32 if src = 0.
2184  bind(&not_zero_src);
2185}
2186
2187
2188void MacroAssembler::Popcnt(Register dst, const Operand& src) {
2189  // TODO(intel): Add support for POPCNT (with POPCNT)
2190  // if (CpuFeatures::IsSupported(POPCNT)) {
2191  //   CpuFeatureScope scope(this, POPCNT);
2192  //   popcnt(dst, src);
2193  //   return;
2194  // }
2195  UNREACHABLE();
2196}
2197
2198
2199void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
2200  if (FLAG_native_code_counters && counter->Enabled()) {
2201    mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value));
2202  }
2203}
2204
2205
2206void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) {
2207  DCHECK(value > 0);
2208  if (FLAG_native_code_counters && counter->Enabled()) {
2209    Operand operand = Operand::StaticVariable(ExternalReference(counter));
2210    if (value == 1) {
2211      inc(operand);
2212    } else {
2213      add(operand, Immediate(value));
2214    }
2215  }
2216}
2217
2218
2219void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) {
2220  DCHECK(value > 0);
2221  if (FLAG_native_code_counters && counter->Enabled()) {
2222    Operand operand = Operand::StaticVariable(ExternalReference(counter));
2223    if (value == 1) {
2224      dec(operand);
2225    } else {
2226      sub(operand, Immediate(value));
2227    }
2228  }
2229}
2230
2231
2232void MacroAssembler::IncrementCounter(Condition cc,
2233                                      StatsCounter* counter,
2234                                      int value) {
2235  DCHECK(value > 0);
2236  if (FLAG_native_code_counters && counter->Enabled()) {
2237    Label skip;
2238    j(NegateCondition(cc), &skip);
2239    pushfd();
2240    IncrementCounter(counter, value);
2241    popfd();
2242    bind(&skip);
2243  }
2244}
2245
2246
2247void MacroAssembler::DecrementCounter(Condition cc,
2248                                      StatsCounter* counter,
2249                                      int value) {
2250  DCHECK(value > 0);
2251  if (FLAG_native_code_counters && counter->Enabled()) {
2252    Label skip;
2253    j(NegateCondition(cc), &skip);
2254    pushfd();
2255    DecrementCounter(counter, value);
2256    popfd();
2257    bind(&skip);
2258  }
2259}
2260
2261
2262void MacroAssembler::Assert(Condition cc, BailoutReason reason) {
2263  if (emit_debug_code()) Check(cc, reason);
2264}
2265
2266
2267void MacroAssembler::AssertFastElements(Register elements) {
2268  if (emit_debug_code()) {
2269    Factory* factory = isolate()->factory();
2270    Label ok;
2271    cmp(FieldOperand(elements, HeapObject::kMapOffset),
2272        Immediate(factory->fixed_array_map()));
2273    j(equal, &ok);
2274    cmp(FieldOperand(elements, HeapObject::kMapOffset),
2275        Immediate(factory->fixed_double_array_map()));
2276    j(equal, &ok);
2277    cmp(FieldOperand(elements, HeapObject::kMapOffset),
2278        Immediate(factory->fixed_cow_array_map()));
2279    j(equal, &ok);
2280    Abort(kJSObjectWithFastElementsMapHasSlowElements);
2281    bind(&ok);
2282  }
2283}
2284
2285
2286void MacroAssembler::Check(Condition cc, BailoutReason reason) {
2287  Label L;
2288  j(cc, &L);
2289  Abort(reason);
2290  // will not return here
2291  bind(&L);
2292}
2293
2294
2295void MacroAssembler::CheckStackAlignment() {
2296  int frame_alignment = base::OS::ActivationFrameAlignment();
2297  int frame_alignment_mask = frame_alignment - 1;
2298  if (frame_alignment > kPointerSize) {
2299    DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
2300    Label alignment_as_expected;
2301    test(esp, Immediate(frame_alignment_mask));
2302    j(zero, &alignment_as_expected);
2303    // Abort if stack is not aligned.
2304    int3();
2305    bind(&alignment_as_expected);
2306  }
2307}
2308
2309
2310void MacroAssembler::Abort(BailoutReason reason) {
2311#ifdef DEBUG
2312  const char* msg = GetBailoutReason(reason);
2313  if (msg != NULL) {
2314    RecordComment("Abort message: ");
2315    RecordComment(msg);
2316  }
2317
2318  if (FLAG_trap_on_abort) {
2319    int3();
2320    return;
2321  }
2322#endif
2323
2324  // Check if Abort() has already been initialized.
2325  DCHECK(isolate()->builtins()->Abort()->IsHeapObject());
2326
2327  Move(edx, Smi::FromInt(static_cast<int>(reason)));
2328
2329  // Disable stub call restrictions to always allow calls to abort.
2330  if (!has_frame_) {
2331    // We don't actually want to generate a pile of code for this, so just
2332    // claim there is a stack frame, without generating one.
2333    FrameScope scope(this, StackFrame::NONE);
2334    Call(isolate()->builtins()->Abort(), RelocInfo::CODE_TARGET);
2335  } else {
2336    Call(isolate()->builtins()->Abort(), RelocInfo::CODE_TARGET);
2337  }
2338  // will not return here
2339  int3();
2340}
2341
2342
2343void MacroAssembler::LoadInstanceDescriptors(Register map,
2344                                             Register descriptors) {
2345  mov(descriptors, FieldOperand(map, Map::kDescriptorsOffset));
2346}
2347
2348
2349void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) {
2350  mov(dst, FieldOperand(map, Map::kBitField3Offset));
2351  DecodeField<Map::NumberOfOwnDescriptorsBits>(dst);
2352}
2353
2354
2355void MacroAssembler::LoadAccessor(Register dst, Register holder,
2356                                  int accessor_index,
2357                                  AccessorComponent accessor) {
2358  mov(dst, FieldOperand(holder, HeapObject::kMapOffset));
2359  LoadInstanceDescriptors(dst, dst);
2360  mov(dst, FieldOperand(dst, DescriptorArray::GetValueOffset(accessor_index)));
2361  int offset = accessor == ACCESSOR_GETTER ? AccessorPair::kGetterOffset
2362                                           : AccessorPair::kSetterOffset;
2363  mov(dst, FieldOperand(dst, offset));
2364}
2365
2366void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register object1,
2367                                                           Register object2,
2368                                                           Register scratch1,
2369                                                           Register scratch2,
2370                                                           Label* failure) {
2371  // Check that both objects are not smis.
2372  STATIC_ASSERT(kSmiTag == 0);
2373  mov(scratch1, object1);
2374  and_(scratch1, object2);
2375  JumpIfSmi(scratch1, failure);
2376
2377  // Load instance type for both strings.
2378  mov(scratch1, FieldOperand(object1, HeapObject::kMapOffset));
2379  mov(scratch2, FieldOperand(object2, HeapObject::kMapOffset));
2380  movzx_b(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset));
2381  movzx_b(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset));
2382
2383  // Check that both are flat one-byte strings.
2384  const int kFlatOneByteStringMask =
2385      kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
2386  const int kFlatOneByteStringTag =
2387      kStringTag | kOneByteStringTag | kSeqStringTag;
2388  // Interleave bits from both instance types and compare them in one check.
2389  const int kShift = 8;
2390  DCHECK_EQ(0, kFlatOneByteStringMask & (kFlatOneByteStringMask << kShift));
2391  and_(scratch1, kFlatOneByteStringMask);
2392  and_(scratch2, kFlatOneByteStringMask);
2393  shl(scratch2, kShift);
2394  or_(scratch1, scratch2);
2395  cmp(scratch1, kFlatOneByteStringTag | (kFlatOneByteStringTag << kShift));
2396  j(not_equal, failure);
2397}
2398
2399
2400void MacroAssembler::JumpIfNotUniqueNameInstanceType(Operand operand,
2401                                                     Label* not_unique_name,
2402                                                     Label::Distance distance) {
2403  STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
2404  Label succeed;
2405  test(operand, Immediate(kIsNotStringMask | kIsNotInternalizedMask));
2406  j(zero, &succeed);
2407  cmpb(operand, Immediate(SYMBOL_TYPE));
2408  j(not_equal, not_unique_name, distance);
2409
2410  bind(&succeed);
2411}
2412
2413
2414void MacroAssembler::EmitSeqStringSetCharCheck(Register string,
2415                                               Register index,
2416                                               Register value,
2417                                               uint32_t encoding_mask) {
2418  Label is_object;
2419  JumpIfNotSmi(string, &is_object, Label::kNear);
2420  Abort(kNonObject);
2421  bind(&is_object);
2422
2423  push(value);
2424  mov(value, FieldOperand(string, HeapObject::kMapOffset));
2425  movzx_b(value, FieldOperand(value, Map::kInstanceTypeOffset));
2426
2427  and_(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
2428  cmp(value, Immediate(encoding_mask));
2429  pop(value);
2430  Check(equal, kUnexpectedStringType);
2431
2432  // The index is assumed to be untagged coming in, tag it to compare with the
2433  // string length without using a temp register, it is restored at the end of
2434  // this function.
2435  SmiTag(index);
2436  Check(no_overflow, kIndexIsTooLarge);
2437
2438  cmp(index, FieldOperand(string, String::kLengthOffset));
2439  Check(less, kIndexIsTooLarge);
2440
2441  cmp(index, Immediate(Smi::kZero));
2442  Check(greater_equal, kIndexIsNegative);
2443
2444  // Restore the index
2445  SmiUntag(index);
2446}
2447
2448
2449void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
2450  int frame_alignment = base::OS::ActivationFrameAlignment();
2451  if (frame_alignment != 0) {
2452    // Make stack end at alignment and make room for num_arguments words
2453    // and the original value of esp.
2454    mov(scratch, esp);
2455    sub(esp, Immediate((num_arguments + 1) * kPointerSize));
2456    DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
2457    and_(esp, -frame_alignment);
2458    mov(Operand(esp, num_arguments * kPointerSize), scratch);
2459  } else {
2460    sub(esp, Immediate(num_arguments * kPointerSize));
2461  }
2462}
2463
2464
2465void MacroAssembler::CallCFunction(ExternalReference function,
2466                                   int num_arguments) {
2467  // Trashing eax is ok as it will be the return value.
2468  mov(eax, Immediate(function));
2469  CallCFunction(eax, num_arguments);
2470}
2471
2472
2473void MacroAssembler::CallCFunction(Register function,
2474                                   int num_arguments) {
2475  DCHECK(has_frame());
2476  // Check stack alignment.
2477  if (emit_debug_code()) {
2478    CheckStackAlignment();
2479  }
2480
2481  call(function);
2482  if (base::OS::ActivationFrameAlignment() != 0) {
2483    mov(esp, Operand(esp, num_arguments * kPointerSize));
2484  } else {
2485    add(esp, Immediate(num_arguments * kPointerSize));
2486  }
2487}
2488
2489
2490#ifdef DEBUG
2491bool AreAliased(Register reg1,
2492                Register reg2,
2493                Register reg3,
2494                Register reg4,
2495                Register reg5,
2496                Register reg6,
2497                Register reg7,
2498                Register reg8) {
2499  int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() +
2500      reg3.is_valid() + reg4.is_valid() + reg5.is_valid() + reg6.is_valid() +
2501      reg7.is_valid() + reg8.is_valid();
2502
2503  RegList regs = 0;
2504  if (reg1.is_valid()) regs |= reg1.bit();
2505  if (reg2.is_valid()) regs |= reg2.bit();
2506  if (reg3.is_valid()) regs |= reg3.bit();
2507  if (reg4.is_valid()) regs |= reg4.bit();
2508  if (reg5.is_valid()) regs |= reg5.bit();
2509  if (reg6.is_valid()) regs |= reg6.bit();
2510  if (reg7.is_valid()) regs |= reg7.bit();
2511  if (reg8.is_valid()) regs |= reg8.bit();
2512  int n_of_non_aliasing_regs = NumRegs(regs);
2513
2514  return n_of_valid_regs != n_of_non_aliasing_regs;
2515}
2516#endif
2517
2518
2519CodePatcher::CodePatcher(Isolate* isolate, byte* address, int size)
2520    : address_(address),
2521      size_(size),
2522      masm_(isolate, address, size + Assembler::kGap, CodeObjectRequired::kNo) {
2523  // Create a new macro assembler pointing to the address of the code to patch.
2524  // The size is adjusted with kGap on order for the assembler to generate size
2525  // bytes of instructions without failing with buffer size constraints.
2526  DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
2527}
2528
2529
2530CodePatcher::~CodePatcher() {
2531  // Indicate that code has changed.
2532  Assembler::FlushICache(masm_.isolate(), address_, size_);
2533
2534  // Check that the code was patched as expected.
2535  DCHECK(masm_.pc_ == address_ + size_);
2536  DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
2537}
2538
2539
2540void MacroAssembler::CheckPageFlag(
2541    Register object,
2542    Register scratch,
2543    int mask,
2544    Condition cc,
2545    Label* condition_met,
2546    Label::Distance condition_met_distance) {
2547  DCHECK(cc == zero || cc == not_zero);
2548  if (scratch.is(object)) {
2549    and_(scratch, Immediate(~Page::kPageAlignmentMask));
2550  } else {
2551    mov(scratch, Immediate(~Page::kPageAlignmentMask));
2552    and_(scratch, object);
2553  }
2554  if (mask < (1 << kBitsPerByte)) {
2555    test_b(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask));
2556  } else {
2557    test(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask));
2558  }
2559  j(cc, condition_met, condition_met_distance);
2560}
2561
2562
2563void MacroAssembler::CheckPageFlagForMap(
2564    Handle<Map> map,
2565    int mask,
2566    Condition cc,
2567    Label* condition_met,
2568    Label::Distance condition_met_distance) {
2569  DCHECK(cc == zero || cc == not_zero);
2570  Page* page = Page::FromAddress(map->address());
2571  DCHECK(!serializer_enabled());  // Serializer cannot match page_flags.
2572  ExternalReference reference(ExternalReference::page_flags(page));
2573  // The inlined static address check of the page's flags relies
2574  // on maps never being compacted.
2575  DCHECK(!isolate()->heap()->mark_compact_collector()->
2576         IsOnEvacuationCandidate(*map));
2577  if (mask < (1 << kBitsPerByte)) {
2578    test_b(Operand::StaticVariable(reference), Immediate(mask));
2579  } else {
2580    test(Operand::StaticVariable(reference), Immediate(mask));
2581  }
2582  j(cc, condition_met, condition_met_distance);
2583}
2584
2585
2586void MacroAssembler::JumpIfBlack(Register object,
2587                                 Register scratch0,
2588                                 Register scratch1,
2589                                 Label* on_black,
2590                                 Label::Distance on_black_near) {
2591  HasColor(object, scratch0, scratch1, on_black, on_black_near, 1,
2592           1);  // kBlackBitPattern.
2593  DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
2594}
2595
2596
2597void MacroAssembler::HasColor(Register object,
2598                              Register bitmap_scratch,
2599                              Register mask_scratch,
2600                              Label* has_color,
2601                              Label::Distance has_color_distance,
2602                              int first_bit,
2603                              int second_bit) {
2604  DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, ecx));
2605
2606  GetMarkBits(object, bitmap_scratch, mask_scratch);
2607
2608  Label other_color, word_boundary;
2609  test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
2610  j(first_bit == 1 ? zero : not_zero, &other_color, Label::kNear);
2611  add(mask_scratch, mask_scratch);  // Shift left 1 by adding.
2612  j(zero, &word_boundary, Label::kNear);
2613  test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
2614  j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance);
2615  jmp(&other_color, Label::kNear);
2616
2617  bind(&word_boundary);
2618  test_b(Operand(bitmap_scratch, MemoryChunk::kHeaderSize + kPointerSize),
2619         Immediate(1));
2620
2621  j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance);
2622  bind(&other_color);
2623}
2624
2625
2626void MacroAssembler::GetMarkBits(Register addr_reg,
2627                                 Register bitmap_reg,
2628                                 Register mask_reg) {
2629  DCHECK(!AreAliased(addr_reg, mask_reg, bitmap_reg, ecx));
2630  mov(bitmap_reg, Immediate(~Page::kPageAlignmentMask));
2631  and_(bitmap_reg, addr_reg);
2632  mov(ecx, addr_reg);
2633  int shift =
2634      Bitmap::kBitsPerCellLog2 + kPointerSizeLog2 - Bitmap::kBytesPerCellLog2;
2635  shr(ecx, shift);
2636  and_(ecx,
2637       (Page::kPageAlignmentMask >> shift) & ~(Bitmap::kBytesPerCell - 1));
2638
2639  add(bitmap_reg, ecx);
2640  mov(ecx, addr_reg);
2641  shr(ecx, kPointerSizeLog2);
2642  and_(ecx, (1 << Bitmap::kBitsPerCellLog2) - 1);
2643  mov(mask_reg, Immediate(1));
2644  shl_cl(mask_reg);
2645}
2646
2647
2648void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch,
2649                                 Register mask_scratch, Label* value_is_white,
2650                                 Label::Distance distance) {
2651  DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, ecx));
2652  GetMarkBits(value, bitmap_scratch, mask_scratch);
2653
2654  // If the value is black or grey we don't need to do anything.
2655  DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0);
2656  DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
2657  DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0);
2658  DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
2659
2660  // Since both black and grey have a 1 in the first position and white does
2661  // not have a 1 there we only need to check one bit.
2662  test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
2663  j(zero, value_is_white, Label::kNear);
2664}
2665
2666
2667void MacroAssembler::EnumLength(Register dst, Register map) {
2668  STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
2669  mov(dst, FieldOperand(map, Map::kBitField3Offset));
2670  and_(dst, Immediate(Map::EnumLengthBits::kMask));
2671  SmiTag(dst);
2672}
2673
2674
2675void MacroAssembler::CheckEnumCache(Label* call_runtime) {
2676  Label next, start;
2677  mov(ecx, eax);
2678
2679  // Check if the enum length field is properly initialized, indicating that
2680  // there is an enum cache.
2681  mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
2682
2683  EnumLength(edx, ebx);
2684  cmp(edx, Immediate(Smi::FromInt(kInvalidEnumCacheSentinel)));
2685  j(equal, call_runtime);
2686
2687  jmp(&start);
2688
2689  bind(&next);
2690  mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
2691
2692  // For all objects but the receiver, check that the cache is empty.
2693  EnumLength(edx, ebx);
2694  cmp(edx, Immediate(Smi::kZero));
2695  j(not_equal, call_runtime);
2696
2697  bind(&start);
2698
2699  // Check that there are no elements. Register rcx contains the current JS
2700  // object we've reached through the prototype chain.
2701  Label no_elements;
2702  mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset));
2703  cmp(ecx, isolate()->factory()->empty_fixed_array());
2704  j(equal, &no_elements);
2705
2706  // Second chance, the object may be using the empty slow element dictionary.
2707  cmp(ecx, isolate()->factory()->empty_slow_element_dictionary());
2708  j(not_equal, call_runtime);
2709
2710  bind(&no_elements);
2711  mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
2712  cmp(ecx, isolate()->factory()->null_value());
2713  j(not_equal, &next);
2714}
2715
2716
2717void MacroAssembler::TestJSArrayForAllocationMemento(
2718    Register receiver_reg,
2719    Register scratch_reg,
2720    Label* no_memento_found) {
2721  Label map_check;
2722  Label top_check;
2723  ExternalReference new_space_allocation_top =
2724      ExternalReference::new_space_allocation_top_address(isolate());
2725  const int kMementoMapOffset = JSArray::kSize - kHeapObjectTag;
2726  const int kMementoLastWordOffset =
2727      kMementoMapOffset + AllocationMemento::kSize - kPointerSize;
2728
2729  // Bail out if the object is not in new space.
2730  JumpIfNotInNewSpace(receiver_reg, scratch_reg, no_memento_found);
2731  // If the object is in new space, we need to check whether it is on the same
2732  // page as the current top.
2733  lea(scratch_reg, Operand(receiver_reg, kMementoLastWordOffset));
2734  xor_(scratch_reg, Operand::StaticVariable(new_space_allocation_top));
2735  test(scratch_reg, Immediate(~Page::kPageAlignmentMask));
2736  j(zero, &top_check);
2737  // The object is on a different page than allocation top. Bail out if the
2738  // object sits on the page boundary as no memento can follow and we cannot
2739  // touch the memory following it.
2740  lea(scratch_reg, Operand(receiver_reg, kMementoLastWordOffset));
2741  xor_(scratch_reg, receiver_reg);
2742  test(scratch_reg, Immediate(~Page::kPageAlignmentMask));
2743  j(not_zero, no_memento_found);
2744  // Continue with the actual map check.
2745  jmp(&map_check);
2746  // If top is on the same page as the current object, we need to check whether
2747  // we are below top.
2748  bind(&top_check);
2749  lea(scratch_reg, Operand(receiver_reg, kMementoLastWordOffset));
2750  cmp(scratch_reg, Operand::StaticVariable(new_space_allocation_top));
2751  j(greater_equal, no_memento_found);
2752  // Memento map check.
2753  bind(&map_check);
2754  mov(scratch_reg, Operand(receiver_reg, kMementoMapOffset));
2755  cmp(scratch_reg, Immediate(isolate()->factory()->allocation_memento_map()));
2756}
2757
2758void MacroAssembler::TruncatingDiv(Register dividend, int32_t divisor) {
2759  DCHECK(!dividend.is(eax));
2760  DCHECK(!dividend.is(edx));
2761  base::MagicNumbersForDivision<uint32_t> mag =
2762      base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
2763  mov(eax, Immediate(mag.multiplier));
2764  imul(dividend);
2765  bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
2766  if (divisor > 0 && neg) add(edx, dividend);
2767  if (divisor < 0 && !neg && mag.multiplier > 0) sub(edx, dividend);
2768  if (mag.shift > 0) sar(edx, mag.shift);
2769  mov(eax, dividend);
2770  shr(eax, 31);
2771  add(edx, eax);
2772}
2773
2774
2775}  // namespace internal
2776}  // namespace v8
2777
2778#endif  // V8_TARGET_ARCH_X87
2779