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 
16 namespace v8 {
17 namespace internal {
18 
19 // -------------------------------------------------------------------------
20 // MacroAssembler implementation.
21 
MacroAssembler(Isolate * arg_isolate,void * buffer,int size,CodeObjectRequired create_code_object)22 MacroAssembler::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 
Load(Register dst,const Operand & src,Representation r)34 void 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 
Store(Register src,const Operand & dst,Representation r)50 void 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 
LoadRoot(Register destination,Heap::RootListIndex index)67 void 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 
StoreRoot(Register source,Register scratch,Heap::RootListIndex index)81 void 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 
CompareRoot(Register with,Register scratch,Heap::RootListIndex index)93 void 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 
CompareRoot(Register with,Heap::RootListIndex index)105 void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) {
106   DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index));
107   cmp(with, isolate()->heap()->root_handle(index));
108 }
109 
110 
CompareRoot(const Operand & with,Heap::RootListIndex index)111 void 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 
PushRoot(Heap::RootListIndex index)118 void 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 
126 static const Register saved_regs[] = {REG(eax), REG(ecx), REG(edx)};
127 
128 #undef REG
129 
130 static const int kNumberOfSavedRegs = sizeof(saved_regs) / sizeof(Register);
131 
PushCallerSaved(SaveFPRegsMode fp_mode,Register exclusion1,Register exclusion2,Register exclusion3)132 void 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 
PopCallerSaved(SaveFPRegsMode fp_mode,Register exclusion1,Register exclusion2,Register exclusion3)151 void 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 
InNewSpace(Register object,Register scratch,Condition cc,Label * condition_met,Label::Distance distance)167 void 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 
RememberedSetHelper(Register object,Register addr,Register scratch,SaveFPRegsMode save_fp,MacroAssembler::RememberedSetFinalAction and_then)175 void 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 
ClampTOSToUint8(Register result_reg)219 void 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 
ClampUint8(Register reg)244 void 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 
SlowTruncateToI(Register result_reg,Register input_reg,int offset)254 void 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 
TruncateX87TOSToI(Register result_reg)262 void 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 
X87TOSToI(Register result_reg,MinusZeroMode minus_zero_mode,Label * lost_precision,Label * is_nan,Label * minus_zero,Label::Distance dst)270 void 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 
TruncateHeapNumberToI(Register result_reg,Register input_reg)298 void 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 
LoadUint32NoSSE2(const Operand & src)307 void 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 
RecordWriteArray(Register object,Register value,Register index,SaveFPRegsMode save_fp,RememberedSetAction remembered_set_action,SmiCheck smi_check,PointersToHereCheck pointers_to_here_check_for_value)322 void 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 
RecordWriteField(Register object,int offset,Register value,Register dst,SaveFPRegsMode save_fp,RememberedSetAction remembered_set_action,SmiCheck smi_check,PointersToHereCheck pointers_to_here_check_for_value)358 void 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 
RecordWriteForMap(Register object,Handle<Map> map,Register scratch1,Register scratch2,SaveFPRegsMode save_fp)398 void 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 
RecordWrite(Register object,Register address,Register value,SaveFPRegsMode fp_mode,RememberedSetAction remembered_set_action,SmiCheck smi_check,PointersToHereCheck pointers_to_here_check_for_value)457 void 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 
RecordWriteCodeEntryField(Register js_function,Register code_entry,Register scratch)521 void 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 
DebugBreak()591 void 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 
ShlPair(Register high,Register low,uint8_t shift)599 void 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 
ShlPair_cl(Register high,Register low)610 void 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 
ShrPair(Register high,Register low,uint8_t shift)621 void 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 
ShrPair_cl(Register high,Register low)632 void 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 
SarPair(Register high,Register low,uint8_t shift)643 void 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 
SarPair_cl(Register high,Register low)654 void 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 
IsUnsafeImmediate(const Immediate & x)665 bool 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 
SafeMove(Register dst,const Immediate & x)672 void 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 
SafePush(const Immediate & x)682 void 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 
CmpObjectType(Register heap_object,InstanceType type,Register map)692 void 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 
CmpInstanceType(Register map,InstanceType type)700 void MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
701   cmpb(FieldOperand(map, Map::kInstanceTypeOffset), Immediate(type));
702 }
703 
CheckFastObjectElements(Register map,Label * fail,Label::Distance distance)704 void MacroAssembler::CheckFastObjectElements(Register map,
705                                              Label* fail,
706                                              Label::Distance distance) {
707   STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
708   STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
709   STATIC_ASSERT(FAST_ELEMENTS == 2);
710   STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
711   cmpb(FieldOperand(map, Map::kBitField2Offset),
712        Immediate(Map::kMaximumBitField2FastHoleySmiElementValue));
713   j(below_equal, fail, distance);
714   cmpb(FieldOperand(map, Map::kBitField2Offset),
715        Immediate(Map::kMaximumBitField2FastHoleyElementValue));
716   j(above, fail, distance);
717 }
718 
719 
CheckFastSmiElements(Register map,Label * fail,Label::Distance distance)720 void MacroAssembler::CheckFastSmiElements(Register map,
721                                           Label* fail,
722                                           Label::Distance distance) {
723   STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
724   STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
725   cmpb(FieldOperand(map, Map::kBitField2Offset),
726        Immediate(Map::kMaximumBitField2FastHoleySmiElementValue));
727   j(above, fail, distance);
728 }
729 
730 
StoreNumberToDoubleElements(Register maybe_number,Register elements,Register key,Register scratch,Label * fail,int elements_offset)731 void MacroAssembler::StoreNumberToDoubleElements(
732     Register maybe_number,
733     Register elements,
734     Register key,
735     Register scratch,
736     Label* fail,
737     int elements_offset) {
738   Label smi_value, done, maybe_nan, not_nan, is_nan, have_double_value;
739   JumpIfSmi(maybe_number, &smi_value, Label::kNear);
740 
741   CheckMap(maybe_number,
742            isolate()->factory()->heap_number_map(),
743            fail,
744            DONT_DO_SMI_CHECK);
745 
746   fld_d(FieldOperand(maybe_number, HeapNumber::kValueOffset));
747   jmp(&done, Label::kNear);
748 
749   bind(&smi_value);
750   // Value is a smi. Convert to a double and store.
751   // Preserve original value.
752   mov(scratch, maybe_number);
753   SmiUntag(scratch);
754   push(scratch);
755   fild_s(Operand(esp, 0));
756   pop(scratch);
757   bind(&done);
758   fstp_d(FieldOperand(elements, key, times_4,
759                       FixedDoubleArray::kHeaderSize - elements_offset));
760 }
761 
762 
CompareMap(Register obj,Handle<Map> map)763 void MacroAssembler::CompareMap(Register obj, Handle<Map> map) {
764   cmp(FieldOperand(obj, HeapObject::kMapOffset), map);
765 }
766 
767 
CheckMap(Register obj,Handle<Map> map,Label * fail,SmiCheckType smi_check_type)768 void MacroAssembler::CheckMap(Register obj,
769                               Handle<Map> map,
770                               Label* fail,
771                               SmiCheckType smi_check_type) {
772   if (smi_check_type == DO_SMI_CHECK) {
773     JumpIfSmi(obj, fail);
774   }
775 
776   CompareMap(obj, map);
777   j(not_equal, fail);
778 }
779 
780 
DispatchWeakMap(Register obj,Register scratch1,Register scratch2,Handle<WeakCell> cell,Handle<Code> success,SmiCheckType smi_check_type)781 void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1,
782                                      Register scratch2, Handle<WeakCell> cell,
783                                      Handle<Code> success,
784                                      SmiCheckType smi_check_type) {
785   Label fail;
786   if (smi_check_type == DO_SMI_CHECK) {
787     JumpIfSmi(obj, &fail);
788   }
789   mov(scratch1, FieldOperand(obj, HeapObject::kMapOffset));
790   CmpWeakValue(scratch1, cell, scratch2);
791   j(equal, success);
792 
793   bind(&fail);
794 }
795 
796 
IsObjectStringType(Register heap_object,Register map,Register instance_type)797 Condition MacroAssembler::IsObjectStringType(Register heap_object,
798                                              Register map,
799                                              Register instance_type) {
800   mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
801   movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
802   STATIC_ASSERT(kNotStringTag != 0);
803   test(instance_type, Immediate(kIsNotStringMask));
804   return zero;
805 }
806 
807 
IsObjectNameType(Register heap_object,Register map,Register instance_type)808 Condition MacroAssembler::IsObjectNameType(Register heap_object,
809                                            Register map,
810                                            Register instance_type) {
811   mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
812   movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
813   cmpb(instance_type, Immediate(LAST_NAME_TYPE));
814   return below_equal;
815 }
816 
817 
FCmp()818 void MacroAssembler::FCmp() {
819   fucompp();
820   push(eax);
821   fnstsw_ax();
822   sahf();
823   pop(eax);
824 }
825 
826 
FXamMinusZero()827 void MacroAssembler::FXamMinusZero() {
828   fxam();
829   push(eax);
830   fnstsw_ax();
831   and_(eax, Immediate(0x4700));
832   // For minus zero, C3 == 1 && C1 == 1.
833   cmp(eax, Immediate(0x4200));
834   pop(eax);
835   fstp(0);
836 }
837 
838 
FXamSign()839 void MacroAssembler::FXamSign() {
840   fxam();
841   push(eax);
842   fnstsw_ax();
843   // For negative value (including -0.0), C1 == 1.
844   and_(eax, Immediate(0x0200));
845   pop(eax);
846   fstp(0);
847 }
848 
849 
X87CheckIA()850 void MacroAssembler::X87CheckIA() {
851   push(eax);
852   fnstsw_ax();
853   // For #IA, IE == 1 && SF == 0.
854   and_(eax, Immediate(0x0041));
855   cmp(eax, Immediate(0x0001));
856   pop(eax);
857 }
858 
859 
860 // rc=00B, round to nearest.
861 // rc=01B, round down.
862 // rc=10B, round up.
863 // rc=11B, round toward zero.
X87SetRC(int rc)864 void MacroAssembler::X87SetRC(int rc) {
865   sub(esp, Immediate(kPointerSize));
866   fnstcw(MemOperand(esp, 0));
867   and_(MemOperand(esp, 0), Immediate(0xF3FF));
868   or_(MemOperand(esp, 0), Immediate(rc));
869   fldcw(MemOperand(esp, 0));
870   add(esp, Immediate(kPointerSize));
871 }
872 
873 
X87SetFPUCW(int cw)874 void MacroAssembler::X87SetFPUCW(int cw) {
875   RecordComment("-- X87SetFPUCW start --");
876   push(Immediate(cw));
877   fldcw(MemOperand(esp, 0));
878   add(esp, Immediate(kPointerSize));
879   RecordComment("-- X87SetFPUCW end--");
880 }
881 
882 
AssertNumber(Register object)883 void MacroAssembler::AssertNumber(Register object) {
884   if (emit_debug_code()) {
885     Label ok;
886     JumpIfSmi(object, &ok);
887     cmp(FieldOperand(object, HeapObject::kMapOffset),
888         isolate()->factory()->heap_number_map());
889     Check(equal, kOperandNotANumber);
890     bind(&ok);
891   }
892 }
893 
AssertNotNumber(Register object)894 void MacroAssembler::AssertNotNumber(Register object) {
895   if (emit_debug_code()) {
896     test(object, Immediate(kSmiTagMask));
897     Check(not_equal, kOperandIsANumber);
898     cmp(FieldOperand(object, HeapObject::kMapOffset),
899         isolate()->factory()->heap_number_map());
900     Check(not_equal, kOperandIsANumber);
901   }
902 }
903 
AssertSmi(Register object)904 void MacroAssembler::AssertSmi(Register object) {
905   if (emit_debug_code()) {
906     test(object, Immediate(kSmiTagMask));
907     Check(equal, kOperandIsNotASmi);
908   }
909 }
910 
911 
AssertString(Register object)912 void MacroAssembler::AssertString(Register object) {
913   if (emit_debug_code()) {
914     test(object, Immediate(kSmiTagMask));
915     Check(not_equal, kOperandIsASmiAndNotAString);
916     push(object);
917     mov(object, FieldOperand(object, HeapObject::kMapOffset));
918     CmpInstanceType(object, FIRST_NONSTRING_TYPE);
919     pop(object);
920     Check(below, kOperandIsNotAString);
921   }
922 }
923 
924 
AssertName(Register object)925 void MacroAssembler::AssertName(Register object) {
926   if (emit_debug_code()) {
927     test(object, Immediate(kSmiTagMask));
928     Check(not_equal, kOperandIsASmiAndNotAName);
929     push(object);
930     mov(object, FieldOperand(object, HeapObject::kMapOffset));
931     CmpInstanceType(object, LAST_NAME_TYPE);
932     pop(object);
933     Check(below_equal, kOperandIsNotAName);
934   }
935 }
936 
937 
AssertFunction(Register object)938 void MacroAssembler::AssertFunction(Register object) {
939   if (emit_debug_code()) {
940     test(object, Immediate(kSmiTagMask));
941     Check(not_equal, kOperandIsASmiAndNotAFunction);
942     Push(object);
943     CmpObjectType(object, JS_FUNCTION_TYPE, object);
944     Pop(object);
945     Check(equal, kOperandIsNotAFunction);
946   }
947 }
948 
949 
AssertBoundFunction(Register object)950 void MacroAssembler::AssertBoundFunction(Register object) {
951   if (emit_debug_code()) {
952     test(object, Immediate(kSmiTagMask));
953     Check(not_equal, kOperandIsASmiAndNotABoundFunction);
954     Push(object);
955     CmpObjectType(object, JS_BOUND_FUNCTION_TYPE, object);
956     Pop(object);
957     Check(equal, kOperandIsNotABoundFunction);
958   }
959 }
960 
AssertGeneratorObject(Register object)961 void MacroAssembler::AssertGeneratorObject(Register object) {
962   if (emit_debug_code()) {
963     test(object, Immediate(kSmiTagMask));
964     Check(not_equal, kOperandIsASmiAndNotAGeneratorObject);
965     Push(object);
966     CmpObjectType(object, JS_GENERATOR_OBJECT_TYPE, object);
967     Pop(object);
968     Check(equal, kOperandIsNotAGeneratorObject);
969   }
970 }
971 
AssertReceiver(Register object)972 void MacroAssembler::AssertReceiver(Register object) {
973   if (emit_debug_code()) {
974     test(object, Immediate(kSmiTagMask));
975     Check(not_equal, kOperandIsASmiAndNotAReceiver);
976     Push(object);
977     STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
978     CmpObjectType(object, FIRST_JS_RECEIVER_TYPE, object);
979     Pop(object);
980     Check(above_equal, kOperandIsNotAReceiver);
981   }
982 }
983 
AssertUndefinedOrAllocationSite(Register object)984 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object) {
985   if (emit_debug_code()) {
986     Label done_checking;
987     AssertNotSmi(object);
988     cmp(object, isolate()->factory()->undefined_value());
989     j(equal, &done_checking);
990     cmp(FieldOperand(object, 0),
991         Immediate(isolate()->factory()->allocation_site_map()));
992     Assert(equal, kExpectedUndefinedOrCell);
993     bind(&done_checking);
994   }
995 }
996 
997 
AssertNotSmi(Register object)998 void MacroAssembler::AssertNotSmi(Register object) {
999   if (emit_debug_code()) {
1000     test(object, Immediate(kSmiTagMask));
1001     Check(not_equal, kOperandIsASmi);
1002   }
1003 }
1004 
StubPrologue(StackFrame::Type type)1005 void MacroAssembler::StubPrologue(StackFrame::Type type) {
1006   push(ebp);  // Caller's frame pointer.
1007   mov(ebp, esp);
1008   push(Immediate(Smi::FromInt(type)));
1009 }
1010 
1011 
Prologue(bool code_pre_aging)1012 void MacroAssembler::Prologue(bool code_pre_aging) {
1013   PredictableCodeSizeScope predictible_code_size_scope(this,
1014       kNoCodeAgeSequenceLength);
1015   if (code_pre_aging) {
1016       // Pre-age the code.
1017     call(isolate()->builtins()->MarkCodeAsExecutedOnce(),
1018         RelocInfo::CODE_AGE_SEQUENCE);
1019     Nop(kNoCodeAgeSequenceLength - Assembler::kCallInstructionLength);
1020   } else {
1021     push(ebp);  // Caller's frame pointer.
1022     mov(ebp, esp);
1023     push(esi);  // Callee's context.
1024     push(edi);  // Callee's JS function.
1025   }
1026 }
1027 
1028 
EmitLoadTypeFeedbackVector(Register vector)1029 void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) {
1030   mov(vector, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1031   mov(vector, FieldOperand(vector, JSFunction::kLiteralsOffset));
1032   mov(vector, FieldOperand(vector, LiteralsArray::kFeedbackVectorOffset));
1033 }
1034 
1035 
EnterFrame(StackFrame::Type type,bool load_constant_pool_pointer_reg)1036 void MacroAssembler::EnterFrame(StackFrame::Type type,
1037                                 bool load_constant_pool_pointer_reg) {
1038   // Out-of-line constant pool not implemented on x87.
1039   UNREACHABLE();
1040 }
1041 
1042 
EnterFrame(StackFrame::Type type)1043 void MacroAssembler::EnterFrame(StackFrame::Type type) {
1044   push(ebp);
1045   mov(ebp, esp);
1046   push(Immediate(Smi::FromInt(type)));
1047   if (type == StackFrame::INTERNAL) {
1048     push(Immediate(CodeObject()));
1049   }
1050   if (emit_debug_code()) {
1051     cmp(Operand(esp, 0), Immediate(isolate()->factory()->undefined_value()));
1052     Check(not_equal, kCodeObjectNotProperlyPatched);
1053   }
1054 }
1055 
1056 
LeaveFrame(StackFrame::Type type)1057 void MacroAssembler::LeaveFrame(StackFrame::Type type) {
1058   if (emit_debug_code()) {
1059     cmp(Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset),
1060         Immediate(Smi::FromInt(type)));
1061     Check(equal, kStackFrameTypesMustMatch);
1062   }
1063   leave();
1064 }
1065 
EnterBuiltinFrame(Register context,Register target,Register argc)1066 void MacroAssembler::EnterBuiltinFrame(Register context, Register target,
1067                                        Register argc) {
1068   Push(ebp);
1069   Move(ebp, esp);
1070   Push(context);
1071   Push(target);
1072   Push(argc);
1073 }
1074 
LeaveBuiltinFrame(Register context,Register target,Register argc)1075 void MacroAssembler::LeaveBuiltinFrame(Register context, Register target,
1076                                        Register argc) {
1077   Pop(argc);
1078   Pop(target);
1079   Pop(context);
1080   leave();
1081 }
1082 
EnterExitFramePrologue(StackFrame::Type frame_type)1083 void MacroAssembler::EnterExitFramePrologue(StackFrame::Type frame_type) {
1084   DCHECK(frame_type == StackFrame::EXIT ||
1085          frame_type == StackFrame::BUILTIN_EXIT);
1086 
1087   // Set up the frame structure on the stack.
1088   DCHECK_EQ(+2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement);
1089   DCHECK_EQ(+1 * kPointerSize, ExitFrameConstants::kCallerPCOffset);
1090   DCHECK_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset);
1091   push(ebp);
1092   mov(ebp, esp);
1093 
1094   // Reserve room for entry stack pointer and push the code object.
1095   push(Immediate(Smi::FromInt(frame_type)));
1096   DCHECK_EQ(-2 * kPointerSize, ExitFrameConstants::kSPOffset);
1097   push(Immediate(0));  // Saved entry sp, patched before call.
1098   DCHECK_EQ(-3 * kPointerSize, ExitFrameConstants::kCodeOffset);
1099   push(Immediate(CodeObject()));  // Accessed from ExitFrame::code_slot.
1100 
1101   // Save the frame pointer and the context in top.
1102   ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress, isolate());
1103   ExternalReference context_address(Isolate::kContextAddress, isolate());
1104   ExternalReference c_function_address(Isolate::kCFunctionAddress, isolate());
1105   mov(Operand::StaticVariable(c_entry_fp_address), ebp);
1106   mov(Operand::StaticVariable(context_address), esi);
1107   mov(Operand::StaticVariable(c_function_address), ebx);
1108 }
1109 
1110 
EnterExitFrameEpilogue(int argc,bool save_doubles)1111 void MacroAssembler::EnterExitFrameEpilogue(int argc, bool save_doubles) {
1112   // Optionally save FPU state.
1113   if (save_doubles) {
1114     // Store FPU state to m108byte.
1115     int space = 108 + argc * kPointerSize;
1116     sub(esp, Immediate(space));
1117     const int offset = -ExitFrameConstants::kFixedFrameSizeFromFp;
1118     fnsave(MemOperand(ebp, offset - 108));
1119   } else {
1120     sub(esp, Immediate(argc * kPointerSize));
1121   }
1122 
1123   // Get the required frame alignment for the OS.
1124   const int kFrameAlignment = base::OS::ActivationFrameAlignment();
1125   if (kFrameAlignment > 0) {
1126     DCHECK(base::bits::IsPowerOfTwo32(kFrameAlignment));
1127     and_(esp, -kFrameAlignment);
1128   }
1129 
1130   // Patch the saved entry sp.
1131   mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp);
1132 }
1133 
EnterExitFrame(int argc,bool save_doubles,StackFrame::Type frame_type)1134 void MacroAssembler::EnterExitFrame(int argc, bool save_doubles,
1135                                     StackFrame::Type frame_type) {
1136   EnterExitFramePrologue(frame_type);
1137 
1138   // Set up argc and argv in callee-saved registers.
1139   int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
1140   mov(edi, eax);
1141   lea(esi, Operand(ebp, eax, times_4, offset));
1142 
1143   // Reserve space for argc, argv and isolate.
1144   EnterExitFrameEpilogue(argc, save_doubles);
1145 }
1146 
1147 
EnterApiExitFrame(int argc)1148 void MacroAssembler::EnterApiExitFrame(int argc) {
1149   EnterExitFramePrologue(StackFrame::EXIT);
1150   EnterExitFrameEpilogue(argc, false);
1151 }
1152 
1153 
LeaveExitFrame(bool save_doubles,bool pop_arguments)1154 void MacroAssembler::LeaveExitFrame(bool save_doubles, bool pop_arguments) {
1155   // Optionally restore FPU state.
1156   if (save_doubles) {
1157     const int offset = -ExitFrameConstants::kFixedFrameSizeFromFp;
1158     frstor(MemOperand(ebp, offset - 108));
1159   }
1160 
1161   if (pop_arguments) {
1162     // Get the return address from the stack and restore the frame pointer.
1163     mov(ecx, Operand(ebp, 1 * kPointerSize));
1164     mov(ebp, Operand(ebp, 0 * kPointerSize));
1165 
1166     // Pop the arguments and the receiver from the caller stack.
1167     lea(esp, Operand(esi, 1 * kPointerSize));
1168 
1169     // Push the return address to get ready to return.
1170     push(ecx);
1171   } else {
1172     // Otherwise just leave the exit frame.
1173     leave();
1174   }
1175 
1176   LeaveExitFrameEpilogue(true);
1177 }
1178 
1179 
LeaveExitFrameEpilogue(bool restore_context)1180 void MacroAssembler::LeaveExitFrameEpilogue(bool restore_context) {
1181   // Restore current context from top and clear it in debug mode.
1182   ExternalReference context_address(Isolate::kContextAddress, isolate());
1183   if (restore_context) {
1184     mov(esi, Operand::StaticVariable(context_address));
1185   }
1186 #ifdef DEBUG
1187   mov(Operand::StaticVariable(context_address), Immediate(0));
1188 #endif
1189 
1190   // Clear the top frame.
1191   ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress,
1192                                        isolate());
1193   mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0));
1194 }
1195 
1196 
LeaveApiExitFrame(bool restore_context)1197 void MacroAssembler::LeaveApiExitFrame(bool restore_context) {
1198   mov(esp, ebp);
1199   pop(ebp);
1200 
1201   LeaveExitFrameEpilogue(restore_context);
1202 }
1203 
1204 
PushStackHandler()1205 void MacroAssembler::PushStackHandler() {
1206   // Adjust this code if not the case.
1207   STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize);
1208   STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
1209 
1210   // Link the current handler as the next handler.
1211   ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
1212   push(Operand::StaticVariable(handler_address));
1213 
1214   // Set this new handler as the current one.
1215   mov(Operand::StaticVariable(handler_address), esp);
1216 }
1217 
1218 
PopStackHandler()1219 void MacroAssembler::PopStackHandler() {
1220   STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
1221   ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
1222   pop(Operand::StaticVariable(handler_address));
1223   add(esp, Immediate(StackHandlerConstants::kSize - kPointerSize));
1224 }
1225 
1226 
1227 // Compute the hash code from the untagged key.  This must be kept in sync with
1228 // ComputeIntegerHash in utils.h and KeyedLoadGenericStub in
1229 // code-stub-hydrogen.cc
1230 //
1231 // Note: r0 will contain hash code
GetNumberHash(Register r0,Register scratch)1232 void MacroAssembler::GetNumberHash(Register r0, Register scratch) {
1233   // Xor original key with a seed.
1234   if (serializer_enabled()) {
1235     ExternalReference roots_array_start =
1236         ExternalReference::roots_array_start(isolate());
1237     mov(scratch, Immediate(Heap::kHashSeedRootIndex));
1238     mov(scratch,
1239         Operand::StaticArray(scratch, times_pointer_size, roots_array_start));
1240     SmiUntag(scratch);
1241     xor_(r0, scratch);
1242   } else {
1243     int32_t seed = isolate()->heap()->HashSeed();
1244     xor_(r0, Immediate(seed));
1245   }
1246 
1247   // hash = ~hash + (hash << 15);
1248   mov(scratch, r0);
1249   not_(r0);
1250   shl(scratch, 15);
1251   add(r0, scratch);
1252   // hash = hash ^ (hash >> 12);
1253   mov(scratch, r0);
1254   shr(scratch, 12);
1255   xor_(r0, scratch);
1256   // hash = hash + (hash << 2);
1257   lea(r0, Operand(r0, r0, times_4, 0));
1258   // hash = hash ^ (hash >> 4);
1259   mov(scratch, r0);
1260   shr(scratch, 4);
1261   xor_(r0, scratch);
1262   // hash = hash * 2057;
1263   imul(r0, r0, 2057);
1264   // hash = hash ^ (hash >> 16);
1265   mov(scratch, r0);
1266   shr(scratch, 16);
1267   xor_(r0, scratch);
1268   and_(r0, 0x3fffffff);
1269 }
1270 
LoadAllocationTopHelper(Register result,Register scratch,AllocationFlags flags)1271 void MacroAssembler::LoadAllocationTopHelper(Register result,
1272                                              Register scratch,
1273                                              AllocationFlags flags) {
1274   ExternalReference allocation_top =
1275       AllocationUtils::GetAllocationTopReference(isolate(), flags);
1276 
1277   // Just return if allocation top is already known.
1278   if ((flags & RESULT_CONTAINS_TOP) != 0) {
1279     // No use of scratch if allocation top is provided.
1280     DCHECK(scratch.is(no_reg));
1281 #ifdef DEBUG
1282     // Assert that result actually contains top on entry.
1283     cmp(result, Operand::StaticVariable(allocation_top));
1284     Check(equal, kUnexpectedAllocationTop);
1285 #endif
1286     return;
1287   }
1288 
1289   // Move address of new object to result. Use scratch register if available.
1290   if (scratch.is(no_reg)) {
1291     mov(result, Operand::StaticVariable(allocation_top));
1292   } else {
1293     mov(scratch, Immediate(allocation_top));
1294     mov(result, Operand(scratch, 0));
1295   }
1296 }
1297 
1298 
UpdateAllocationTopHelper(Register result_end,Register scratch,AllocationFlags flags)1299 void MacroAssembler::UpdateAllocationTopHelper(Register result_end,
1300                                                Register scratch,
1301                                                AllocationFlags flags) {
1302   if (emit_debug_code()) {
1303     test(result_end, Immediate(kObjectAlignmentMask));
1304     Check(zero, kUnalignedAllocationInNewSpace);
1305   }
1306 
1307   ExternalReference allocation_top =
1308       AllocationUtils::GetAllocationTopReference(isolate(), flags);
1309 
1310   // Update new top. Use scratch if available.
1311   if (scratch.is(no_reg)) {
1312     mov(Operand::StaticVariable(allocation_top), result_end);
1313   } else {
1314     mov(Operand(scratch, 0), result_end);
1315   }
1316 }
1317 
1318 
Allocate(int object_size,Register result,Register result_end,Register scratch,Label * gc_required,AllocationFlags flags)1319 void MacroAssembler::Allocate(int object_size,
1320                               Register result,
1321                               Register result_end,
1322                               Register scratch,
1323                               Label* gc_required,
1324                               AllocationFlags flags) {
1325   DCHECK((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0);
1326   DCHECK(object_size <= kMaxRegularHeapObjectSize);
1327   DCHECK((flags & ALLOCATION_FOLDED) == 0);
1328   if (!FLAG_inline_new) {
1329     if (emit_debug_code()) {
1330       // Trash the registers to simulate an allocation failure.
1331       mov(result, Immediate(0x7091));
1332       if (result_end.is_valid()) {
1333         mov(result_end, Immediate(0x7191));
1334       }
1335       if (scratch.is_valid()) {
1336         mov(scratch, Immediate(0x7291));
1337       }
1338     }
1339     jmp(gc_required);
1340     return;
1341   }
1342   DCHECK(!result.is(result_end));
1343 
1344   // Load address of new object into result.
1345   LoadAllocationTopHelper(result, scratch, flags);
1346 
1347   ExternalReference allocation_limit =
1348       AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1349 
1350   // Align the next allocation. Storing the filler map without checking top is
1351   // safe in new-space because the limit of the heap is aligned there.
1352   if ((flags & DOUBLE_ALIGNMENT) != 0) {
1353     DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
1354     Label aligned;
1355     test(result, Immediate(kDoubleAlignmentMask));
1356     j(zero, &aligned, Label::kNear);
1357     if ((flags & PRETENURE) != 0) {
1358       cmp(result, Operand::StaticVariable(allocation_limit));
1359       j(above_equal, gc_required);
1360     }
1361     mov(Operand(result, 0),
1362         Immediate(isolate()->factory()->one_pointer_filler_map()));
1363     add(result, Immediate(kDoubleSize / 2));
1364     bind(&aligned);
1365   }
1366 
1367   // Calculate new top and bail out if space is exhausted.
1368   Register top_reg = result_end.is_valid() ? result_end : result;
1369 
1370   if (!top_reg.is(result)) {
1371     mov(top_reg, result);
1372   }
1373   add(top_reg, Immediate(object_size));
1374   cmp(top_reg, Operand::StaticVariable(allocation_limit));
1375   j(above, gc_required);
1376 
1377   if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) {
1378     // The top pointer is not updated for allocation folding dominators.
1379     UpdateAllocationTopHelper(top_reg, scratch, flags);
1380   }
1381 
1382   if (top_reg.is(result)) {
1383     sub(result, Immediate(object_size - kHeapObjectTag));
1384   } else {
1385     // Tag the result.
1386     DCHECK(kHeapObjectTag == 1);
1387     inc(result);
1388   }
1389 }
1390 
1391 
Allocate(int header_size,ScaleFactor element_size,Register element_count,RegisterValueType element_count_type,Register result,Register result_end,Register scratch,Label * gc_required,AllocationFlags flags)1392 void MacroAssembler::Allocate(int header_size,
1393                               ScaleFactor element_size,
1394                               Register element_count,
1395                               RegisterValueType element_count_type,
1396                               Register result,
1397                               Register result_end,
1398                               Register scratch,
1399                               Label* gc_required,
1400                               AllocationFlags flags) {
1401   DCHECK((flags & SIZE_IN_WORDS) == 0);
1402   DCHECK((flags & ALLOCATION_FOLDING_DOMINATOR) == 0);
1403   DCHECK((flags & ALLOCATION_FOLDED) == 0);
1404   if (!FLAG_inline_new) {
1405     if (emit_debug_code()) {
1406       // Trash the registers to simulate an allocation failure.
1407       mov(result, Immediate(0x7091));
1408       mov(result_end, Immediate(0x7191));
1409       if (scratch.is_valid()) {
1410         mov(scratch, Immediate(0x7291));
1411       }
1412       // Register element_count is not modified by the function.
1413     }
1414     jmp(gc_required);
1415     return;
1416   }
1417   DCHECK(!result.is(result_end));
1418 
1419   // Load address of new object into result.
1420   LoadAllocationTopHelper(result, scratch, flags);
1421 
1422   ExternalReference allocation_limit =
1423       AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1424 
1425   // Align the next allocation. Storing the filler map without checking top is
1426   // safe in new-space because the limit of the heap is aligned there.
1427   if ((flags & DOUBLE_ALIGNMENT) != 0) {
1428     DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
1429     Label aligned;
1430     test(result, Immediate(kDoubleAlignmentMask));
1431     j(zero, &aligned, Label::kNear);
1432     if ((flags & PRETENURE) != 0) {
1433       cmp(result, Operand::StaticVariable(allocation_limit));
1434       j(above_equal, gc_required);
1435     }
1436     mov(Operand(result, 0),
1437         Immediate(isolate()->factory()->one_pointer_filler_map()));
1438     add(result, Immediate(kDoubleSize / 2));
1439     bind(&aligned);
1440   }
1441 
1442   // Calculate new top and bail out if space is exhausted.
1443   // We assume that element_count*element_size + header_size does not
1444   // overflow.
1445   if (element_count_type == REGISTER_VALUE_IS_SMI) {
1446     STATIC_ASSERT(static_cast<ScaleFactor>(times_2 - 1) == times_1);
1447     STATIC_ASSERT(static_cast<ScaleFactor>(times_4 - 1) == times_2);
1448     STATIC_ASSERT(static_cast<ScaleFactor>(times_8 - 1) == times_4);
1449     DCHECK(element_size >= times_2);
1450     DCHECK(kSmiTagSize == 1);
1451     element_size = static_cast<ScaleFactor>(element_size - 1);
1452   } else {
1453     DCHECK(element_count_type == REGISTER_VALUE_IS_INT32);
1454   }
1455   lea(result_end, Operand(element_count, element_size, header_size));
1456   add(result_end, result);
1457   j(carry, gc_required);
1458   cmp(result_end, Operand::StaticVariable(allocation_limit));
1459   j(above, gc_required);
1460 
1461   // Tag result.
1462   DCHECK(kHeapObjectTag == 1);
1463   inc(result);
1464 
1465   // Update allocation top.
1466   UpdateAllocationTopHelper(result_end, scratch, flags);
1467 }
1468 
Allocate(Register object_size,Register result,Register result_end,Register scratch,Label * gc_required,AllocationFlags flags)1469 void MacroAssembler::Allocate(Register object_size,
1470                               Register result,
1471                               Register result_end,
1472                               Register scratch,
1473                               Label* gc_required,
1474                               AllocationFlags flags) {
1475   DCHECK((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0);
1476   DCHECK((flags & ALLOCATION_FOLDED) == 0);
1477   if (!FLAG_inline_new) {
1478     if (emit_debug_code()) {
1479       // Trash the registers to simulate an allocation failure.
1480       mov(result, Immediate(0x7091));
1481       mov(result_end, Immediate(0x7191));
1482       if (scratch.is_valid()) {
1483         mov(scratch, Immediate(0x7291));
1484       }
1485       // object_size is left unchanged by this function.
1486     }
1487     jmp(gc_required);
1488     return;
1489   }
1490   DCHECK(!result.is(result_end));
1491 
1492   // Load address of new object into result.
1493   LoadAllocationTopHelper(result, scratch, flags);
1494 
1495   ExternalReference allocation_limit =
1496       AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1497 
1498   // Align the next allocation. Storing the filler map without checking top is
1499   // safe in new-space because the limit of the heap is aligned there.
1500   if ((flags & DOUBLE_ALIGNMENT) != 0) {
1501     DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
1502     Label aligned;
1503     test(result, Immediate(kDoubleAlignmentMask));
1504     j(zero, &aligned, Label::kNear);
1505     if ((flags & PRETENURE) != 0) {
1506       cmp(result, Operand::StaticVariable(allocation_limit));
1507       j(above_equal, gc_required);
1508     }
1509     mov(Operand(result, 0),
1510         Immediate(isolate()->factory()->one_pointer_filler_map()));
1511     add(result, Immediate(kDoubleSize / 2));
1512     bind(&aligned);
1513   }
1514 
1515   // Calculate new top and bail out if space is exhausted.
1516   if (!object_size.is(result_end)) {
1517     mov(result_end, object_size);
1518   }
1519   add(result_end, result);
1520   cmp(result_end, Operand::StaticVariable(allocation_limit));
1521   j(above, gc_required);
1522 
1523   // Tag result.
1524   DCHECK(kHeapObjectTag == 1);
1525   inc(result);
1526 
1527   if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) {
1528     // The top pointer is not updated for allocation folding dominators.
1529     UpdateAllocationTopHelper(result_end, scratch, flags);
1530   }
1531 }
1532 
FastAllocate(int object_size,Register result,Register result_end,AllocationFlags flags)1533 void MacroAssembler::FastAllocate(int object_size, Register result,
1534                                   Register result_end, AllocationFlags flags) {
1535   DCHECK(!result.is(result_end));
1536   // Load address of new object into result.
1537   LoadAllocationTopHelper(result, no_reg, flags);
1538 
1539   if ((flags & DOUBLE_ALIGNMENT) != 0) {
1540     DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
1541     Label aligned;
1542     test(result, Immediate(kDoubleAlignmentMask));
1543     j(zero, &aligned, Label::kNear);
1544     mov(Operand(result, 0),
1545         Immediate(isolate()->factory()->one_pointer_filler_map()));
1546     add(result, Immediate(kDoubleSize / 2));
1547     bind(&aligned);
1548   }
1549 
1550   lea(result_end, Operand(result, object_size));
1551   UpdateAllocationTopHelper(result_end, no_reg, flags);
1552 
1553   DCHECK(kHeapObjectTag == 1);
1554   inc(result);
1555 }
1556 
FastAllocate(Register object_size,Register result,Register result_end,AllocationFlags flags)1557 void MacroAssembler::FastAllocate(Register object_size, Register result,
1558                                   Register result_end, AllocationFlags flags) {
1559   DCHECK(!result.is(result_end));
1560   // Load address of new object into result.
1561   LoadAllocationTopHelper(result, no_reg, flags);
1562 
1563   if ((flags & DOUBLE_ALIGNMENT) != 0) {
1564     DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
1565     Label aligned;
1566     test(result, Immediate(kDoubleAlignmentMask));
1567     j(zero, &aligned, Label::kNear);
1568     mov(Operand(result, 0),
1569         Immediate(isolate()->factory()->one_pointer_filler_map()));
1570     add(result, Immediate(kDoubleSize / 2));
1571     bind(&aligned);
1572   }
1573 
1574   lea(result_end, Operand(result, object_size, times_1, 0));
1575   UpdateAllocationTopHelper(result_end, no_reg, flags);
1576 
1577   DCHECK(kHeapObjectTag == 1);
1578   inc(result);
1579 }
1580 
AllocateHeapNumber(Register result,Register scratch1,Register scratch2,Label * gc_required,MutableMode mode)1581 void MacroAssembler::AllocateHeapNumber(Register result,
1582                                         Register scratch1,
1583                                         Register scratch2,
1584                                         Label* gc_required,
1585                                         MutableMode mode) {
1586   // Allocate heap number in new space.
1587   Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required,
1588            NO_ALLOCATION_FLAGS);
1589 
1590   Handle<Map> map = mode == MUTABLE
1591       ? isolate()->factory()->mutable_heap_number_map()
1592       : isolate()->factory()->heap_number_map();
1593 
1594   // Set the map.
1595   mov(FieldOperand(result, HeapObject::kMapOffset), Immediate(map));
1596 }
1597 
1598 
AllocateTwoByteString(Register result,Register length,Register scratch1,Register scratch2,Register scratch3,Label * gc_required)1599 void MacroAssembler::AllocateTwoByteString(Register result,
1600                                            Register length,
1601                                            Register scratch1,
1602                                            Register scratch2,
1603                                            Register scratch3,
1604                                            Label* gc_required) {
1605   // Calculate the number of bytes needed for the characters in the string while
1606   // observing object alignment.
1607   DCHECK((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
1608   DCHECK(kShortSize == 2);
1609   // scratch1 = length * 2 + kObjectAlignmentMask.
1610   lea(scratch1, Operand(length, length, times_1, kObjectAlignmentMask));
1611   and_(scratch1, Immediate(~kObjectAlignmentMask));
1612 
1613   // Allocate two byte string in new space.
1614   Allocate(SeqTwoByteString::kHeaderSize, times_1, scratch1,
1615            REGISTER_VALUE_IS_INT32, result, scratch2, scratch3, gc_required,
1616            NO_ALLOCATION_FLAGS);
1617 
1618   // Set the map, length and hash field.
1619   mov(FieldOperand(result, HeapObject::kMapOffset),
1620       Immediate(isolate()->factory()->string_map()));
1621   mov(scratch1, length);
1622   SmiTag(scratch1);
1623   mov(FieldOperand(result, String::kLengthOffset), scratch1);
1624   mov(FieldOperand(result, String::kHashFieldOffset),
1625       Immediate(String::kEmptyHashField));
1626 }
1627 
1628 
AllocateOneByteString(Register result,Register length,Register scratch1,Register scratch2,Register scratch3,Label * gc_required)1629 void MacroAssembler::AllocateOneByteString(Register result, Register length,
1630                                            Register scratch1, Register scratch2,
1631                                            Register scratch3,
1632                                            Label* gc_required) {
1633   // Calculate the number of bytes needed for the characters in the string while
1634   // observing object alignment.
1635   DCHECK((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
1636   mov(scratch1, length);
1637   DCHECK(kCharSize == 1);
1638   add(scratch1, Immediate(kObjectAlignmentMask));
1639   and_(scratch1, Immediate(~kObjectAlignmentMask));
1640 
1641   // Allocate one-byte string in new space.
1642   Allocate(SeqOneByteString::kHeaderSize, times_1, scratch1,
1643            REGISTER_VALUE_IS_INT32, result, scratch2, scratch3, gc_required,
1644            NO_ALLOCATION_FLAGS);
1645 
1646   // Set the map, length and hash field.
1647   mov(FieldOperand(result, HeapObject::kMapOffset),
1648       Immediate(isolate()->factory()->one_byte_string_map()));
1649   mov(scratch1, length);
1650   SmiTag(scratch1);
1651   mov(FieldOperand(result, String::kLengthOffset), scratch1);
1652   mov(FieldOperand(result, String::kHashFieldOffset),
1653       Immediate(String::kEmptyHashField));
1654 }
1655 
1656 
AllocateOneByteString(Register result,int length,Register scratch1,Register scratch2,Label * gc_required)1657 void MacroAssembler::AllocateOneByteString(Register result, int length,
1658                                            Register scratch1, Register scratch2,
1659                                            Label* gc_required) {
1660   DCHECK(length > 0);
1661 
1662   // Allocate one-byte string in new space.
1663   Allocate(SeqOneByteString::SizeFor(length), result, scratch1, scratch2,
1664            gc_required, NO_ALLOCATION_FLAGS);
1665 
1666   // Set the map, length and hash field.
1667   mov(FieldOperand(result, HeapObject::kMapOffset),
1668       Immediate(isolate()->factory()->one_byte_string_map()));
1669   mov(FieldOperand(result, String::kLengthOffset),
1670       Immediate(Smi::FromInt(length)));
1671   mov(FieldOperand(result, String::kHashFieldOffset),
1672       Immediate(String::kEmptyHashField));
1673 }
1674 
1675 
AllocateTwoByteConsString(Register result,Register scratch1,Register scratch2,Label * gc_required)1676 void MacroAssembler::AllocateTwoByteConsString(Register result,
1677                                         Register scratch1,
1678                                         Register scratch2,
1679                                         Label* gc_required) {
1680   // Allocate heap number in new space.
1681   Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
1682            NO_ALLOCATION_FLAGS);
1683 
1684   // Set the map. The other fields are left uninitialized.
1685   mov(FieldOperand(result, HeapObject::kMapOffset),
1686       Immediate(isolate()->factory()->cons_string_map()));
1687 }
1688 
1689 
AllocateOneByteConsString(Register result,Register scratch1,Register scratch2,Label * gc_required)1690 void MacroAssembler::AllocateOneByteConsString(Register result,
1691                                                Register scratch1,
1692                                                Register scratch2,
1693                                                Label* gc_required) {
1694   Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
1695            NO_ALLOCATION_FLAGS);
1696 
1697   // Set the map. The other fields are left uninitialized.
1698   mov(FieldOperand(result, HeapObject::kMapOffset),
1699       Immediate(isolate()->factory()->cons_one_byte_string_map()));
1700 }
1701 
1702 
AllocateTwoByteSlicedString(Register result,Register scratch1,Register scratch2,Label * gc_required)1703 void MacroAssembler::AllocateTwoByteSlicedString(Register result,
1704                                           Register scratch1,
1705                                           Register scratch2,
1706                                           Label* gc_required) {
1707   // Allocate heap number in new space.
1708   Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
1709            NO_ALLOCATION_FLAGS);
1710 
1711   // Set the map. The other fields are left uninitialized.
1712   mov(FieldOperand(result, HeapObject::kMapOffset),
1713       Immediate(isolate()->factory()->sliced_string_map()));
1714 }
1715 
1716 
AllocateOneByteSlicedString(Register result,Register scratch1,Register scratch2,Label * gc_required)1717 void MacroAssembler::AllocateOneByteSlicedString(Register result,
1718                                                  Register scratch1,
1719                                                  Register scratch2,
1720                                                  Label* gc_required) {
1721   // Allocate heap number in new space.
1722   Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
1723            NO_ALLOCATION_FLAGS);
1724 
1725   // Set the map. The other fields are left uninitialized.
1726   mov(FieldOperand(result, HeapObject::kMapOffset),
1727       Immediate(isolate()->factory()->sliced_one_byte_string_map()));
1728 }
1729 
1730 
AllocateJSValue(Register result,Register constructor,Register value,Register scratch,Label * gc_required)1731 void MacroAssembler::AllocateJSValue(Register result, Register constructor,
1732                                      Register value, Register scratch,
1733                                      Label* gc_required) {
1734   DCHECK(!result.is(constructor));
1735   DCHECK(!result.is(scratch));
1736   DCHECK(!result.is(value));
1737 
1738   // Allocate JSValue in new space.
1739   Allocate(JSValue::kSize, result, scratch, no_reg, gc_required,
1740            NO_ALLOCATION_FLAGS);
1741 
1742   // Initialize the JSValue.
1743   LoadGlobalFunctionInitialMap(constructor, scratch);
1744   mov(FieldOperand(result, HeapObject::kMapOffset), scratch);
1745   LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex);
1746   mov(FieldOperand(result, JSObject::kPropertiesOffset), scratch);
1747   mov(FieldOperand(result, JSObject::kElementsOffset), scratch);
1748   mov(FieldOperand(result, JSValue::kValueOffset), value);
1749   STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
1750 }
1751 
InitializeFieldsWithFiller(Register current_address,Register end_address,Register filler)1752 void MacroAssembler::InitializeFieldsWithFiller(Register current_address,
1753                                                 Register end_address,
1754                                                 Register filler) {
1755   Label loop, entry;
1756   jmp(&entry, Label::kNear);
1757   bind(&loop);
1758   mov(Operand(current_address, 0), filler);
1759   add(current_address, Immediate(kPointerSize));
1760   bind(&entry);
1761   cmp(current_address, end_address);
1762   j(below, &loop, Label::kNear);
1763 }
1764 
1765 
BooleanBitTest(Register object,int field_offset,int bit_index)1766 void MacroAssembler::BooleanBitTest(Register object,
1767                                     int field_offset,
1768                                     int bit_index) {
1769   bit_index += kSmiTagSize + kSmiShiftSize;
1770   DCHECK(base::bits::IsPowerOfTwo32(kBitsPerByte));
1771   int byte_index = bit_index / kBitsPerByte;
1772   int byte_bit_index = bit_index & (kBitsPerByte - 1);
1773   test_b(FieldOperand(object, field_offset + byte_index),
1774          Immediate(1 << byte_bit_index));
1775 }
1776 
1777 
1778 
NegativeZeroTest(Register result,Register op,Label * then_label)1779 void MacroAssembler::NegativeZeroTest(Register result,
1780                                       Register op,
1781                                       Label* then_label) {
1782   Label ok;
1783   test(result, result);
1784   j(not_zero, &ok, Label::kNear);
1785   test(op, op);
1786   j(sign, then_label, Label::kNear);
1787   bind(&ok);
1788 }
1789 
1790 
NegativeZeroTest(Register result,Register op1,Register op2,Register scratch,Label * then_label)1791 void MacroAssembler::NegativeZeroTest(Register result,
1792                                       Register op1,
1793                                       Register op2,
1794                                       Register scratch,
1795                                       Label* then_label) {
1796   Label ok;
1797   test(result, result);
1798   j(not_zero, &ok, Label::kNear);
1799   mov(scratch, op1);
1800   or_(scratch, op2);
1801   j(sign, then_label, Label::kNear);
1802   bind(&ok);
1803 }
1804 
1805 
GetMapConstructor(Register result,Register map,Register temp)1806 void MacroAssembler::GetMapConstructor(Register result, Register map,
1807                                        Register temp) {
1808   Label done, loop;
1809   mov(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset));
1810   bind(&loop);
1811   JumpIfSmi(result, &done, Label::kNear);
1812   CmpObjectType(result, MAP_TYPE, temp);
1813   j(not_equal, &done, Label::kNear);
1814   mov(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset));
1815   jmp(&loop);
1816   bind(&done);
1817 }
1818 
1819 
TryGetFunctionPrototype(Register function,Register result,Register scratch,Label * miss)1820 void MacroAssembler::TryGetFunctionPrototype(Register function, Register result,
1821                                              Register scratch, Label* miss) {
1822   // Get the prototype or initial map from the function.
1823   mov(result,
1824       FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
1825 
1826   // If the prototype or initial map is the hole, don't return it and
1827   // simply miss the cache instead. This will allow us to allocate a
1828   // prototype object on-demand in the runtime system.
1829   cmp(result, Immediate(isolate()->factory()->the_hole_value()));
1830   j(equal, miss);
1831 
1832   // If the function does not have an initial map, we're done.
1833   Label done;
1834   CmpObjectType(result, MAP_TYPE, scratch);
1835   j(not_equal, &done, Label::kNear);
1836 
1837   // Get the prototype from the initial map.
1838   mov(result, FieldOperand(result, Map::kPrototypeOffset));
1839 
1840   // All done.
1841   bind(&done);
1842 }
1843 
1844 
CallStub(CodeStub * stub,TypeFeedbackId ast_id)1845 void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id) {
1846   DCHECK(AllowThisStubCall(stub));  // Calls are not allowed in some stubs.
1847   call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id);
1848 }
1849 
1850 
TailCallStub(CodeStub * stub)1851 void MacroAssembler::TailCallStub(CodeStub* stub) {
1852   jmp(stub->GetCode(), RelocInfo::CODE_TARGET);
1853 }
1854 
1855 
StubReturn(int argc)1856 void MacroAssembler::StubReturn(int argc) {
1857   DCHECK(argc >= 1 && generating_stub());
1858   ret((argc - 1) * kPointerSize);
1859 }
1860 
1861 
AllowThisStubCall(CodeStub * stub)1862 bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
1863   return has_frame_ || !stub->SometimesSetsUpAFrame();
1864 }
1865 
CallRuntime(const Runtime::Function * f,int num_arguments,SaveFPRegsMode save_doubles)1866 void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments,
1867                                  SaveFPRegsMode save_doubles) {
1868   // If the expected number of arguments of the runtime function is
1869   // constant, we check that the actual number of arguments match the
1870   // expectation.
1871   CHECK(f->nargs < 0 || f->nargs == num_arguments);
1872 
1873   // TODO(1236192): Most runtime routines don't need the number of
1874   // arguments passed in because it is constant. At some point we
1875   // should remove this need and make the runtime routine entry code
1876   // smarter.
1877   Move(eax, Immediate(num_arguments));
1878   mov(ebx, Immediate(ExternalReference(f, isolate())));
1879   CEntryStub ces(isolate(), 1, save_doubles);
1880   CallStub(&ces);
1881 }
1882 
1883 
CallExternalReference(ExternalReference ref,int num_arguments)1884 void MacroAssembler::CallExternalReference(ExternalReference ref,
1885                                            int num_arguments) {
1886   mov(eax, Immediate(num_arguments));
1887   mov(ebx, Immediate(ref));
1888 
1889   CEntryStub stub(isolate(), 1);
1890   CallStub(&stub);
1891 }
1892 
1893 
TailCallRuntime(Runtime::FunctionId fid)1894 void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
1895   // ----------- S t a t e -------------
1896   //  -- esp[0]                 : return address
1897   //  -- esp[8]                 : argument num_arguments - 1
1898   //  ...
1899   //  -- esp[8 * num_arguments] : argument 0 (receiver)
1900   //
1901   //  For runtime functions with variable arguments:
1902   //  -- eax                    : number of  arguments
1903   // -----------------------------------
1904 
1905   const Runtime::Function* function = Runtime::FunctionForId(fid);
1906   DCHECK_EQ(1, function->result_size);
1907   if (function->nargs >= 0) {
1908     // TODO(1236192): Most runtime routines don't need the number of
1909     // arguments passed in because it is constant. At some point we
1910     // should remove this need and make the runtime routine entry code
1911     // smarter.
1912     mov(eax, Immediate(function->nargs));
1913   }
1914   JumpToExternalReference(ExternalReference(fid, isolate()));
1915 }
1916 
JumpToExternalReference(const ExternalReference & ext,bool builtin_exit_frame)1917 void MacroAssembler::JumpToExternalReference(const ExternalReference& ext,
1918                                              bool builtin_exit_frame) {
1919   // Set the entry point and jump to the C entry runtime stub.
1920   mov(ebx, Immediate(ext));
1921   CEntryStub ces(isolate(), 1, kDontSaveFPRegs, kArgvOnStack,
1922                  builtin_exit_frame);
1923   jmp(ces.GetCode(), RelocInfo::CODE_TARGET);
1924 }
1925 
PrepareForTailCall(const ParameterCount & callee_args_count,Register caller_args_count_reg,Register scratch0,Register scratch1,ReturnAddressState ra_state,int number_of_temp_values_after_return_address)1926 void MacroAssembler::PrepareForTailCall(
1927     const ParameterCount& callee_args_count, Register caller_args_count_reg,
1928     Register scratch0, Register scratch1, ReturnAddressState ra_state,
1929     int number_of_temp_values_after_return_address) {
1930 #if DEBUG
1931   if (callee_args_count.is_reg()) {
1932     DCHECK(!AreAliased(callee_args_count.reg(), caller_args_count_reg, scratch0,
1933                        scratch1));
1934   } else {
1935     DCHECK(!AreAliased(caller_args_count_reg, scratch0, scratch1));
1936   }
1937   DCHECK(ra_state != ReturnAddressState::kNotOnStack ||
1938          number_of_temp_values_after_return_address == 0);
1939 #endif
1940 
1941   // Calculate the destination address where we will put the return address
1942   // after we drop current frame.
1943   Register new_sp_reg = scratch0;
1944   if (callee_args_count.is_reg()) {
1945     sub(caller_args_count_reg, callee_args_count.reg());
1946     lea(new_sp_reg,
1947         Operand(ebp, caller_args_count_reg, times_pointer_size,
1948                 StandardFrameConstants::kCallerPCOffset -
1949                     number_of_temp_values_after_return_address * kPointerSize));
1950   } else {
1951     lea(new_sp_reg, Operand(ebp, caller_args_count_reg, times_pointer_size,
1952                             StandardFrameConstants::kCallerPCOffset -
1953                                 (callee_args_count.immediate() +
1954                                  number_of_temp_values_after_return_address) *
1955                                     kPointerSize));
1956   }
1957 
1958   if (FLAG_debug_code) {
1959     cmp(esp, new_sp_reg);
1960     Check(below, kStackAccessBelowStackPointer);
1961   }
1962 
1963   // Copy return address from caller's frame to current frame's return address
1964   // to avoid its trashing and let the following loop copy it to the right
1965   // place.
1966   Register tmp_reg = scratch1;
1967   if (ra_state == ReturnAddressState::kOnStack) {
1968     mov(tmp_reg, Operand(ebp, StandardFrameConstants::kCallerPCOffset));
1969     mov(Operand(esp, number_of_temp_values_after_return_address * kPointerSize),
1970         tmp_reg);
1971   } else {
1972     DCHECK(ReturnAddressState::kNotOnStack == ra_state);
1973     DCHECK_EQ(0, number_of_temp_values_after_return_address);
1974     Push(Operand(ebp, StandardFrameConstants::kCallerPCOffset));
1975   }
1976 
1977   // Restore caller's frame pointer now as it could be overwritten by
1978   // the copying loop.
1979   mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
1980 
1981   // +2 here is to copy both receiver and return address.
1982   Register count_reg = caller_args_count_reg;
1983   if (callee_args_count.is_reg()) {
1984     lea(count_reg, Operand(callee_args_count.reg(),
1985                            2 + number_of_temp_values_after_return_address));
1986   } else {
1987     mov(count_reg, Immediate(callee_args_count.immediate() + 2 +
1988                              number_of_temp_values_after_return_address));
1989     // TODO(ishell): Unroll copying loop for small immediate values.
1990   }
1991 
1992   // Now copy callee arguments to the caller frame going backwards to avoid
1993   // callee arguments corruption (source and destination areas could overlap).
1994   Label loop, entry;
1995   jmp(&entry, Label::kNear);
1996   bind(&loop);
1997   dec(count_reg);
1998   mov(tmp_reg, Operand(esp, count_reg, times_pointer_size, 0));
1999   mov(Operand(new_sp_reg, count_reg, times_pointer_size, 0), tmp_reg);
2000   bind(&entry);
2001   cmp(count_reg, Immediate(0));
2002   j(not_equal, &loop, Label::kNear);
2003 
2004   // Leave current frame.
2005   mov(esp, new_sp_reg);
2006 }
2007 
InvokePrologue(const ParameterCount & expected,const ParameterCount & actual,Label * done,bool * definitely_mismatches,InvokeFlag flag,Label::Distance done_near,const CallWrapper & call_wrapper)2008 void MacroAssembler::InvokePrologue(const ParameterCount& expected,
2009                                     const ParameterCount& actual,
2010                                     Label* done,
2011                                     bool* definitely_mismatches,
2012                                     InvokeFlag flag,
2013                                     Label::Distance done_near,
2014                                     const CallWrapper& call_wrapper) {
2015   bool definitely_matches = false;
2016   *definitely_mismatches = false;
2017   Label invoke;
2018   if (expected.is_immediate()) {
2019     DCHECK(actual.is_immediate());
2020     mov(eax, actual.immediate());
2021     if (expected.immediate() == actual.immediate()) {
2022       definitely_matches = true;
2023     } else {
2024       const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
2025       if (expected.immediate() == sentinel) {
2026         // Don't worry about adapting arguments for builtins that
2027         // don't want that done. Skip adaption code by making it look
2028         // like we have a match between expected and actual number of
2029         // arguments.
2030         definitely_matches = true;
2031       } else {
2032         *definitely_mismatches = true;
2033         mov(ebx, expected.immediate());
2034       }
2035     }
2036   } else {
2037     if (actual.is_immediate()) {
2038       // Expected is in register, actual is immediate. This is the
2039       // case when we invoke function values without going through the
2040       // IC mechanism.
2041       mov(eax, actual.immediate());
2042       cmp(expected.reg(), actual.immediate());
2043       j(equal, &invoke);
2044       DCHECK(expected.reg().is(ebx));
2045     } else if (!expected.reg().is(actual.reg())) {
2046       // Both expected and actual are in (different) registers. This
2047       // is the case when we invoke functions using call and apply.
2048       cmp(expected.reg(), actual.reg());
2049       j(equal, &invoke);
2050       DCHECK(actual.reg().is(eax));
2051       DCHECK(expected.reg().is(ebx));
2052     } else {
2053       Move(eax, actual.reg());
2054     }
2055   }
2056 
2057   if (!definitely_matches) {
2058     Handle<Code> adaptor =
2059         isolate()->builtins()->ArgumentsAdaptorTrampoline();
2060     if (flag == CALL_FUNCTION) {
2061       call_wrapper.BeforeCall(CallSize(adaptor, RelocInfo::CODE_TARGET));
2062       call(adaptor, RelocInfo::CODE_TARGET);
2063       call_wrapper.AfterCall();
2064       if (!*definitely_mismatches) {
2065         jmp(done, done_near);
2066       }
2067     } else {
2068       jmp(adaptor, RelocInfo::CODE_TARGET);
2069     }
2070     bind(&invoke);
2071   }
2072 }
2073 
2074 
FloodFunctionIfStepping(Register fun,Register new_target,const ParameterCount & expected,const ParameterCount & actual)2075 void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target,
2076                                              const ParameterCount& expected,
2077                                              const ParameterCount& actual) {
2078   Label skip_flooding;
2079   ExternalReference last_step_action =
2080       ExternalReference::debug_last_step_action_address(isolate());
2081   STATIC_ASSERT(StepFrame > StepIn);
2082   cmpb(Operand::StaticVariable(last_step_action), Immediate(StepIn));
2083   j(less, &skip_flooding);
2084   {
2085     FrameScope frame(this,
2086                      has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
2087     if (expected.is_reg()) {
2088       SmiTag(expected.reg());
2089       Push(expected.reg());
2090     }
2091     if (actual.is_reg()) {
2092       SmiTag(actual.reg());
2093       Push(actual.reg());
2094     }
2095     if (new_target.is_valid()) {
2096       Push(new_target);
2097     }
2098     Push(fun);
2099     Push(fun);
2100     CallRuntime(Runtime::kDebugPrepareStepInIfStepping);
2101     Pop(fun);
2102     if (new_target.is_valid()) {
2103       Pop(new_target);
2104     }
2105     if (actual.is_reg()) {
2106       Pop(actual.reg());
2107       SmiUntag(actual.reg());
2108     }
2109     if (expected.is_reg()) {
2110       Pop(expected.reg());
2111       SmiUntag(expected.reg());
2112     }
2113   }
2114   bind(&skip_flooding);
2115 }
2116 
2117 
InvokeFunctionCode(Register function,Register new_target,const ParameterCount & expected,const ParameterCount & actual,InvokeFlag flag,const CallWrapper & call_wrapper)2118 void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
2119                                         const ParameterCount& expected,
2120                                         const ParameterCount& actual,
2121                                         InvokeFlag flag,
2122                                         const CallWrapper& call_wrapper) {
2123   // You can't call a function without a valid frame.
2124   DCHECK(flag == JUMP_FUNCTION || has_frame());
2125   DCHECK(function.is(edi));
2126   DCHECK_IMPLIES(new_target.is_valid(), new_target.is(edx));
2127 
2128   if (call_wrapper.NeedsDebugStepCheck()) {
2129     FloodFunctionIfStepping(function, new_target, expected, actual);
2130   }
2131 
2132   // Clear the new.target register if not given.
2133   if (!new_target.is_valid()) {
2134     mov(edx, isolate()->factory()->undefined_value());
2135   }
2136 
2137   Label done;
2138   bool definitely_mismatches = false;
2139   InvokePrologue(expected, actual, &done, &definitely_mismatches, flag,
2140                  Label::kNear, call_wrapper);
2141   if (!definitely_mismatches) {
2142     // We call indirectly through the code field in the function to
2143     // allow recompilation to take effect without changing any of the
2144     // call sites.
2145     Operand code = FieldOperand(function, JSFunction::kCodeEntryOffset);
2146     if (flag == CALL_FUNCTION) {
2147       call_wrapper.BeforeCall(CallSize(code));
2148       call(code);
2149       call_wrapper.AfterCall();
2150     } else {
2151       DCHECK(flag == JUMP_FUNCTION);
2152       jmp(code);
2153     }
2154     bind(&done);
2155   }
2156 }
2157 
2158 
InvokeFunction(Register fun,Register new_target,const ParameterCount & actual,InvokeFlag flag,const CallWrapper & call_wrapper)2159 void MacroAssembler::InvokeFunction(Register fun, Register new_target,
2160                                     const ParameterCount& actual,
2161                                     InvokeFlag flag,
2162                                     const CallWrapper& call_wrapper) {
2163   // You can't call a function without a valid frame.
2164   DCHECK(flag == JUMP_FUNCTION || has_frame());
2165 
2166   DCHECK(fun.is(edi));
2167   mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2168   mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2169   mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kFormalParameterCountOffset));
2170   SmiUntag(ebx);
2171 
2172   ParameterCount expected(ebx);
2173   InvokeFunctionCode(edi, new_target, expected, actual, flag, call_wrapper);
2174 }
2175 
2176 
InvokeFunction(Register fun,const ParameterCount & expected,const ParameterCount & actual,InvokeFlag flag,const CallWrapper & call_wrapper)2177 void MacroAssembler::InvokeFunction(Register fun,
2178                                     const ParameterCount& expected,
2179                                     const ParameterCount& actual,
2180                                     InvokeFlag flag,
2181                                     const CallWrapper& call_wrapper) {
2182   // You can't call a function without a valid frame.
2183   DCHECK(flag == JUMP_FUNCTION || has_frame());
2184 
2185   DCHECK(fun.is(edi));
2186   mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2187 
2188   InvokeFunctionCode(edi, no_reg, expected, actual, flag, call_wrapper);
2189 }
2190 
2191 
InvokeFunction(Handle<JSFunction> function,const ParameterCount & expected,const ParameterCount & actual,InvokeFlag flag,const CallWrapper & call_wrapper)2192 void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
2193                                     const ParameterCount& expected,
2194                                     const ParameterCount& actual,
2195                                     InvokeFlag flag,
2196                                     const CallWrapper& call_wrapper) {
2197   LoadHeapObject(edi, function);
2198   InvokeFunction(edi, expected, actual, flag, call_wrapper);
2199 }
2200 
2201 
LoadContext(Register dst,int context_chain_length)2202 void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
2203   if (context_chain_length > 0) {
2204     // Move up the chain of contexts to the context containing the slot.
2205     mov(dst, Operand(esi, Context::SlotOffset(Context::PREVIOUS_INDEX)));
2206     for (int i = 1; i < context_chain_length; i++) {
2207       mov(dst, Operand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX)));
2208     }
2209   } else {
2210     // Slot is in the current function context.  Move it into the
2211     // destination register in case we store into it (the write barrier
2212     // cannot be allowed to destroy the context in esi).
2213     mov(dst, esi);
2214   }
2215 
2216   // We should not have found a with context by walking the context chain
2217   // (i.e., the static scope chain and runtime context chain do not agree).
2218   // A variable occurring in such a scope should have slot type LOOKUP and
2219   // not CONTEXT.
2220   if (emit_debug_code()) {
2221     cmp(FieldOperand(dst, HeapObject::kMapOffset),
2222         isolate()->factory()->with_context_map());
2223     Check(not_equal, kVariableResolvedToWithContext);
2224   }
2225 }
2226 
2227 
LoadGlobalProxy(Register dst)2228 void MacroAssembler::LoadGlobalProxy(Register dst) {
2229   mov(dst, NativeContextOperand());
2230   mov(dst, ContextOperand(dst, Context::GLOBAL_PROXY_INDEX));
2231 }
2232 
2233 
LoadTransitionedArrayMapConditional(ElementsKind expected_kind,ElementsKind transitioned_kind,Register map_in_out,Register scratch,Label * no_map_match)2234 void MacroAssembler::LoadTransitionedArrayMapConditional(
2235     ElementsKind expected_kind,
2236     ElementsKind transitioned_kind,
2237     Register map_in_out,
2238     Register scratch,
2239     Label* no_map_match) {
2240   DCHECK(IsFastElementsKind(expected_kind));
2241   DCHECK(IsFastElementsKind(transitioned_kind));
2242 
2243   // Check that the function's map is the same as the expected cached map.
2244   mov(scratch, NativeContextOperand());
2245   cmp(map_in_out,
2246       ContextOperand(scratch, Context::ArrayMapIndex(expected_kind)));
2247   j(not_equal, no_map_match);
2248 
2249   // Use the transitioned cached map.
2250   mov(map_in_out,
2251       ContextOperand(scratch, Context::ArrayMapIndex(transitioned_kind)));
2252 }
2253 
2254 
LoadGlobalFunction(int index,Register function)2255 void MacroAssembler::LoadGlobalFunction(int index, Register function) {
2256   // Load the native context from the current context.
2257   mov(function, NativeContextOperand());
2258   // Load the function from the native context.
2259   mov(function, ContextOperand(function, index));
2260 }
2261 
2262 
LoadGlobalFunctionInitialMap(Register function,Register map)2263 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
2264                                                   Register map) {
2265   // Load the initial map.  The global functions all have initial maps.
2266   mov(map, FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2267   if (emit_debug_code()) {
2268     Label ok, fail;
2269     CheckMap(map, isolate()->factory()->meta_map(), &fail, DO_SMI_CHECK);
2270     jmp(&ok);
2271     bind(&fail);
2272     Abort(kGlobalFunctionsMustHaveInitialMap);
2273     bind(&ok);
2274   }
2275 }
2276 
2277 
2278 // Store the value in register src in the safepoint register stack
2279 // slot for register dst.
StoreToSafepointRegisterSlot(Register dst,Register src)2280 void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, Register src) {
2281   mov(SafepointRegisterSlot(dst), src);
2282 }
2283 
2284 
StoreToSafepointRegisterSlot(Register dst,Immediate src)2285 void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, Immediate src) {
2286   mov(SafepointRegisterSlot(dst), src);
2287 }
2288 
2289 
LoadFromSafepointRegisterSlot(Register dst,Register src)2290 void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) {
2291   mov(dst, SafepointRegisterSlot(src));
2292 }
2293 
2294 
SafepointRegisterSlot(Register reg)2295 Operand MacroAssembler::SafepointRegisterSlot(Register reg) {
2296   return Operand(esp, SafepointRegisterStackIndex(reg.code()) * kPointerSize);
2297 }
2298 
2299 
SafepointRegisterStackIndex(int reg_code)2300 int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
2301   // The registers are pushed starting with the lowest encoding,
2302   // which means that lowest encodings are furthest away from
2303   // the stack pointer.
2304   DCHECK(reg_code >= 0 && reg_code < kNumSafepointRegisters);
2305   return kNumSafepointRegisters - reg_code - 1;
2306 }
2307 
2308 
LoadHeapObject(Register result,Handle<HeapObject> object)2309 void MacroAssembler::LoadHeapObject(Register result,
2310                                     Handle<HeapObject> object) {
2311   mov(result, object);
2312 }
2313 
2314 
CmpHeapObject(Register reg,Handle<HeapObject> object)2315 void MacroAssembler::CmpHeapObject(Register reg, Handle<HeapObject> object) {
2316   cmp(reg, object);
2317 }
2318 
PushHeapObject(Handle<HeapObject> object)2319 void MacroAssembler::PushHeapObject(Handle<HeapObject> object) { Push(object); }
2320 
CmpWeakValue(Register value,Handle<WeakCell> cell,Register scratch)2321 void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell,
2322                                   Register scratch) {
2323   mov(scratch, cell);
2324   cmp(value, FieldOperand(scratch, WeakCell::kValueOffset));
2325 }
2326 
2327 
GetWeakValue(Register value,Handle<WeakCell> cell)2328 void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) {
2329   mov(value, cell);
2330   mov(value, FieldOperand(value, WeakCell::kValueOffset));
2331 }
2332 
2333 
LoadWeakValue(Register value,Handle<WeakCell> cell,Label * miss)2334 void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
2335                                    Label* miss) {
2336   GetWeakValue(value, cell);
2337   JumpIfSmi(value, miss);
2338 }
2339 
2340 
Ret()2341 void MacroAssembler::Ret() {
2342   ret(0);
2343 }
2344 
2345 
Ret(int bytes_dropped,Register scratch)2346 void MacroAssembler::Ret(int bytes_dropped, Register scratch) {
2347   if (is_uint16(bytes_dropped)) {
2348     ret(bytes_dropped);
2349   } else {
2350     pop(scratch);
2351     add(esp, Immediate(bytes_dropped));
2352     push(scratch);
2353     ret(0);
2354   }
2355 }
2356 
2357 
VerifyX87StackDepth(uint32_t depth)2358 void MacroAssembler::VerifyX87StackDepth(uint32_t depth) {
2359   // Turn off the stack depth check when serializer is enabled to reduce the
2360   // code size.
2361   if (serializer_enabled()) return;
2362   // Make sure the floating point stack is either empty or has depth items.
2363   DCHECK(depth <= 7);
2364   // This is very expensive.
2365   DCHECK(FLAG_debug_code && FLAG_enable_slow_asserts);
2366 
2367   // The top-of-stack (tos) is 7 if there is one item pushed.
2368   int tos = (8 - depth) % 8;
2369   const int kTopMask = 0x3800;
2370   push(eax);
2371   fwait();
2372   fnstsw_ax();
2373   and_(eax, kTopMask);
2374   shr(eax, 11);
2375   cmp(eax, Immediate(tos));
2376   Check(equal, kUnexpectedFPUStackDepthAfterInstruction);
2377   fnclex();
2378   pop(eax);
2379 }
2380 
2381 
Drop(int stack_elements)2382 void MacroAssembler::Drop(int stack_elements) {
2383   if (stack_elements > 0) {
2384     add(esp, Immediate(stack_elements * kPointerSize));
2385   }
2386 }
2387 
2388 
Move(Register dst,Register src)2389 void MacroAssembler::Move(Register dst, Register src) {
2390   if (!dst.is(src)) {
2391     mov(dst, src);
2392   }
2393 }
2394 
2395 
Move(Register dst,const Immediate & x)2396 void MacroAssembler::Move(Register dst, const Immediate& x) {
2397   if (x.is_zero() && RelocInfo::IsNone(x.rmode_)) {
2398     xor_(dst, dst);  // Shorter than mov of 32-bit immediate 0.
2399   } else {
2400     mov(dst, x);
2401   }
2402 }
2403 
2404 
Move(const Operand & dst,const Immediate & x)2405 void MacroAssembler::Move(const Operand& dst, const Immediate& x) {
2406   mov(dst, x);
2407 }
2408 
2409 
Lzcnt(Register dst,const Operand & src)2410 void MacroAssembler::Lzcnt(Register dst, const Operand& src) {
2411   // TODO(intel): Add support for LZCNT (with ABM/BMI1).
2412   Label not_zero_src;
2413   bsr(dst, src);
2414   j(not_zero, &not_zero_src, Label::kNear);
2415   Move(dst, Immediate(63));  // 63^31 == 32
2416   bind(&not_zero_src);
2417   xor_(dst, Immediate(31));  // for x in [0..31], 31^x == 31-x.
2418 }
2419 
2420 
Tzcnt(Register dst,const Operand & src)2421 void MacroAssembler::Tzcnt(Register dst, const Operand& src) {
2422   // TODO(intel): Add support for TZCNT (with ABM/BMI1).
2423   Label not_zero_src;
2424   bsf(dst, src);
2425   j(not_zero, &not_zero_src, Label::kNear);
2426   Move(dst, Immediate(32));  // The result of tzcnt is 32 if src = 0.
2427   bind(&not_zero_src);
2428 }
2429 
2430 
Popcnt(Register dst,const Operand & src)2431 void MacroAssembler::Popcnt(Register dst, const Operand& src) {
2432   // TODO(intel): Add support for POPCNT (with POPCNT)
2433   // if (CpuFeatures::IsSupported(POPCNT)) {
2434   //   CpuFeatureScope scope(this, POPCNT);
2435   //   popcnt(dst, src);
2436   //   return;
2437   // }
2438   UNREACHABLE();
2439 }
2440 
2441 
SetCounter(StatsCounter * counter,int value)2442 void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
2443   if (FLAG_native_code_counters && counter->Enabled()) {
2444     mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value));
2445   }
2446 }
2447 
2448 
IncrementCounter(StatsCounter * counter,int value)2449 void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) {
2450   DCHECK(value > 0);
2451   if (FLAG_native_code_counters && counter->Enabled()) {
2452     Operand operand = Operand::StaticVariable(ExternalReference(counter));
2453     if (value == 1) {
2454       inc(operand);
2455     } else {
2456       add(operand, Immediate(value));
2457     }
2458   }
2459 }
2460 
2461 
DecrementCounter(StatsCounter * counter,int value)2462 void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) {
2463   DCHECK(value > 0);
2464   if (FLAG_native_code_counters && counter->Enabled()) {
2465     Operand operand = Operand::StaticVariable(ExternalReference(counter));
2466     if (value == 1) {
2467       dec(operand);
2468     } else {
2469       sub(operand, Immediate(value));
2470     }
2471   }
2472 }
2473 
2474 
IncrementCounter(Condition cc,StatsCounter * counter,int value)2475 void MacroAssembler::IncrementCounter(Condition cc,
2476                                       StatsCounter* counter,
2477                                       int value) {
2478   DCHECK(value > 0);
2479   if (FLAG_native_code_counters && counter->Enabled()) {
2480     Label skip;
2481     j(NegateCondition(cc), &skip);
2482     pushfd();
2483     IncrementCounter(counter, value);
2484     popfd();
2485     bind(&skip);
2486   }
2487 }
2488 
2489 
DecrementCounter(Condition cc,StatsCounter * counter,int value)2490 void MacroAssembler::DecrementCounter(Condition cc,
2491                                       StatsCounter* counter,
2492                                       int value) {
2493   DCHECK(value > 0);
2494   if (FLAG_native_code_counters && counter->Enabled()) {
2495     Label skip;
2496     j(NegateCondition(cc), &skip);
2497     pushfd();
2498     DecrementCounter(counter, value);
2499     popfd();
2500     bind(&skip);
2501   }
2502 }
2503 
2504 
Assert(Condition cc,BailoutReason reason)2505 void MacroAssembler::Assert(Condition cc, BailoutReason reason) {
2506   if (emit_debug_code()) Check(cc, reason);
2507 }
2508 
2509 
AssertFastElements(Register elements)2510 void MacroAssembler::AssertFastElements(Register elements) {
2511   if (emit_debug_code()) {
2512     Factory* factory = isolate()->factory();
2513     Label ok;
2514     cmp(FieldOperand(elements, HeapObject::kMapOffset),
2515         Immediate(factory->fixed_array_map()));
2516     j(equal, &ok);
2517     cmp(FieldOperand(elements, HeapObject::kMapOffset),
2518         Immediate(factory->fixed_double_array_map()));
2519     j(equal, &ok);
2520     cmp(FieldOperand(elements, HeapObject::kMapOffset),
2521         Immediate(factory->fixed_cow_array_map()));
2522     j(equal, &ok);
2523     Abort(kJSObjectWithFastElementsMapHasSlowElements);
2524     bind(&ok);
2525   }
2526 }
2527 
2528 
Check(Condition cc,BailoutReason reason)2529 void MacroAssembler::Check(Condition cc, BailoutReason reason) {
2530   Label L;
2531   j(cc, &L);
2532   Abort(reason);
2533   // will not return here
2534   bind(&L);
2535 }
2536 
2537 
CheckStackAlignment()2538 void MacroAssembler::CheckStackAlignment() {
2539   int frame_alignment = base::OS::ActivationFrameAlignment();
2540   int frame_alignment_mask = frame_alignment - 1;
2541   if (frame_alignment > kPointerSize) {
2542     DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
2543     Label alignment_as_expected;
2544     test(esp, Immediate(frame_alignment_mask));
2545     j(zero, &alignment_as_expected);
2546     // Abort if stack is not aligned.
2547     int3();
2548     bind(&alignment_as_expected);
2549   }
2550 }
2551 
2552 
Abort(BailoutReason reason)2553 void MacroAssembler::Abort(BailoutReason reason) {
2554 #ifdef DEBUG
2555   const char* msg = GetBailoutReason(reason);
2556   if (msg != NULL) {
2557     RecordComment("Abort message: ");
2558     RecordComment(msg);
2559   }
2560 
2561   if (FLAG_trap_on_abort) {
2562     int3();
2563     return;
2564   }
2565 #endif
2566 
2567   // Check if Abort() has already been initialized.
2568   DCHECK(isolate()->builtins()->Abort()->IsHeapObject());
2569 
2570   Move(edx, Smi::FromInt(static_cast<int>(reason)));
2571 
2572   // Disable stub call restrictions to always allow calls to abort.
2573   if (!has_frame_) {
2574     // We don't actually want to generate a pile of code for this, so just
2575     // claim there is a stack frame, without generating one.
2576     FrameScope scope(this, StackFrame::NONE);
2577     Call(isolate()->builtins()->Abort(), RelocInfo::CODE_TARGET);
2578   } else {
2579     Call(isolate()->builtins()->Abort(), RelocInfo::CODE_TARGET);
2580   }
2581   // will not return here
2582   int3();
2583 }
2584 
2585 
LoadInstanceDescriptors(Register map,Register descriptors)2586 void MacroAssembler::LoadInstanceDescriptors(Register map,
2587                                              Register descriptors) {
2588   mov(descriptors, FieldOperand(map, Map::kDescriptorsOffset));
2589 }
2590 
2591 
NumberOfOwnDescriptors(Register dst,Register map)2592 void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) {
2593   mov(dst, FieldOperand(map, Map::kBitField3Offset));
2594   DecodeField<Map::NumberOfOwnDescriptorsBits>(dst);
2595 }
2596 
2597 
LoadAccessor(Register dst,Register holder,int accessor_index,AccessorComponent accessor)2598 void MacroAssembler::LoadAccessor(Register dst, Register holder,
2599                                   int accessor_index,
2600                                   AccessorComponent accessor) {
2601   mov(dst, FieldOperand(holder, HeapObject::kMapOffset));
2602   LoadInstanceDescriptors(dst, dst);
2603   mov(dst, FieldOperand(dst, DescriptorArray::GetValueOffset(accessor_index)));
2604   int offset = accessor == ACCESSOR_GETTER ? AccessorPair::kGetterOffset
2605                                            : AccessorPair::kSetterOffset;
2606   mov(dst, FieldOperand(dst, offset));
2607 }
2608 
2609 
JumpIfInstanceTypeIsNotSequentialOneByte(Register instance_type,Register scratch,Label * failure)2610 void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte(
2611     Register instance_type, Register scratch, Label* failure) {
2612   if (!scratch.is(instance_type)) {
2613     mov(scratch, instance_type);
2614   }
2615   and_(scratch,
2616        kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask);
2617   cmp(scratch, kStringTag | kSeqStringTag | kOneByteStringTag);
2618   j(not_equal, failure);
2619 }
2620 
2621 
JumpIfNotBothSequentialOneByteStrings(Register object1,Register object2,Register scratch1,Register scratch2,Label * failure)2622 void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register object1,
2623                                                            Register object2,
2624                                                            Register scratch1,
2625                                                            Register scratch2,
2626                                                            Label* failure) {
2627   // Check that both objects are not smis.
2628   STATIC_ASSERT(kSmiTag == 0);
2629   mov(scratch1, object1);
2630   and_(scratch1, object2);
2631   JumpIfSmi(scratch1, failure);
2632 
2633   // Load instance type for both strings.
2634   mov(scratch1, FieldOperand(object1, HeapObject::kMapOffset));
2635   mov(scratch2, FieldOperand(object2, HeapObject::kMapOffset));
2636   movzx_b(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset));
2637   movzx_b(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset));
2638 
2639   // Check that both are flat one-byte strings.
2640   const int kFlatOneByteStringMask =
2641       kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
2642   const int kFlatOneByteStringTag =
2643       kStringTag | kOneByteStringTag | kSeqStringTag;
2644   // Interleave bits from both instance types and compare them in one check.
2645   DCHECK_EQ(0, kFlatOneByteStringMask & (kFlatOneByteStringMask << 3));
2646   and_(scratch1, kFlatOneByteStringMask);
2647   and_(scratch2, kFlatOneByteStringMask);
2648   lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
2649   cmp(scratch1, kFlatOneByteStringTag | (kFlatOneByteStringTag << 3));
2650   j(not_equal, failure);
2651 }
2652 
2653 
JumpIfNotUniqueNameInstanceType(Operand operand,Label * not_unique_name,Label::Distance distance)2654 void MacroAssembler::JumpIfNotUniqueNameInstanceType(Operand operand,
2655                                                      Label* not_unique_name,
2656                                                      Label::Distance distance) {
2657   STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
2658   Label succeed;
2659   test(operand, Immediate(kIsNotStringMask | kIsNotInternalizedMask));
2660   j(zero, &succeed);
2661   cmpb(operand, Immediate(SYMBOL_TYPE));
2662   j(not_equal, not_unique_name, distance);
2663 
2664   bind(&succeed);
2665 }
2666 
2667 
EmitSeqStringSetCharCheck(Register string,Register index,Register value,uint32_t encoding_mask)2668 void MacroAssembler::EmitSeqStringSetCharCheck(Register string,
2669                                                Register index,
2670                                                Register value,
2671                                                uint32_t encoding_mask) {
2672   Label is_object;
2673   JumpIfNotSmi(string, &is_object, Label::kNear);
2674   Abort(kNonObject);
2675   bind(&is_object);
2676 
2677   push(value);
2678   mov(value, FieldOperand(string, HeapObject::kMapOffset));
2679   movzx_b(value, FieldOperand(value, Map::kInstanceTypeOffset));
2680 
2681   and_(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
2682   cmp(value, Immediate(encoding_mask));
2683   pop(value);
2684   Check(equal, kUnexpectedStringType);
2685 
2686   // The index is assumed to be untagged coming in, tag it to compare with the
2687   // string length without using a temp register, it is restored at the end of
2688   // this function.
2689   SmiTag(index);
2690   Check(no_overflow, kIndexIsTooLarge);
2691 
2692   cmp(index, FieldOperand(string, String::kLengthOffset));
2693   Check(less, kIndexIsTooLarge);
2694 
2695   cmp(index, Immediate(Smi::kZero));
2696   Check(greater_equal, kIndexIsNegative);
2697 
2698   // Restore the index
2699   SmiUntag(index);
2700 }
2701 
2702 
PrepareCallCFunction(int num_arguments,Register scratch)2703 void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
2704   int frame_alignment = base::OS::ActivationFrameAlignment();
2705   if (frame_alignment != 0) {
2706     // Make stack end at alignment and make room for num_arguments words
2707     // and the original value of esp.
2708     mov(scratch, esp);
2709     sub(esp, Immediate((num_arguments + 1) * kPointerSize));
2710     DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
2711     and_(esp, -frame_alignment);
2712     mov(Operand(esp, num_arguments * kPointerSize), scratch);
2713   } else {
2714     sub(esp, Immediate(num_arguments * kPointerSize));
2715   }
2716 }
2717 
2718 
CallCFunction(ExternalReference function,int num_arguments)2719 void MacroAssembler::CallCFunction(ExternalReference function,
2720                                    int num_arguments) {
2721   // Trashing eax is ok as it will be the return value.
2722   mov(eax, Immediate(function));
2723   CallCFunction(eax, num_arguments);
2724 }
2725 
2726 
CallCFunction(Register function,int num_arguments)2727 void MacroAssembler::CallCFunction(Register function,
2728                                    int num_arguments) {
2729   DCHECK(has_frame());
2730   // Check stack alignment.
2731   if (emit_debug_code()) {
2732     CheckStackAlignment();
2733   }
2734 
2735   call(function);
2736   if (base::OS::ActivationFrameAlignment() != 0) {
2737     mov(esp, Operand(esp, num_arguments * kPointerSize));
2738   } else {
2739     add(esp, Immediate(num_arguments * kPointerSize));
2740   }
2741 }
2742 
2743 
2744 #ifdef DEBUG
AreAliased(Register reg1,Register reg2,Register reg3,Register reg4,Register reg5,Register reg6,Register reg7,Register reg8)2745 bool AreAliased(Register reg1,
2746                 Register reg2,
2747                 Register reg3,
2748                 Register reg4,
2749                 Register reg5,
2750                 Register reg6,
2751                 Register reg7,
2752                 Register reg8) {
2753   int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() +
2754       reg3.is_valid() + reg4.is_valid() + reg5.is_valid() + reg6.is_valid() +
2755       reg7.is_valid() + reg8.is_valid();
2756 
2757   RegList regs = 0;
2758   if (reg1.is_valid()) regs |= reg1.bit();
2759   if (reg2.is_valid()) regs |= reg2.bit();
2760   if (reg3.is_valid()) regs |= reg3.bit();
2761   if (reg4.is_valid()) regs |= reg4.bit();
2762   if (reg5.is_valid()) regs |= reg5.bit();
2763   if (reg6.is_valid()) regs |= reg6.bit();
2764   if (reg7.is_valid()) regs |= reg7.bit();
2765   if (reg8.is_valid()) regs |= reg8.bit();
2766   int n_of_non_aliasing_regs = NumRegs(regs);
2767 
2768   return n_of_valid_regs != n_of_non_aliasing_regs;
2769 }
2770 #endif
2771 
2772 
CodePatcher(Isolate * isolate,byte * address,int size)2773 CodePatcher::CodePatcher(Isolate* isolate, byte* address, int size)
2774     : address_(address),
2775       size_(size),
2776       masm_(isolate, address, size + Assembler::kGap, CodeObjectRequired::kNo) {
2777   // Create a new macro assembler pointing to the address of the code to patch.
2778   // The size is adjusted with kGap on order for the assembler to generate size
2779   // bytes of instructions without failing with buffer size constraints.
2780   DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
2781 }
2782 
2783 
~CodePatcher()2784 CodePatcher::~CodePatcher() {
2785   // Indicate that code has changed.
2786   Assembler::FlushICache(masm_.isolate(), address_, size_);
2787 
2788   // Check that the code was patched as expected.
2789   DCHECK(masm_.pc_ == address_ + size_);
2790   DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
2791 }
2792 
2793 
CheckPageFlag(Register object,Register scratch,int mask,Condition cc,Label * condition_met,Label::Distance condition_met_distance)2794 void MacroAssembler::CheckPageFlag(
2795     Register object,
2796     Register scratch,
2797     int mask,
2798     Condition cc,
2799     Label* condition_met,
2800     Label::Distance condition_met_distance) {
2801   DCHECK(cc == zero || cc == not_zero);
2802   if (scratch.is(object)) {
2803     and_(scratch, Immediate(~Page::kPageAlignmentMask));
2804   } else {
2805     mov(scratch, Immediate(~Page::kPageAlignmentMask));
2806     and_(scratch, object);
2807   }
2808   if (mask < (1 << kBitsPerByte)) {
2809     test_b(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask));
2810   } else {
2811     test(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask));
2812   }
2813   j(cc, condition_met, condition_met_distance);
2814 }
2815 
2816 
CheckPageFlagForMap(Handle<Map> map,int mask,Condition cc,Label * condition_met,Label::Distance condition_met_distance)2817 void MacroAssembler::CheckPageFlagForMap(
2818     Handle<Map> map,
2819     int mask,
2820     Condition cc,
2821     Label* condition_met,
2822     Label::Distance condition_met_distance) {
2823   DCHECK(cc == zero || cc == not_zero);
2824   Page* page = Page::FromAddress(map->address());
2825   DCHECK(!serializer_enabled());  // Serializer cannot match page_flags.
2826   ExternalReference reference(ExternalReference::page_flags(page));
2827   // The inlined static address check of the page's flags relies
2828   // on maps never being compacted.
2829   DCHECK(!isolate()->heap()->mark_compact_collector()->
2830          IsOnEvacuationCandidate(*map));
2831   if (mask < (1 << kBitsPerByte)) {
2832     test_b(Operand::StaticVariable(reference), Immediate(mask));
2833   } else {
2834     test(Operand::StaticVariable(reference), Immediate(mask));
2835   }
2836   j(cc, condition_met, condition_met_distance);
2837 }
2838 
2839 
JumpIfBlack(Register object,Register scratch0,Register scratch1,Label * on_black,Label::Distance on_black_near)2840 void MacroAssembler::JumpIfBlack(Register object,
2841                                  Register scratch0,
2842                                  Register scratch1,
2843                                  Label* on_black,
2844                                  Label::Distance on_black_near) {
2845   HasColor(object, scratch0, scratch1, on_black, on_black_near, 1,
2846            1);  // kBlackBitPattern.
2847   DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
2848 }
2849 
2850 
HasColor(Register object,Register bitmap_scratch,Register mask_scratch,Label * has_color,Label::Distance has_color_distance,int first_bit,int second_bit)2851 void MacroAssembler::HasColor(Register object,
2852                               Register bitmap_scratch,
2853                               Register mask_scratch,
2854                               Label* has_color,
2855                               Label::Distance has_color_distance,
2856                               int first_bit,
2857                               int second_bit) {
2858   DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, ecx));
2859 
2860   GetMarkBits(object, bitmap_scratch, mask_scratch);
2861 
2862   Label other_color, word_boundary;
2863   test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
2864   j(first_bit == 1 ? zero : not_zero, &other_color, Label::kNear);
2865   add(mask_scratch, mask_scratch);  // Shift left 1 by adding.
2866   j(zero, &word_boundary, Label::kNear);
2867   test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
2868   j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance);
2869   jmp(&other_color, Label::kNear);
2870 
2871   bind(&word_boundary);
2872   test_b(Operand(bitmap_scratch, MemoryChunk::kHeaderSize + kPointerSize),
2873          Immediate(1));
2874 
2875   j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance);
2876   bind(&other_color);
2877 }
2878 
2879 
GetMarkBits(Register addr_reg,Register bitmap_reg,Register mask_reg)2880 void MacroAssembler::GetMarkBits(Register addr_reg,
2881                                  Register bitmap_reg,
2882                                  Register mask_reg) {
2883   DCHECK(!AreAliased(addr_reg, mask_reg, bitmap_reg, ecx));
2884   mov(bitmap_reg, Immediate(~Page::kPageAlignmentMask));
2885   and_(bitmap_reg, addr_reg);
2886   mov(ecx, addr_reg);
2887   int shift =
2888       Bitmap::kBitsPerCellLog2 + kPointerSizeLog2 - Bitmap::kBytesPerCellLog2;
2889   shr(ecx, shift);
2890   and_(ecx,
2891        (Page::kPageAlignmentMask >> shift) & ~(Bitmap::kBytesPerCell - 1));
2892 
2893   add(bitmap_reg, ecx);
2894   mov(ecx, addr_reg);
2895   shr(ecx, kPointerSizeLog2);
2896   and_(ecx, (1 << Bitmap::kBitsPerCellLog2) - 1);
2897   mov(mask_reg, Immediate(1));
2898   shl_cl(mask_reg);
2899 }
2900 
2901 
JumpIfWhite(Register value,Register bitmap_scratch,Register mask_scratch,Label * value_is_white,Label::Distance distance)2902 void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch,
2903                                  Register mask_scratch, Label* value_is_white,
2904                                  Label::Distance distance) {
2905   DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, ecx));
2906   GetMarkBits(value, bitmap_scratch, mask_scratch);
2907 
2908   // If the value is black or grey we don't need to do anything.
2909   DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0);
2910   DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
2911   DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0);
2912   DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
2913 
2914   // Since both black and grey have a 1 in the first position and white does
2915   // not have a 1 there we only need to check one bit.
2916   test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
2917   j(zero, value_is_white, Label::kNear);
2918 }
2919 
2920 
EnumLength(Register dst,Register map)2921 void MacroAssembler::EnumLength(Register dst, Register map) {
2922   STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
2923   mov(dst, FieldOperand(map, Map::kBitField3Offset));
2924   and_(dst, Immediate(Map::EnumLengthBits::kMask));
2925   SmiTag(dst);
2926 }
2927 
2928 
CheckEnumCache(Label * call_runtime)2929 void MacroAssembler::CheckEnumCache(Label* call_runtime) {
2930   Label next, start;
2931   mov(ecx, eax);
2932 
2933   // Check if the enum length field is properly initialized, indicating that
2934   // there is an enum cache.
2935   mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
2936 
2937   EnumLength(edx, ebx);
2938   cmp(edx, Immediate(Smi::FromInt(kInvalidEnumCacheSentinel)));
2939   j(equal, call_runtime);
2940 
2941   jmp(&start);
2942 
2943   bind(&next);
2944   mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
2945 
2946   // For all objects but the receiver, check that the cache is empty.
2947   EnumLength(edx, ebx);
2948   cmp(edx, Immediate(Smi::kZero));
2949   j(not_equal, call_runtime);
2950 
2951   bind(&start);
2952 
2953   // Check that there are no elements. Register rcx contains the current JS
2954   // object we've reached through the prototype chain.
2955   Label no_elements;
2956   mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset));
2957   cmp(ecx, isolate()->factory()->empty_fixed_array());
2958   j(equal, &no_elements);
2959 
2960   // Second chance, the object may be using the empty slow element dictionary.
2961   cmp(ecx, isolate()->factory()->empty_slow_element_dictionary());
2962   j(not_equal, call_runtime);
2963 
2964   bind(&no_elements);
2965   mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
2966   cmp(ecx, isolate()->factory()->null_value());
2967   j(not_equal, &next);
2968 }
2969 
2970 
TestJSArrayForAllocationMemento(Register receiver_reg,Register scratch_reg,Label * no_memento_found)2971 void MacroAssembler::TestJSArrayForAllocationMemento(
2972     Register receiver_reg,
2973     Register scratch_reg,
2974     Label* no_memento_found) {
2975   Label map_check;
2976   Label top_check;
2977   ExternalReference new_space_allocation_top =
2978       ExternalReference::new_space_allocation_top_address(isolate());
2979   const int kMementoMapOffset = JSArray::kSize - kHeapObjectTag;
2980   const int kMementoLastWordOffset =
2981       kMementoMapOffset + AllocationMemento::kSize - kPointerSize;
2982 
2983   // Bail out if the object is not in new space.
2984   JumpIfNotInNewSpace(receiver_reg, scratch_reg, no_memento_found);
2985   // If the object is in new space, we need to check whether it is on the same
2986   // page as the current top.
2987   lea(scratch_reg, Operand(receiver_reg, kMementoLastWordOffset));
2988   xor_(scratch_reg, Operand::StaticVariable(new_space_allocation_top));
2989   test(scratch_reg, Immediate(~Page::kPageAlignmentMask));
2990   j(zero, &top_check);
2991   // The object is on a different page than allocation top. Bail out if the
2992   // object sits on the page boundary as no memento can follow and we cannot
2993   // touch the memory following it.
2994   lea(scratch_reg, Operand(receiver_reg, kMementoLastWordOffset));
2995   xor_(scratch_reg, receiver_reg);
2996   test(scratch_reg, Immediate(~Page::kPageAlignmentMask));
2997   j(not_zero, no_memento_found);
2998   // Continue with the actual map check.
2999   jmp(&map_check);
3000   // If top is on the same page as the current object, we need to check whether
3001   // we are below top.
3002   bind(&top_check);
3003   lea(scratch_reg, Operand(receiver_reg, kMementoLastWordOffset));
3004   cmp(scratch_reg, Operand::StaticVariable(new_space_allocation_top));
3005   j(greater_equal, no_memento_found);
3006   // Memento map check.
3007   bind(&map_check);
3008   mov(scratch_reg, Operand(receiver_reg, kMementoMapOffset));
3009   cmp(scratch_reg, Immediate(isolate()->factory()->allocation_memento_map()));
3010 }
3011 
3012 
JumpIfDictionaryInPrototypeChain(Register object,Register scratch0,Register scratch1,Label * found)3013 void MacroAssembler::JumpIfDictionaryInPrototypeChain(
3014     Register object,
3015     Register scratch0,
3016     Register scratch1,
3017     Label* found) {
3018   DCHECK(!scratch1.is(scratch0));
3019   Factory* factory = isolate()->factory();
3020   Register current = scratch0;
3021   Label loop_again, end;
3022 
3023   // scratch contained elements pointer.
3024   mov(current, object);
3025   mov(current, FieldOperand(current, HeapObject::kMapOffset));
3026   mov(current, FieldOperand(current, Map::kPrototypeOffset));
3027   cmp(current, Immediate(factory->null_value()));
3028   j(equal, &end);
3029 
3030   // Loop based on the map going up the prototype chain.
3031   bind(&loop_again);
3032   mov(current, FieldOperand(current, HeapObject::kMapOffset));
3033   STATIC_ASSERT(JS_PROXY_TYPE < JS_OBJECT_TYPE);
3034   STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE);
3035   CmpInstanceType(current, JS_OBJECT_TYPE);
3036   j(below, found);
3037   mov(scratch1, FieldOperand(current, Map::kBitField2Offset));
3038   DecodeField<Map::ElementsKindBits>(scratch1);
3039   cmp(scratch1, Immediate(DICTIONARY_ELEMENTS));
3040   j(equal, found);
3041   mov(current, FieldOperand(current, Map::kPrototypeOffset));
3042   cmp(current, Immediate(factory->null_value()));
3043   j(not_equal, &loop_again);
3044 
3045   bind(&end);
3046 }
3047 
3048 
TruncatingDiv(Register dividend,int32_t divisor)3049 void MacroAssembler::TruncatingDiv(Register dividend, int32_t divisor) {
3050   DCHECK(!dividend.is(eax));
3051   DCHECK(!dividend.is(edx));
3052   base::MagicNumbersForDivision<uint32_t> mag =
3053       base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
3054   mov(eax, Immediate(mag.multiplier));
3055   imul(dividend);
3056   bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
3057   if (divisor > 0 && neg) add(edx, dividend);
3058   if (divisor < 0 && !neg && mag.multiplier > 0) sub(edx, dividend);
3059   if (mag.shift > 0) sar(edx, mag.shift);
3060   mov(eax, dividend);
3061   shr(eax, 31);
3062   add(edx, eax);
3063 }
3064 
3065 
3066 }  // namespace internal
3067 }  // namespace v8
3068 
3069 #endif  // V8_TARGET_ARCH_X87
3070