V8 Project
macro-assembler-ia32.cc
Go to the documentation of this file.
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/v8.h"
6 
7 #if V8_TARGET_ARCH_IA32
8 
9 #include "src/base/bits.h"
11 #include "src/bootstrapper.h"
12 #include "src/codegen.h"
13 #include "src/cpu-profiler.h"
14 #include "src/debug.h"
15 #include "src/isolate-inl.h"
16 #include "src/runtime/runtime.h"
17 #include "src/serialize.h"
18 
19 namespace v8 {
20 namespace internal {
21 
22 // -------------------------------------------------------------------------
23 // MacroAssembler implementation.
24 
25 MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size)
26  : Assembler(arg_isolate, buffer, size),
27  generating_stub_(false),
28  has_frame_(false) {
29  if (isolate() != NULL) {
30  // TODO(titzer): should we just use a null handle here instead?
31  code_object_ = Handle<Object>(isolate()->heap()->undefined_value(),
32  isolate());
33  }
34 }
35 
36 
37 void MacroAssembler::Load(Register dst, const Operand& src, Representation r) {
38  DCHECK(!r.IsDouble());
39  if (r.IsInteger8()) {
40  movsx_b(dst, src);
41  } else if (r.IsUInteger8()) {
42  movzx_b(dst, src);
43  } else if (r.IsInteger16()) {
44  movsx_w(dst, src);
45  } else if (r.IsUInteger16()) {
46  movzx_w(dst, src);
47  } else {
48  mov(dst, src);
49  }
50 }
51 
52 
53 void MacroAssembler::Store(Register src, const Operand& dst, Representation r) {
54  DCHECK(!r.IsDouble());
55  if (r.IsInteger8() || r.IsUInteger8()) {
56  mov_b(dst, src);
57  } else if (r.IsInteger16() || r.IsUInteger16()) {
58  mov_w(dst, src);
59  } else {
60  if (r.IsHeapObject()) {
61  AssertNotSmi(src);
62  } else if (r.IsSmi()) {
63  AssertSmi(src);
64  }
65  mov(dst, src);
66  }
67 }
68 
69 
70 void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index) {
71  if (isolate()->heap()->RootCanBeTreatedAsConstant(index)) {
72  Handle<Object> value(&isolate()->heap()->roots_array_start()[index]);
73  mov(destination, value);
74  return;
75  }
76  ExternalReference roots_array_start =
77  ExternalReference::roots_array_start(isolate());
78  mov(destination, Immediate(index));
79  mov(destination, Operand::StaticArray(destination,
81  roots_array_start));
82 }
83 
84 
85 void MacroAssembler::StoreRoot(Register source,
86  Register scratch,
87  Heap::RootListIndex index) {
88  DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
89  ExternalReference roots_array_start =
90  ExternalReference::roots_array_start(isolate());
91  mov(scratch, Immediate(index));
92  mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start),
93  source);
94 }
95 
96 
97 void MacroAssembler::CompareRoot(Register with,
98  Register scratch,
99  Heap::RootListIndex index) {
100  ExternalReference roots_array_start =
101  ExternalReference::roots_array_start(isolate());
102  mov(scratch, Immediate(index));
103  cmp(with, Operand::StaticArray(scratch,
105  roots_array_start));
106 }
107 
108 
109 void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) {
110  DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index));
111  Handle<Object> value(&isolate()->heap()->roots_array_start()[index]);
112  cmp(with, value);
113 }
114 
115 
116 void MacroAssembler::CompareRoot(const Operand& with,
117  Heap::RootListIndex index) {
118  DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index));
119  Handle<Object> value(&isolate()->heap()->roots_array_start()[index]);
120  cmp(with, value);
121 }
122 
123 
124 void MacroAssembler::InNewSpace(
125  Register object,
126  Register scratch,
127  Condition cc,
128  Label* condition_met,
129  Label::Distance condition_met_distance) {
130  DCHECK(cc == equal || cc == not_equal);
131  if (scratch.is(object)) {
132  and_(scratch, Immediate(~Page::kPageAlignmentMask));
133  } else {
134  mov(scratch, Immediate(~Page::kPageAlignmentMask));
135  and_(scratch, object);
136  }
137  // Check that we can use a test_b.
138  DCHECK(MemoryChunk::IN_FROM_SPACE < 8);
139  DCHECK(MemoryChunk::IN_TO_SPACE < 8);
140  int mask = (1 << MemoryChunk::IN_FROM_SPACE)
141  | (1 << MemoryChunk::IN_TO_SPACE);
142  // If non-zero, the page belongs to new-space.
143  test_b(Operand(scratch, MemoryChunk::kFlagsOffset),
144  static_cast<uint8_t>(mask));
145  j(cc, condition_met, condition_met_distance);
146 }
147 
148 
149 void MacroAssembler::RememberedSetHelper(
150  Register object, // Only used for debug checks.
151  Register addr,
152  Register scratch,
153  SaveFPRegsMode save_fp,
154  MacroAssembler::RememberedSetFinalAction and_then) {
155  Label done;
156  if (emit_debug_code()) {
157  Label ok;
158  JumpIfNotInNewSpace(object, scratch, &ok, Label::kNear);
159  int3();
160  bind(&ok);
161  }
162  // Load store buffer top.
163  ExternalReference store_buffer =
164  ExternalReference::store_buffer_top(isolate());
165  mov(scratch, Operand::StaticVariable(store_buffer));
166  // Store pointer to buffer.
167  mov(Operand(scratch, 0), addr);
168  // Increment buffer top.
169  add(scratch, Immediate(kPointerSize));
170  // Write back new top of buffer.
171  mov(Operand::StaticVariable(store_buffer), scratch);
172  // Call stub on end of buffer.
173  // Check for end of buffer.
174  test(scratch, Immediate(StoreBuffer::kStoreBufferOverflowBit));
175  if (and_then == kReturnAtEnd) {
176  Label buffer_overflowed;
177  j(not_equal, &buffer_overflowed, Label::kNear);
178  ret(0);
179  bind(&buffer_overflowed);
180  } else {
181  DCHECK(and_then == kFallThroughAtEnd);
182  j(equal, &done, Label::kNear);
183  }
184  StoreBufferOverflowStub store_buffer_overflow(isolate(), save_fp);
185  CallStub(&store_buffer_overflow);
186  if (and_then == kReturnAtEnd) {
187  ret(0);
188  } else {
189  DCHECK(and_then == kFallThroughAtEnd);
190  bind(&done);
191  }
192 }
193 
194 
195 void MacroAssembler::ClampDoubleToUint8(XMMRegister input_reg,
196  XMMRegister scratch_reg,
197  Register result_reg) {
198  Label done;
199  Label conv_failure;
200  xorps(scratch_reg, scratch_reg);
201  cvtsd2si(result_reg, input_reg);
202  test(result_reg, Immediate(0xFFFFFF00));
203  j(zero, &done, Label::kNear);
204  cmp(result_reg, Immediate(0x1));
205  j(overflow, &conv_failure, Label::kNear);
206  mov(result_reg, Immediate(0));
207  setcc(sign, result_reg);
208  sub(result_reg, Immediate(1));
209  and_(result_reg, Immediate(255));
210  jmp(&done, Label::kNear);
211  bind(&conv_failure);
212  Move(result_reg, Immediate(0));
213  ucomisd(input_reg, scratch_reg);
214  j(below, &done, Label::kNear);
215  Move(result_reg, Immediate(255));
216  bind(&done);
217 }
218 
219 
220 void MacroAssembler::ClampUint8(Register reg) {
221  Label done;
222  test(reg, Immediate(0xFFFFFF00));
223  j(zero, &done, Label::kNear);
224  setcc(negative, reg); // 1 if negative, 0 if positive.
225  dec_b(reg); // 0 if negative, 255 if positive.
226  bind(&done);
227 }
228 
229 
230 void MacroAssembler::SlowTruncateToI(Register result_reg,
231  Register input_reg,
232  int offset) {
233  DoubleToIStub stub(isolate(), input_reg, result_reg, offset, true);
234  call(stub.GetCode(), RelocInfo::CODE_TARGET);
235 }
236 
237 
238 void MacroAssembler::TruncateDoubleToI(Register result_reg,
239  XMMRegister input_reg) {
240  Label done;
241  cvttsd2si(result_reg, Operand(input_reg));
242  cmp(result_reg, 0x1);
243  j(no_overflow, &done, Label::kNear);
244 
245  sub(esp, Immediate(kDoubleSize));
246  movsd(MemOperand(esp, 0), input_reg);
247  SlowTruncateToI(result_reg, esp, 0);
248  add(esp, Immediate(kDoubleSize));
249  bind(&done);
250 }
251 
252 
253 void MacroAssembler::DoubleToI(Register result_reg, XMMRegister input_reg,
254  XMMRegister scratch,
255  MinusZeroMode minus_zero_mode,
256  Label* lost_precision, Label* is_nan,
257  Label* minus_zero, Label::Distance dst) {
258  DCHECK(!input_reg.is(scratch));
259  cvttsd2si(result_reg, Operand(input_reg));
260  Cvtsi2sd(scratch, Operand(result_reg));
261  ucomisd(scratch, input_reg);
262  j(not_equal, lost_precision, dst);
263  j(parity_even, is_nan, dst);
264  if (minus_zero_mode == FAIL_ON_MINUS_ZERO) {
265  Label done;
266  // The integer converted back is equal to the original. We
267  // only have to test if we got -0 as an input.
268  test(result_reg, Operand(result_reg));
269  j(not_zero, &done, Label::kNear);
270  movmskpd(result_reg, input_reg);
271  // Bit 0 contains the sign of the double in input_reg.
272  // If input was positive, we are ok and return 0, otherwise
273  // jump to minus_zero.
274  and_(result_reg, 1);
275  j(not_zero, minus_zero, dst);
276  bind(&done);
277  }
278 }
279 
280 
281 void MacroAssembler::TruncateHeapNumberToI(Register result_reg,
282  Register input_reg) {
283  Label done, slow_case;
284 
285  if (CpuFeatures::IsSupported(SSE3)) {
286  CpuFeatureScope scope(this, SSE3);
287  Label convert;
288  // Use more powerful conversion when sse3 is available.
289  // Load x87 register with heap number.
290  fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
291  // Get exponent alone and check for too-big exponent.
292  mov(result_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
293  and_(result_reg, HeapNumber::kExponentMask);
294  const uint32_t kTooBigExponent =
295  (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
296  cmp(Operand(result_reg), Immediate(kTooBigExponent));
297  j(greater_equal, &slow_case, Label::kNear);
298 
299  // Reserve space for 64 bit answer.
300  sub(Operand(esp), Immediate(kDoubleSize));
301  // Do conversion, which cannot fail because we checked the exponent.
302  fisttp_d(Operand(esp, 0));
303  mov(result_reg, Operand(esp, 0)); // Low word of answer is the result.
304  add(Operand(esp), Immediate(kDoubleSize));
305  jmp(&done, Label::kNear);
306 
307  // Slow case.
308  bind(&slow_case);
309  if (input_reg.is(result_reg)) {
310  // Input is clobbered. Restore number from fpu stack
311  sub(Operand(esp), Immediate(kDoubleSize));
312  fstp_d(Operand(esp, 0));
313  SlowTruncateToI(result_reg, esp, 0);
314  add(esp, Immediate(kDoubleSize));
315  } else {
316  fstp(0);
317  SlowTruncateToI(result_reg, input_reg);
318  }
319  } else {
320  movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
321  cvttsd2si(result_reg, Operand(xmm0));
322  cmp(result_reg, 0x1);
323  j(no_overflow, &done, Label::kNear);
324  // Check if the input was 0x8000000 (kMinInt).
325  // If no, then we got an overflow and we deoptimize.
326  ExternalReference min_int = ExternalReference::address_of_min_int();
327  ucomisd(xmm0, Operand::StaticVariable(min_int));
328  j(not_equal, &slow_case, Label::kNear);
329  j(parity_even, &slow_case, Label::kNear); // NaN.
330  jmp(&done, Label::kNear);
331 
332  // Slow case.
333  bind(&slow_case);
334  if (input_reg.is(result_reg)) {
335  // Input is clobbered. Restore number from double scratch.
336  sub(esp, Immediate(kDoubleSize));
337  movsd(MemOperand(esp, 0), xmm0);
338  SlowTruncateToI(result_reg, esp, 0);
339  add(esp, Immediate(kDoubleSize));
340  } else {
341  SlowTruncateToI(result_reg, input_reg);
342  }
343  }
344  bind(&done);
345 }
346 
347 
348 void MacroAssembler::LoadUint32(XMMRegister dst,
349  Register src) {
350  Label done;
351  cmp(src, Immediate(0));
352  ExternalReference uint32_bias =
353  ExternalReference::address_of_uint32_bias();
354  Cvtsi2sd(dst, src);
355  j(not_sign, &done, Label::kNear);
356  addsd(dst, Operand::StaticVariable(uint32_bias));
357  bind(&done);
358 }
359 
360 
361 void MacroAssembler::RecordWriteArray(
362  Register object,
363  Register value,
364  Register index,
365  SaveFPRegsMode save_fp,
366  RememberedSetAction remembered_set_action,
367  SmiCheck smi_check,
368  PointersToHereCheck pointers_to_here_check_for_value) {
369  // First, check if a write barrier is even needed. The tests below
370  // catch stores of Smis.
371  Label done;
372 
373  // Skip barrier if writing a smi.
374  if (smi_check == INLINE_SMI_CHECK) {
375  DCHECK_EQ(0, kSmiTag);
376  test(value, Immediate(kSmiTagMask));
377  j(zero, &done);
378  }
379 
380  // Array access: calculate the destination address in the same manner as
381  // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset
382  // into an array of words.
383  Register dst = index;
384  lea(dst, Operand(object, index, times_half_pointer_size,
385  FixedArray::kHeaderSize - kHeapObjectTag));
386 
387  RecordWrite(object, dst, value, save_fp, remembered_set_action,
388  OMIT_SMI_CHECK, pointers_to_here_check_for_value);
389 
390  bind(&done);
391 
392  // Clobber clobbered input registers when running with the debug-code flag
393  // turned on to provoke errors.
394  if (emit_debug_code()) {
395  mov(value, Immediate(bit_cast<int32_t>(kZapValue)));
396  mov(index, Immediate(bit_cast<int32_t>(kZapValue)));
397  }
398 }
399 
400 
401 void MacroAssembler::RecordWriteField(
402  Register object,
403  int offset,
404  Register value,
405  Register dst,
406  SaveFPRegsMode save_fp,
407  RememberedSetAction remembered_set_action,
408  SmiCheck smi_check,
409  PointersToHereCheck pointers_to_here_check_for_value) {
410  // First, check if a write barrier is even needed. The tests below
411  // catch stores of Smis.
412  Label done;
413 
414  // Skip barrier if writing a smi.
415  if (smi_check == INLINE_SMI_CHECK) {
416  JumpIfSmi(value, &done, Label::kNear);
417  }
418 
419  // Although the object register is tagged, the offset is relative to the start
420  // of the object, so so offset must be a multiple of kPointerSize.
421  DCHECK(IsAligned(offset, kPointerSize));
422 
423  lea(dst, FieldOperand(object, offset));
424  if (emit_debug_code()) {
425  Label ok;
426  test_b(dst, (1 << kPointerSizeLog2) - 1);
427  j(zero, &ok, Label::kNear);
428  int3();
429  bind(&ok);
430  }
431 
432  RecordWrite(object, dst, value, save_fp, remembered_set_action,
433  OMIT_SMI_CHECK, pointers_to_here_check_for_value);
434 
435  bind(&done);
436 
437  // Clobber clobbered input registers when running with the debug-code flag
438  // turned on to provoke errors.
439  if (emit_debug_code()) {
440  mov(value, Immediate(bit_cast<int32_t>(kZapValue)));
441  mov(dst, Immediate(bit_cast<int32_t>(kZapValue)));
442  }
443 }
444 
445 
446 void MacroAssembler::RecordWriteForMap(
447  Register object,
448  Handle<Map> map,
449  Register scratch1,
450  Register scratch2,
451  SaveFPRegsMode save_fp) {
452  Label done;
453 
454  Register address = scratch1;
455  Register value = scratch2;
456  if (emit_debug_code()) {
457  Label ok;
458  lea(address, FieldOperand(object, HeapObject::kMapOffset));
459  test_b(address, (1 << kPointerSizeLog2) - 1);
460  j(zero, &ok, Label::kNear);
461  int3();
462  bind(&ok);
463  }
464 
465  DCHECK(!object.is(value));
466  DCHECK(!object.is(address));
467  DCHECK(!value.is(address));
468  AssertNotSmi(object);
469 
470  if (!FLAG_incremental_marking) {
471  return;
472  }
473 
474  // Compute the address.
475  lea(address, FieldOperand(object, HeapObject::kMapOffset));
476 
477  // A single check of the map's pages interesting flag suffices, since it is
478  // only set during incremental collection, and then it's also guaranteed that
479  // the from object's page's interesting flag is also set. This optimization
480  // relies on the fact that maps can never be in new space.
481  DCHECK(!isolate()->heap()->InNewSpace(*map));
482  CheckPageFlagForMap(map,
483  MemoryChunk::kPointersToHereAreInterestingMask,
484  zero,
485  &done,
486  Label::kNear);
487 
488  RecordWriteStub stub(isolate(), object, value, address, OMIT_REMEMBERED_SET,
489  save_fp);
490  CallStub(&stub);
491 
492  bind(&done);
493 
494  // Count number of write barriers in generated code.
495  isolate()->counters()->write_barriers_static()->Increment();
496  IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1);
497 
498  // Clobber clobbered input registers when running with the debug-code flag
499  // turned on to provoke errors.
500  if (emit_debug_code()) {
501  mov(value, Immediate(bit_cast<int32_t>(kZapValue)));
502  mov(scratch1, Immediate(bit_cast<int32_t>(kZapValue)));
503  mov(scratch2, Immediate(bit_cast<int32_t>(kZapValue)));
504  }
505 }
506 
507 
508 void MacroAssembler::RecordWrite(
509  Register object,
510  Register address,
511  Register value,
512  SaveFPRegsMode fp_mode,
513  RememberedSetAction remembered_set_action,
514  SmiCheck smi_check,
515  PointersToHereCheck pointers_to_here_check_for_value) {
516  DCHECK(!object.is(value));
517  DCHECK(!object.is(address));
518  DCHECK(!value.is(address));
519  AssertNotSmi(object);
520 
521  if (remembered_set_action == OMIT_REMEMBERED_SET &&
522  !FLAG_incremental_marking) {
523  return;
524  }
525 
526  if (emit_debug_code()) {
527  Label ok;
528  cmp(value, Operand(address, 0));
529  j(equal, &ok, Label::kNear);
530  int3();
531  bind(&ok);
532  }
533 
534  // First, check if a write barrier is even needed. The tests below
535  // catch stores of Smis and stores into young gen.
536  Label done;
537 
538  if (smi_check == INLINE_SMI_CHECK) {
539  // Skip barrier if writing a smi.
540  JumpIfSmi(value, &done, Label::kNear);
541  }
542 
543  if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) {
544  CheckPageFlag(value,
545  value, // Used as scratch.
546  MemoryChunk::kPointersToHereAreInterestingMask,
547  zero,
548  &done,
549  Label::kNear);
550  }
551  CheckPageFlag(object,
552  value, // Used as scratch.
553  MemoryChunk::kPointersFromHereAreInterestingMask,
554  zero,
555  &done,
556  Label::kNear);
557 
558  RecordWriteStub stub(isolate(), object, value, address, remembered_set_action,
559  fp_mode);
560  CallStub(&stub);
561 
562  bind(&done);
563 
564  // Count number of write barriers in generated code.
565  isolate()->counters()->write_barriers_static()->Increment();
566  IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1);
567 
568  // Clobber clobbered registers when running with the debug-code flag
569  // turned on to provoke errors.
570  if (emit_debug_code()) {
571  mov(address, Immediate(bit_cast<int32_t>(kZapValue)));
572  mov(value, Immediate(bit_cast<int32_t>(kZapValue)));
573  }
574 }
575 
576 
577 void MacroAssembler::DebugBreak() {
578  Move(eax, Immediate(0));
579  mov(ebx, Immediate(ExternalReference(Runtime::kDebugBreak, isolate())));
580  CEntryStub ces(isolate(), 1);
581  call(ces.GetCode(), RelocInfo::DEBUG_BREAK);
582 }
583 
584 
585 void MacroAssembler::Cvtsi2sd(XMMRegister dst, const Operand& src) {
586  xorps(dst, dst);
587  cvtsi2sd(dst, src);
588 }
589 
590 
591 bool MacroAssembler::IsUnsafeImmediate(const Immediate& x) {
592  static const int kMaxImmediateBits = 17;
593  if (!RelocInfo::IsNone(x.rmode_)) return false;
594  return !is_intn(x.x_, kMaxImmediateBits);
595 }
596 
597 
598 void MacroAssembler::SafeMove(Register dst, const Immediate& x) {
599  if (IsUnsafeImmediate(x) && jit_cookie() != 0) {
600  Move(dst, Immediate(x.x_ ^ jit_cookie()));
601  xor_(dst, jit_cookie());
602  } else {
603  Move(dst, x);
604  }
605 }
606 
607 
608 void MacroAssembler::SafePush(const Immediate& x) {
609  if (IsUnsafeImmediate(x) && jit_cookie() != 0) {
610  push(Immediate(x.x_ ^ jit_cookie()));
611  xor_(Operand(esp, 0), Immediate(jit_cookie()));
612  } else {
613  push(x);
614  }
615 }
616 
617 
618 void MacroAssembler::CmpObjectType(Register heap_object,
619  InstanceType type,
620  Register map) {
621  mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
622  CmpInstanceType(map, type);
623 }
624 
625 
626 void MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
627  cmpb(FieldOperand(map, Map::kInstanceTypeOffset),
628  static_cast<int8_t>(type));
629 }
630 
631 
632 void MacroAssembler::CheckFastElements(Register map,
633  Label* fail,
634  Label::Distance distance) {
639  cmpb(FieldOperand(map, Map::kBitField2Offset),
640  Map::kMaximumBitField2FastHoleyElementValue);
641  j(above, fail, distance);
642 }
643 
644 
645 void MacroAssembler::CheckFastObjectElements(Register map,
646  Label* fail,
647  Label::Distance distance) {
652  cmpb(FieldOperand(map, Map::kBitField2Offset),
653  Map::kMaximumBitField2FastHoleySmiElementValue);
654  j(below_equal, fail, distance);
655  cmpb(FieldOperand(map, Map::kBitField2Offset),
656  Map::kMaximumBitField2FastHoleyElementValue);
657  j(above, fail, distance);
658 }
659 
660 
661 void MacroAssembler::CheckFastSmiElements(Register map,
662  Label* fail,
663  Label::Distance distance) {
666  cmpb(FieldOperand(map, Map::kBitField2Offset),
667  Map::kMaximumBitField2FastHoleySmiElementValue);
668  j(above, fail, distance);
669 }
670 
671 
672 void MacroAssembler::StoreNumberToDoubleElements(
673  Register maybe_number,
674  Register elements,
675  Register key,
676  Register scratch1,
677  XMMRegister scratch2,
678  Label* fail,
679  int elements_offset) {
680  Label smi_value, done, maybe_nan, not_nan, is_nan, have_double_value;
681  JumpIfSmi(maybe_number, &smi_value, Label::kNear);
682 
683  CheckMap(maybe_number,
684  isolate()->factory()->heap_number_map(),
685  fail,
687 
688  // Double value, canonicalize NaN.
689  uint32_t offset = HeapNumber::kValueOffset + sizeof(kHoleNanLower32);
690  cmp(FieldOperand(maybe_number, offset),
692  j(greater_equal, &maybe_nan, Label::kNear);
693 
694  bind(&not_nan);
695  ExternalReference canonical_nan_reference =
696  ExternalReference::address_of_canonical_non_hole_nan();
697  movsd(scratch2, FieldOperand(maybe_number, HeapNumber::kValueOffset));
698  bind(&have_double_value);
699  movsd(FieldOperand(elements, key, times_4,
700  FixedDoubleArray::kHeaderSize - elements_offset),
701  scratch2);
702  jmp(&done);
703 
704  bind(&maybe_nan);
705  // Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise
706  // it's an Infinity, and the non-NaN code path applies.
707  j(greater, &is_nan, Label::kNear);
708  cmp(FieldOperand(maybe_number, HeapNumber::kValueOffset), Immediate(0));
709  j(zero, &not_nan);
710  bind(&is_nan);
711  movsd(scratch2, Operand::StaticVariable(canonical_nan_reference));
712  jmp(&have_double_value, Label::kNear);
713 
714  bind(&smi_value);
715  // Value is a smi. Convert to a double and store.
716  // Preserve original value.
717  mov(scratch1, maybe_number);
718  SmiUntag(scratch1);
719  Cvtsi2sd(scratch2, scratch1);
720  movsd(FieldOperand(elements, key, times_4,
721  FixedDoubleArray::kHeaderSize - elements_offset),
722  scratch2);
723  bind(&done);
724 }
725 
726 
727 void MacroAssembler::CompareMap(Register obj, Handle<Map> map) {
728  cmp(FieldOperand(obj, HeapObject::kMapOffset), map);
729 }
730 
731 
732 void MacroAssembler::CheckMap(Register obj,
733  Handle<Map> map,
734  Label* fail,
735  SmiCheckType smi_check_type) {
736  if (smi_check_type == DO_SMI_CHECK) {
737  JumpIfSmi(obj, fail);
738  }
739 
740  CompareMap(obj, map);
741  j(not_equal, fail);
742 }
743 
744 
745 void MacroAssembler::DispatchMap(Register obj,
746  Register unused,
747  Handle<Map> map,
748  Handle<Code> success,
749  SmiCheckType smi_check_type) {
750  Label fail;
751  if (smi_check_type == DO_SMI_CHECK) {
752  JumpIfSmi(obj, &fail);
753  }
754  cmp(FieldOperand(obj, HeapObject::kMapOffset), Immediate(map));
755  j(equal, success);
756 
757  bind(&fail);
758 }
759 
760 
761 Condition MacroAssembler::IsObjectStringType(Register heap_object,
762  Register map,
763  Register instance_type) {
764  mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
765  movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
767  test(instance_type, Immediate(kIsNotStringMask));
768  return zero;
769 }
770 
771 
772 Condition MacroAssembler::IsObjectNameType(Register heap_object,
773  Register map,
774  Register instance_type) {
775  mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
776  movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
777  cmpb(instance_type, static_cast<uint8_t>(LAST_NAME_TYPE));
778  return below_equal;
779 }
780 
781 
782 void MacroAssembler::IsObjectJSObjectType(Register heap_object,
783  Register map,
784  Register scratch,
785  Label* fail) {
786  mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
787  IsInstanceJSObjectType(map, scratch, fail);
788 }
789 
790 
791 void MacroAssembler::IsInstanceJSObjectType(Register map,
792  Register scratch,
793  Label* fail) {
794  movzx_b(scratch, FieldOperand(map, Map::kInstanceTypeOffset));
795  sub(scratch, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
796  cmp(scratch,
798  j(above, fail);
799 }
800 
801 
802 void MacroAssembler::FCmp() {
803  fucomip();
804  fstp(0);
805 }
806 
807 
808 void MacroAssembler::AssertNumber(Register object) {
809  if (emit_debug_code()) {
810  Label ok;
811  JumpIfSmi(object, &ok);
812  cmp(FieldOperand(object, HeapObject::kMapOffset),
813  isolate()->factory()->heap_number_map());
814  Check(equal, kOperandNotANumber);
815  bind(&ok);
816  }
817 }
818 
819 
820 void MacroAssembler::AssertSmi(Register object) {
821  if (emit_debug_code()) {
822  test(object, Immediate(kSmiTagMask));
823  Check(equal, kOperandIsNotASmi);
824  }
825 }
826 
827 
828 void MacroAssembler::AssertString(Register object) {
829  if (emit_debug_code()) {
830  test(object, Immediate(kSmiTagMask));
831  Check(not_equal, kOperandIsASmiAndNotAString);
832  push(object);
833  mov(object, FieldOperand(object, HeapObject::kMapOffset));
834  CmpInstanceType(object, FIRST_NONSTRING_TYPE);
835  pop(object);
836  Check(below, kOperandIsNotAString);
837  }
838 }
839 
840 
841 void MacroAssembler::AssertName(Register object) {
842  if (emit_debug_code()) {
843  test(object, Immediate(kSmiTagMask));
844  Check(not_equal, kOperandIsASmiAndNotAName);
845  push(object);
846  mov(object, FieldOperand(object, HeapObject::kMapOffset));
847  CmpInstanceType(object, LAST_NAME_TYPE);
848  pop(object);
849  Check(below_equal, kOperandIsNotAName);
850  }
851 }
852 
853 
854 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object) {
855  if (emit_debug_code()) {
856  Label done_checking;
857  AssertNotSmi(object);
858  cmp(object, isolate()->factory()->undefined_value());
859  j(equal, &done_checking);
860  cmp(FieldOperand(object, 0),
861  Immediate(isolate()->factory()->allocation_site_map()));
862  Assert(equal, kExpectedUndefinedOrCell);
863  bind(&done_checking);
864  }
865 }
866 
867 
868 void MacroAssembler::AssertNotSmi(Register object) {
869  if (emit_debug_code()) {
870  test(object, Immediate(kSmiTagMask));
871  Check(not_equal, kOperandIsASmi);
872  }
873 }
874 
875 
876 void MacroAssembler::StubPrologue() {
877  push(ebp); // Caller's frame pointer.
878  mov(ebp, esp);
879  push(esi); // Callee's context.
880  push(Immediate(Smi::FromInt(StackFrame::STUB)));
881 }
882 
883 
884 void MacroAssembler::Prologue(bool code_pre_aging) {
885  PredictableCodeSizeScope predictible_code_size_scope(this,
887  if (code_pre_aging) {
888  // Pre-age the code.
889  call(isolate()->builtins()->MarkCodeAsExecutedOnce(),
890  RelocInfo::CODE_AGE_SEQUENCE);
891  Nop(kNoCodeAgeSequenceLength - Assembler::kCallInstructionLength);
892  } else {
893  push(ebp); // Caller's frame pointer.
894  mov(ebp, esp);
895  push(esi); // Callee's context.
896  push(edi); // Callee's JS function.
897  }
898 }
899 
900 
901 void MacroAssembler::EnterFrame(StackFrame::Type type) {
902  push(ebp);
903  mov(ebp, esp);
904  push(esi);
905  push(Immediate(Smi::FromInt(type)));
906  push(Immediate(CodeObject()));
907  if (emit_debug_code()) {
908  cmp(Operand(esp, 0), Immediate(isolate()->factory()->undefined_value()));
909  Check(not_equal, kCodeObjectNotProperlyPatched);
910  }
911 }
912 
913 
914 void MacroAssembler::LeaveFrame(StackFrame::Type type) {
915  if (emit_debug_code()) {
916  cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset),
917  Immediate(Smi::FromInt(type)));
918  Check(equal, kStackFrameTypesMustMatch);
919  }
920  leave();
921 }
922 
923 
924 void MacroAssembler::EnterExitFramePrologue() {
925  // Set up the frame structure on the stack.
926  DCHECK(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize);
927  DCHECK(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize);
928  DCHECK(ExitFrameConstants::kCallerFPOffset == 0 * kPointerSize);
929  push(ebp);
930  mov(ebp, esp);
931 
932  // Reserve room for entry stack pointer and push the code object.
933  DCHECK(ExitFrameConstants::kSPOffset == -1 * kPointerSize);
934  push(Immediate(0)); // Saved entry sp, patched before call.
935  push(Immediate(CodeObject())); // Accessed from ExitFrame::code_slot.
936 
937  // Save the frame pointer and the context in top.
938  ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress, isolate());
939  ExternalReference context_address(Isolate::kContextAddress, isolate());
940  mov(Operand::StaticVariable(c_entry_fp_address), ebp);
941  mov(Operand::StaticVariable(context_address), esi);
942 }
943 
944 
945 void MacroAssembler::EnterExitFrameEpilogue(int argc, bool save_doubles) {
946  // Optionally save all XMM registers.
947  if (save_doubles) {
948  int space = XMMRegister::kMaxNumRegisters * kDoubleSize +
949  argc * kPointerSize;
950  sub(esp, Immediate(space));
951  const int offset = -2 * kPointerSize;
952  for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
953  XMMRegister reg = XMMRegister::from_code(i);
954  movsd(Operand(ebp, offset - ((i + 1) * kDoubleSize)), reg);
955  }
956  } else {
957  sub(esp, Immediate(argc * kPointerSize));
958  }
959 
960  // Get the required frame alignment for the OS.
961  const int kFrameAlignment = base::OS::ActivationFrameAlignment();
962  if (kFrameAlignment > 0) {
963  DCHECK(base::bits::IsPowerOfTwo32(kFrameAlignment));
964  and_(esp, -kFrameAlignment);
965  }
966 
967  // Patch the saved entry sp.
968  mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp);
969 }
970 
971 
972 void MacroAssembler::EnterExitFrame(bool save_doubles) {
973  EnterExitFramePrologue();
974 
975  // Set up argc and argv in callee-saved registers.
976  int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
977  mov(edi, eax);
978  lea(esi, Operand(ebp, eax, times_4, offset));
979 
980  // Reserve space for argc, argv and isolate.
981  EnterExitFrameEpilogue(3, save_doubles);
982 }
983 
984 
985 void MacroAssembler::EnterApiExitFrame(int argc) {
986  EnterExitFramePrologue();
987  EnterExitFrameEpilogue(argc, false);
988 }
989 
990 
991 void MacroAssembler::LeaveExitFrame(bool save_doubles) {
992  // Optionally restore all XMM registers.
993  if (save_doubles) {
994  const int offset = -2 * kPointerSize;
995  for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
996  XMMRegister reg = XMMRegister::from_code(i);
997  movsd(reg, Operand(ebp, offset - ((i + 1) * kDoubleSize)));
998  }
999  }
1000 
1001  // Get the return address from the stack and restore the frame pointer.
1002  mov(ecx, Operand(ebp, 1 * kPointerSize));
1003  mov(ebp, Operand(ebp, 0 * kPointerSize));
1004 
1005  // Pop the arguments and the receiver from the caller stack.
1006  lea(esp, Operand(esi, 1 * kPointerSize));
1007 
1008  // Push the return address to get ready to return.
1009  push(ecx);
1010 
1011  LeaveExitFrameEpilogue(true);
1012 }
1013 
1014 
1015 void MacroAssembler::LeaveExitFrameEpilogue(bool restore_context) {
1016  // Restore current context from top and clear it in debug mode.
1017  ExternalReference context_address(Isolate::kContextAddress, isolate());
1018  if (restore_context) {
1019  mov(esi, Operand::StaticVariable(context_address));
1020  }
1021 #ifdef DEBUG
1022  mov(Operand::StaticVariable(context_address), Immediate(0));
1023 #endif
1024 
1025  // Clear the top frame.
1026  ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress,
1027  isolate());
1028  mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0));
1029 }
1030 
1031 
1032 void MacroAssembler::LeaveApiExitFrame(bool restore_context) {
1033  mov(esp, ebp);
1034  pop(ebp);
1035 
1036  LeaveExitFrameEpilogue(restore_context);
1037 }
1038 
1039 
1040 void MacroAssembler::PushTryHandler(StackHandler::Kind kind,
1041  int handler_index) {
1042  // Adjust this code if not the case.
1043  STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
1044  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
1045  STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
1046  STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
1047  STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
1048  STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
1049 
1050  // We will build up the handler from the bottom by pushing on the stack.
1051  // First push the frame pointer and context.
1052  if (kind == StackHandler::JS_ENTRY) {
1053  // The frame pointer does not point to a JS frame so we save NULL for
1054  // ebp. We expect the code throwing an exception to check ebp before
1055  // dereferencing it to restore the context.
1056  push(Immediate(0)); // NULL frame pointer.
1057  push(Immediate(Smi::FromInt(0))); // No context.
1058  } else {
1059  push(ebp);
1060  push(esi);
1061  }
1062  // Push the state and the code object.
1063  unsigned state =
1064  StackHandler::IndexField::encode(handler_index) |
1065  StackHandler::KindField::encode(kind);
1066  push(Immediate(state));
1067  Push(CodeObject());
1068 
1069  // Link the current handler as the next handler.
1070  ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
1071  push(Operand::StaticVariable(handler_address));
1072  // Set this new handler as the current one.
1073  mov(Operand::StaticVariable(handler_address), esp);
1074 }
1075 
1076 
1077 void MacroAssembler::PopTryHandler() {
1078  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
1079  ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
1080  pop(Operand::StaticVariable(handler_address));
1081  add(esp, Immediate(StackHandlerConstants::kSize - kPointerSize));
1082 }
1083 
1084 
1085 void MacroAssembler::JumpToHandlerEntry() {
1086  // Compute the handler entry address and jump to it. The handler table is
1087  // a fixed array of (smi-tagged) code offsets.
1088  // eax = exception, edi = code object, edx = state.
1089  mov(ebx, FieldOperand(edi, Code::kHandlerTableOffset));
1090  shr(edx, StackHandler::kKindWidth);
1091  mov(edx, FieldOperand(ebx, edx, times_4, FixedArray::kHeaderSize));
1092  SmiUntag(edx);
1093  lea(edi, FieldOperand(edi, edx, times_1, Code::kHeaderSize));
1094  jmp(edi);
1095 }
1096 
1097 
1098 void MacroAssembler::Throw(Register value) {
1099  // Adjust this code if not the case.
1100  STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
1101  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
1102  STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
1103  STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
1104  STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
1105  STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
1106 
1107  // The exception is expected in eax.
1108  if (!value.is(eax)) {
1109  mov(eax, value);
1110  }
1111  // Drop the stack pointer to the top of the top handler.
1112  ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
1113  mov(esp, Operand::StaticVariable(handler_address));
1114  // Restore the next handler.
1115  pop(Operand::StaticVariable(handler_address));
1116 
1117  // Remove the code object and state, compute the handler address in edi.
1118  pop(edi); // Code object.
1119  pop(edx); // Index and state.
1120 
1121  // Restore the context and frame pointer.
1122  pop(esi); // Context.
1123  pop(ebp); // Frame pointer.
1124 
1125  // If the handler is a JS frame, restore the context to the frame.
1126  // (kind == ENTRY) == (ebp == 0) == (esi == 0), so we could test either
1127  // ebp or esi.
1128  Label skip;
1129  test(esi, esi);
1130  j(zero, &skip, Label::kNear);
1131  mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
1132  bind(&skip);
1133 
1134  JumpToHandlerEntry();
1135 }
1136 
1137 
1138 void MacroAssembler::ThrowUncatchable(Register value) {
1139  // Adjust this code if not the case.
1140  STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
1141  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
1142  STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
1143  STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
1144  STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
1145  STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
1146 
1147  // The exception is expected in eax.
1148  if (!value.is(eax)) {
1149  mov(eax, value);
1150  }
1151  // Drop the stack pointer to the top of the top stack handler.
1152  ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
1153  mov(esp, Operand::StaticVariable(handler_address));
1154 
1155  // Unwind the handlers until the top ENTRY handler is found.
1156  Label fetch_next, check_kind;
1157  jmp(&check_kind, Label::kNear);
1158  bind(&fetch_next);
1159  mov(esp, Operand(esp, StackHandlerConstants::kNextOffset));
1160 
1161  bind(&check_kind);
1162  STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
1163  test(Operand(esp, StackHandlerConstants::kStateOffset),
1164  Immediate(StackHandler::KindField::kMask));
1165  j(not_zero, &fetch_next);
1166 
1167  // Set the top handler address to next handler past the top ENTRY handler.
1168  pop(Operand::StaticVariable(handler_address));
1169 
1170  // Remove the code object and state, compute the handler address in edi.
1171  pop(edi); // Code object.
1172  pop(edx); // Index and state.
1173 
1174  // Clear the context pointer and frame pointer (0 was saved in the handler).
1175  pop(esi);
1176  pop(ebp);
1177 
1178  JumpToHandlerEntry();
1179 }
1180 
1181 
1182 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
1183  Register scratch1,
1184  Register scratch2,
1185  Label* miss) {
1186  Label same_contexts;
1187 
1188  DCHECK(!holder_reg.is(scratch1));
1189  DCHECK(!holder_reg.is(scratch2));
1190  DCHECK(!scratch1.is(scratch2));
1191 
1192  // Load current lexical context from the stack frame.
1193  mov(scratch1, Operand(ebp, StandardFrameConstants::kContextOffset));
1194 
1195  // When generating debug code, make sure the lexical context is set.
1196  if (emit_debug_code()) {
1197  cmp(scratch1, Immediate(0));
1198  Check(not_equal, kWeShouldNotHaveAnEmptyLexicalContext);
1199  }
1200  // Load the native context of the current context.
1201  int offset =
1202  Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
1203  mov(scratch1, FieldOperand(scratch1, offset));
1204  mov(scratch1, FieldOperand(scratch1, GlobalObject::kNativeContextOffset));
1205 
1206  // Check the context is a native context.
1207  if (emit_debug_code()) {
1208  // Read the first word and compare to native_context_map.
1209  cmp(FieldOperand(scratch1, HeapObject::kMapOffset),
1210  isolate()->factory()->native_context_map());
1211  Check(equal, kJSGlobalObjectNativeContextShouldBeANativeContext);
1212  }
1213 
1214  // Check if both contexts are the same.
1215  cmp(scratch1, FieldOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
1216  j(equal, &same_contexts);
1217 
1218  // Compare security tokens, save holder_reg on the stack so we can use it
1219  // as a temporary register.
1220  //
1221  // Check that the security token in the calling global object is
1222  // compatible with the security token in the receiving global
1223  // object.
1224  mov(scratch2,
1225  FieldOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
1226 
1227  // Check the context is a native context.
1228  if (emit_debug_code()) {
1229  cmp(scratch2, isolate()->factory()->null_value());
1230  Check(not_equal, kJSGlobalProxyContextShouldNotBeNull);
1231 
1232  // Read the first word and compare to native_context_map(),
1233  cmp(FieldOperand(scratch2, HeapObject::kMapOffset),
1234  isolate()->factory()->native_context_map());
1235  Check(equal, kJSGlobalObjectNativeContextShouldBeANativeContext);
1236  }
1237 
1238  int token_offset = Context::kHeaderSize +
1239  Context::SECURITY_TOKEN_INDEX * kPointerSize;
1240  mov(scratch1, FieldOperand(scratch1, token_offset));
1241  cmp(scratch1, FieldOperand(scratch2, token_offset));
1242  j(not_equal, miss);
1243 
1244  bind(&same_contexts);
1245 }
1246 
1247 
1248 // Compute the hash code from the untagged key. This must be kept in sync with
1249 // ComputeIntegerHash in utils.h and KeyedLoadGenericStub in
1250 // code-stub-hydrogen.cc
1251 //
1252 // Note: r0 will contain hash code
1253 void MacroAssembler::GetNumberHash(Register r0, Register scratch) {
1254  // Xor original key with a seed.
1255  if (serializer_enabled()) {
1256  ExternalReference roots_array_start =
1257  ExternalReference::roots_array_start(isolate());
1258  mov(scratch, Immediate(Heap::kHashSeedRootIndex));
1259  mov(scratch,
1260  Operand::StaticArray(scratch, times_pointer_size, roots_array_start));
1261  SmiUntag(scratch);
1262  xor_(r0, scratch);
1263  } else {
1264  int32_t seed = isolate()->heap()->HashSeed();
1265  xor_(r0, Immediate(seed));
1266  }
1267 
1268  // hash = ~hash + (hash << 15);
1269  mov(scratch, r0);
1270  not_(r0);
1271  shl(scratch, 15);
1272  add(r0, scratch);
1273  // hash = hash ^ (hash >> 12);
1274  mov(scratch, r0);
1275  shr(scratch, 12);
1276  xor_(r0, scratch);
1277  // hash = hash + (hash << 2);
1278  lea(r0, Operand(r0, r0, times_4, 0));
1279  // hash = hash ^ (hash >> 4);
1280  mov(scratch, r0);
1281  shr(scratch, 4);
1282  xor_(r0, scratch);
1283  // hash = hash * 2057;
1284  imul(r0, r0, 2057);
1285  // hash = hash ^ (hash >> 16);
1286  mov(scratch, r0);
1287  shr(scratch, 16);
1288  xor_(r0, scratch);
1289 }
1290 
1291 
1292 
1293 void MacroAssembler::LoadFromNumberDictionary(Label* miss,
1294  Register elements,
1295  Register key,
1296  Register r0,
1297  Register r1,
1298  Register r2,
1299  Register result) {
1300  // Register use:
1301  //
1302  // elements - holds the slow-case elements of the receiver and is unchanged.
1303  //
1304  // key - holds the smi key on entry and is unchanged.
1305  //
1306  // Scratch registers:
1307  //
1308  // r0 - holds the untagged key on entry and holds the hash once computed.
1309  //
1310  // r1 - used to hold the capacity mask of the dictionary
1311  //
1312  // r2 - used for the index into the dictionary.
1313  //
1314  // result - holds the result on exit if the load succeeds and we fall through.
1315 
1316  Label done;
1317 
1318  GetNumberHash(r0, r1);
1319 
1320  // Compute capacity mask.
1321  mov(r1, FieldOperand(elements, SeededNumberDictionary::kCapacityOffset));
1322  shr(r1, kSmiTagSize); // convert smi to int
1323  dec(r1);
1324 
1325  // Generate an unrolled loop that performs a few probes before giving up.
1326  for (int i = 0; i < kNumberDictionaryProbes; i++) {
1327  // Use r2 for index calculations and keep the hash intact in r0.
1328  mov(r2, r0);
1329  // Compute the masked index: (hash + i + i * i) & mask.
1330  if (i > 0) {
1331  add(r2, Immediate(SeededNumberDictionary::GetProbeOffset(i)));
1332  }
1333  and_(r2, r1);
1334 
1335  // Scale the index by multiplying by the entry size.
1336  DCHECK(SeededNumberDictionary::kEntrySize == 3);
1337  lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3
1338 
1339  // Check if the key matches.
1340  cmp(key, FieldOperand(elements,
1341  r2,
1343  SeededNumberDictionary::kElementsStartOffset));
1344  if (i != (kNumberDictionaryProbes - 1)) {
1345  j(equal, &done);
1346  } else {
1347  j(not_equal, miss);
1348  }
1349  }
1350 
1351  bind(&done);
1352  // Check that the value is a normal propety.
1353  const int kDetailsOffset =
1354  SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
1355  DCHECK_EQ(NORMAL, 0);
1356  test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
1357  Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
1358  j(not_zero, miss);
1359 
1360  // Get the value at the masked, scaled index.
1361  const int kValueOffset =
1362  SeededNumberDictionary::kElementsStartOffset + kPointerSize;
1363  mov(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset));
1364 }
1365 
1366 
1367 void MacroAssembler::LoadAllocationTopHelper(Register result,
1368  Register scratch,
1370  ExternalReference allocation_top =
1371  AllocationUtils::GetAllocationTopReference(isolate(), flags);
1372 
1373  // Just return if allocation top is already known.
1374  if ((flags & RESULT_CONTAINS_TOP) != 0) {
1375  // No use of scratch if allocation top is provided.
1376  DCHECK(scratch.is(no_reg));
1377 #ifdef DEBUG
1378  // Assert that result actually contains top on entry.
1379  cmp(result, Operand::StaticVariable(allocation_top));
1380  Check(equal, kUnexpectedAllocationTop);
1381 #endif
1382  return;
1383  }
1384 
1385  // Move address of new object to result. Use scratch register if available.
1386  if (scratch.is(no_reg)) {
1387  mov(result, Operand::StaticVariable(allocation_top));
1388  } else {
1389  mov(scratch, Immediate(allocation_top));
1390  mov(result, Operand(scratch, 0));
1391  }
1392 }
1393 
1394 
1395 void MacroAssembler::UpdateAllocationTopHelper(Register result_end,
1396  Register scratch,
1398  if (emit_debug_code()) {
1399  test(result_end, Immediate(kObjectAlignmentMask));
1400  Check(zero, kUnalignedAllocationInNewSpace);
1401  }
1402 
1403  ExternalReference allocation_top =
1404  AllocationUtils::GetAllocationTopReference(isolate(), flags);
1405 
1406  // Update new top. Use scratch if available.
1407  if (scratch.is(no_reg)) {
1408  mov(Operand::StaticVariable(allocation_top), result_end);
1409  } else {
1410  mov(Operand(scratch, 0), result_end);
1411  }
1412 }
1413 
1414 
1415 void MacroAssembler::Allocate(int object_size,
1416  Register result,
1417  Register result_end,
1418  Register scratch,
1419  Label* gc_required,
1422  DCHECK(object_size <= Page::kMaxRegularHeapObjectSize);
1423  if (!FLAG_inline_new) {
1424  if (emit_debug_code()) {
1425  // Trash the registers to simulate an allocation failure.
1426  mov(result, Immediate(0x7091));
1427  if (result_end.is_valid()) {
1428  mov(result_end, Immediate(0x7191));
1429  }
1430  if (scratch.is_valid()) {
1431  mov(scratch, Immediate(0x7291));
1432  }
1433  }
1434  jmp(gc_required);
1435  return;
1436  }
1437  DCHECK(!result.is(result_end));
1438 
1439  // Load address of new object into result.
1440  LoadAllocationTopHelper(result, scratch, flags);
1441 
1442  ExternalReference allocation_limit =
1443  AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1444 
1445  // Align the next allocation. Storing the filler map without checking top is
1446  // safe in new-space because the limit of the heap is aligned there.
1447  if ((flags & DOUBLE_ALIGNMENT) != 0) {
1450  Label aligned;
1451  test(result, Immediate(kDoubleAlignmentMask));
1452  j(zero, &aligned, Label::kNear);
1453  if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
1454  cmp(result, Operand::StaticVariable(allocation_limit));
1455  j(above_equal, gc_required);
1456  }
1457  mov(Operand(result, 0),
1458  Immediate(isolate()->factory()->one_pointer_filler_map()));
1459  add(result, Immediate(kDoubleSize / 2));
1460  bind(&aligned);
1461  }
1462 
1463  // Calculate new top and bail out if space is exhausted.
1464  Register top_reg = result_end.is_valid() ? result_end : result;
1465  if (!top_reg.is(result)) {
1466  mov(top_reg, result);
1467  }
1468  add(top_reg, Immediate(object_size));
1469  j(carry, gc_required);
1470  cmp(top_reg, Operand::StaticVariable(allocation_limit));
1471  j(above, gc_required);
1472 
1473  // Update allocation top.
1474  UpdateAllocationTopHelper(top_reg, scratch, flags);
1475 
1476  // Tag result if requested.
1477  bool tag_result = (flags & TAG_OBJECT) != 0;
1478  if (top_reg.is(result)) {
1479  if (tag_result) {
1480  sub(result, Immediate(object_size - kHeapObjectTag));
1481  } else {
1482  sub(result, Immediate(object_size));
1483  }
1484  } else if (tag_result) {
1485  DCHECK(kHeapObjectTag == 1);
1486  inc(result);
1487  }
1488 }
1489 
1490 
1491 void MacroAssembler::Allocate(int header_size,
1492  ScaleFactor element_size,
1493  Register element_count,
1494  RegisterValueType element_count_type,
1495  Register result,
1496  Register result_end,
1497  Register scratch,
1498  Label* gc_required,
1500  DCHECK((flags & SIZE_IN_WORDS) == 0);
1501  if (!FLAG_inline_new) {
1502  if (emit_debug_code()) {
1503  // Trash the registers to simulate an allocation failure.
1504  mov(result, Immediate(0x7091));
1505  mov(result_end, Immediate(0x7191));
1506  if (scratch.is_valid()) {
1507  mov(scratch, Immediate(0x7291));
1508  }
1509  // Register element_count is not modified by the function.
1510  }
1511  jmp(gc_required);
1512  return;
1513  }
1514  DCHECK(!result.is(result_end));
1515 
1516  // Load address of new object into result.
1517  LoadAllocationTopHelper(result, scratch, flags);
1518 
1519  ExternalReference allocation_limit =
1520  AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1521 
1522  // Align the next allocation. Storing the filler map without checking top is
1523  // safe in new-space because the limit of the heap is aligned there.
1524  if ((flags & DOUBLE_ALIGNMENT) != 0) {
1527  Label aligned;
1528  test(result, Immediate(kDoubleAlignmentMask));
1529  j(zero, &aligned, Label::kNear);
1530  if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
1531  cmp(result, Operand::StaticVariable(allocation_limit));
1532  j(above_equal, gc_required);
1533  }
1534  mov(Operand(result, 0),
1535  Immediate(isolate()->factory()->one_pointer_filler_map()));
1536  add(result, Immediate(kDoubleSize / 2));
1537  bind(&aligned);
1538  }
1539 
1540  // Calculate new top and bail out if space is exhausted.
1541  // We assume that element_count*element_size + header_size does not
1542  // overflow.
1543  if (element_count_type == REGISTER_VALUE_IS_SMI) {
1544  STATIC_ASSERT(static_cast<ScaleFactor>(times_2 - 1) == times_1);
1545  STATIC_ASSERT(static_cast<ScaleFactor>(times_4 - 1) == times_2);
1546  STATIC_ASSERT(static_cast<ScaleFactor>(times_8 - 1) == times_4);
1547  DCHECK(element_size >= times_2);
1548  DCHECK(kSmiTagSize == 1);
1549  element_size = static_cast<ScaleFactor>(element_size - 1);
1550  } else {
1551  DCHECK(element_count_type == REGISTER_VALUE_IS_INT32);
1552  }
1553  lea(result_end, Operand(element_count, element_size, header_size));
1554  add(result_end, result);
1555  j(carry, gc_required);
1556  cmp(result_end, Operand::StaticVariable(allocation_limit));
1557  j(above, gc_required);
1558 
1559  if ((flags & TAG_OBJECT) != 0) {
1560  DCHECK(kHeapObjectTag == 1);
1561  inc(result);
1562  }
1563 
1564  // Update allocation top.
1565  UpdateAllocationTopHelper(result_end, scratch, flags);
1566 }
1567 
1568 
1569 void MacroAssembler::Allocate(Register object_size,
1570  Register result,
1571  Register result_end,
1572  Register scratch,
1573  Label* gc_required,
1576  if (!FLAG_inline_new) {
1577  if (emit_debug_code()) {
1578  // Trash the registers to simulate an allocation failure.
1579  mov(result, Immediate(0x7091));
1580  mov(result_end, Immediate(0x7191));
1581  if (scratch.is_valid()) {
1582  mov(scratch, Immediate(0x7291));
1583  }
1584  // object_size is left unchanged by this function.
1585  }
1586  jmp(gc_required);
1587  return;
1588  }
1589  DCHECK(!result.is(result_end));
1590 
1591  // Load address of new object into result.
1592  LoadAllocationTopHelper(result, scratch, flags);
1593 
1594  ExternalReference allocation_limit =
1595  AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1596 
1597  // Align the next allocation. Storing the filler map without checking top is
1598  // safe in new-space because the limit of the heap is aligned there.
1599  if ((flags & DOUBLE_ALIGNMENT) != 0) {
1602  Label aligned;
1603  test(result, Immediate(kDoubleAlignmentMask));
1604  j(zero, &aligned, Label::kNear);
1605  if ((flags & PRETENURE_OLD_DATA_SPACE) != 0) {
1606  cmp(result, Operand::StaticVariable(allocation_limit));
1607  j(above_equal, gc_required);
1608  }
1609  mov(Operand(result, 0),
1610  Immediate(isolate()->factory()->one_pointer_filler_map()));
1611  add(result, Immediate(kDoubleSize / 2));
1612  bind(&aligned);
1613  }
1614 
1615  // Calculate new top and bail out if space is exhausted.
1616  if (!object_size.is(result_end)) {
1617  mov(result_end, object_size);
1618  }
1619  add(result_end, result);
1620  j(carry, gc_required);
1621  cmp(result_end, Operand::StaticVariable(allocation_limit));
1622  j(above, gc_required);
1623 
1624  // Tag result if requested.
1625  if ((flags & TAG_OBJECT) != 0) {
1626  DCHECK(kHeapObjectTag == 1);
1627  inc(result);
1628  }
1629 
1630  // Update allocation top.
1631  UpdateAllocationTopHelper(result_end, scratch, flags);
1632 }
1633 
1634 
1635 void MacroAssembler::UndoAllocationInNewSpace(Register object) {
1636  ExternalReference new_space_allocation_top =
1637  ExternalReference::new_space_allocation_top_address(isolate());
1638 
1639  // Make sure the object has no tag before resetting top.
1640  and_(object, Immediate(~kHeapObjectTagMask));
1641 #ifdef DEBUG
1642  cmp(object, Operand::StaticVariable(new_space_allocation_top));
1643  Check(below, kUndoAllocationOfNonAllocatedMemory);
1644 #endif
1645  mov(Operand::StaticVariable(new_space_allocation_top), object);
1646 }
1647 
1648 
1649 void MacroAssembler::AllocateHeapNumber(Register result,
1650  Register scratch1,
1651  Register scratch2,
1652  Label* gc_required,
1653  MutableMode mode) {
1654  // Allocate heap number in new space.
1655  Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required,
1656  TAG_OBJECT);
1657 
1658  Handle<Map> map = mode == MUTABLE
1659  ? isolate()->factory()->mutable_heap_number_map()
1660  : isolate()->factory()->heap_number_map();
1661 
1662  // Set the map.
1663  mov(FieldOperand(result, HeapObject::kMapOffset), Immediate(map));
1664 }
1665 
1666 
1667 void MacroAssembler::AllocateTwoByteString(Register result,
1668  Register length,
1669  Register scratch1,
1670  Register scratch2,
1671  Register scratch3,
1672  Label* gc_required) {
1673  // Calculate the number of bytes needed for the characters in the string while
1674  // observing object alignment.
1675  DCHECK((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
1676  DCHECK(kShortSize == 2);
1677  // scratch1 = length * 2 + kObjectAlignmentMask.
1678  lea(scratch1, Operand(length, length, times_1, kObjectAlignmentMask));
1679  and_(scratch1, Immediate(~kObjectAlignmentMask));
1680 
1681  // Allocate two byte string in new space.
1682  Allocate(SeqTwoByteString::kHeaderSize,
1683  times_1,
1684  scratch1,
1686  result,
1687  scratch2,
1688  scratch3,
1689  gc_required,
1690  TAG_OBJECT);
1691 
1692  // Set the map, length and hash field.
1693  mov(FieldOperand(result, HeapObject::kMapOffset),
1694  Immediate(isolate()->factory()->string_map()));
1695  mov(scratch1, length);
1696  SmiTag(scratch1);
1697  mov(FieldOperand(result, String::kLengthOffset), scratch1);
1698  mov(FieldOperand(result, String::kHashFieldOffset),
1699  Immediate(String::kEmptyHashField));
1700 }
1701 
1702 
1703 void MacroAssembler::AllocateOneByteString(Register result, Register length,
1704  Register scratch1, Register scratch2,
1705  Register scratch3,
1706  Label* gc_required) {
1707  // Calculate the number of bytes needed for the characters in the string while
1708  // observing object alignment.
1709  DCHECK((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
1710  mov(scratch1, length);
1711  DCHECK(kCharSize == 1);
1712  add(scratch1, Immediate(kObjectAlignmentMask));
1713  and_(scratch1, Immediate(~kObjectAlignmentMask));
1714 
1715  // Allocate one-byte string in new space.
1716  Allocate(SeqOneByteString::kHeaderSize,
1717  times_1,
1718  scratch1,
1720  result,
1721  scratch2,
1722  scratch3,
1723  gc_required,
1724  TAG_OBJECT);
1725 
1726  // Set the map, length and hash field.
1727  mov(FieldOperand(result, HeapObject::kMapOffset),
1728  Immediate(isolate()->factory()->one_byte_string_map()));
1729  mov(scratch1, length);
1730  SmiTag(scratch1);
1731  mov(FieldOperand(result, String::kLengthOffset), scratch1);
1732  mov(FieldOperand(result, String::kHashFieldOffset),
1733  Immediate(String::kEmptyHashField));
1734 }
1735 
1736 
1737 void MacroAssembler::AllocateOneByteString(Register result, int length,
1738  Register scratch1, Register scratch2,
1739  Label* gc_required) {
1740  DCHECK(length > 0);
1741 
1742  // Allocate one-byte string in new space.
1743  Allocate(SeqOneByteString::SizeFor(length), result, scratch1, scratch2,
1744  gc_required, TAG_OBJECT);
1745 
1746  // Set the map, length and hash field.
1747  mov(FieldOperand(result, HeapObject::kMapOffset),
1748  Immediate(isolate()->factory()->one_byte_string_map()));
1749  mov(FieldOperand(result, String::kLengthOffset),
1750  Immediate(Smi::FromInt(length)));
1751  mov(FieldOperand(result, String::kHashFieldOffset),
1752  Immediate(String::kEmptyHashField));
1753 }
1754 
1755 
1756 void MacroAssembler::AllocateTwoByteConsString(Register result,
1757  Register scratch1,
1758  Register scratch2,
1759  Label* gc_required) {
1760  // Allocate heap number in new space.
1761  Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
1762  TAG_OBJECT);
1763 
1764  // Set the map. The other fields are left uninitialized.
1765  mov(FieldOperand(result, HeapObject::kMapOffset),
1766  Immediate(isolate()->factory()->cons_string_map()));
1767 }
1768 
1769 
1770 void MacroAssembler::AllocateOneByteConsString(Register result,
1771  Register scratch1,
1772  Register scratch2,
1773  Label* gc_required) {
1774  Allocate(ConsString::kSize,
1775  result,
1776  scratch1,
1777  scratch2,
1778  gc_required,
1779  TAG_OBJECT);
1780 
1781  // Set the map. The other fields are left uninitialized.
1782  mov(FieldOperand(result, HeapObject::kMapOffset),
1783  Immediate(isolate()->factory()->cons_one_byte_string_map()));
1784 }
1785 
1786 
1787 void MacroAssembler::AllocateTwoByteSlicedString(Register result,
1788  Register scratch1,
1789  Register scratch2,
1790  Label* gc_required) {
1791  // Allocate heap number in new space.
1792  Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
1793  TAG_OBJECT);
1794 
1795  // Set the map. The other fields are left uninitialized.
1796  mov(FieldOperand(result, HeapObject::kMapOffset),
1797  Immediate(isolate()->factory()->sliced_string_map()));
1798 }
1799 
1800 
1801 void MacroAssembler::AllocateOneByteSlicedString(Register result,
1802  Register scratch1,
1803  Register scratch2,
1804  Label* gc_required) {
1805  // Allocate heap number in new space.
1806  Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
1807  TAG_OBJECT);
1808 
1809  // Set the map. The other fields are left uninitialized.
1810  mov(FieldOperand(result, HeapObject::kMapOffset),
1811  Immediate(isolate()->factory()->sliced_one_byte_string_map()));
1812 }
1813 
1814 
1815 // Copy memory, byte-by-byte, from source to destination. Not optimized for
1816 // long or aligned copies. The contents of scratch and length are destroyed.
1817 // Source and destination are incremented by length.
1818 // Many variants of movsb, loop unrolling, word moves, and indexed operands
1819 // have been tried here already, and this is fastest.
1820 // A simpler loop is faster on small copies, but 30% slower on large ones.
1821 // The cld() instruction must have been emitted, to set the direction flag(),
1822 // before calling this function.
1823 void MacroAssembler::CopyBytes(Register source,
1824  Register destination,
1825  Register length,
1826  Register scratch) {
1827  Label short_loop, len4, len8, len12, done, short_string;
1828  DCHECK(source.is(esi));
1829  DCHECK(destination.is(edi));
1830  DCHECK(length.is(ecx));
1831  cmp(length, Immediate(4));
1832  j(below, &short_string, Label::kNear);
1833 
1834  // Because source is 4-byte aligned in our uses of this function,
1835  // we keep source aligned for the rep_movs call by copying the odd bytes
1836  // at the end of the ranges.
1837  mov(scratch, Operand(source, length, times_1, -4));
1838  mov(Operand(destination, length, times_1, -4), scratch);
1839 
1840  cmp(length, Immediate(8));
1841  j(below_equal, &len4, Label::kNear);
1842  cmp(length, Immediate(12));
1843  j(below_equal, &len8, Label::kNear);
1844  cmp(length, Immediate(16));
1845  j(below_equal, &len12, Label::kNear);
1846 
1847  mov(scratch, ecx);
1848  shr(ecx, 2);
1849  rep_movs();
1850  and_(scratch, Immediate(0x3));
1851  add(destination, scratch);
1852  jmp(&done, Label::kNear);
1853 
1854  bind(&len12);
1855  mov(scratch, Operand(source, 8));
1856  mov(Operand(destination, 8), scratch);
1857  bind(&len8);
1858  mov(scratch, Operand(source, 4));
1859  mov(Operand(destination, 4), scratch);
1860  bind(&len4);
1861  mov(scratch, Operand(source, 0));
1862  mov(Operand(destination, 0), scratch);
1863  add(destination, length);
1864  jmp(&done, Label::kNear);
1865 
1866  bind(&short_string);
1867  test(length, length);
1868  j(zero, &done, Label::kNear);
1869 
1870  bind(&short_loop);
1871  mov_b(scratch, Operand(source, 0));
1872  mov_b(Operand(destination, 0), scratch);
1873  inc(source);
1874  inc(destination);
1875  dec(length);
1876  j(not_zero, &short_loop);
1877 
1878  bind(&done);
1879 }
1880 
1881 
1882 void MacroAssembler::InitializeFieldsWithFiller(Register start_offset,
1883  Register end_offset,
1884  Register filler) {
1885  Label loop, entry;
1886  jmp(&entry);
1887  bind(&loop);
1888  mov(Operand(start_offset, 0), filler);
1889  add(start_offset, Immediate(kPointerSize));
1890  bind(&entry);
1891  cmp(start_offset, end_offset);
1892  j(less, &loop);
1893 }
1894 
1895 
1896 void MacroAssembler::BooleanBitTest(Register object,
1897  int field_offset,
1898  int bit_index) {
1899  bit_index += kSmiTagSize + kSmiShiftSize;
1901  int byte_index = bit_index / kBitsPerByte;
1902  int byte_bit_index = bit_index & (kBitsPerByte - 1);
1903  test_b(FieldOperand(object, field_offset + byte_index),
1904  static_cast<byte>(1 << byte_bit_index));
1905 }
1906 
1907 
1908 
1909 void MacroAssembler::NegativeZeroTest(Register result,
1910  Register op,
1911  Label* then_label) {
1912  Label ok;
1913  test(result, result);
1914  j(not_zero, &ok);
1915  test(op, op);
1916  j(sign, then_label);
1917  bind(&ok);
1918 }
1919 
1920 
1921 void MacroAssembler::NegativeZeroTest(Register result,
1922  Register op1,
1923  Register op2,
1924  Register scratch,
1925  Label* then_label) {
1926  Label ok;
1927  test(result, result);
1928  j(not_zero, &ok);
1929  mov(scratch, op1);
1930  or_(scratch, op2);
1931  j(sign, then_label);
1932  bind(&ok);
1933 }
1934 
1935 
1936 void MacroAssembler::TryGetFunctionPrototype(Register function,
1937  Register result,
1938  Register scratch,
1939  Label* miss,
1940  bool miss_on_bound_function) {
1941  Label non_instance;
1942  if (miss_on_bound_function) {
1943  // Check that the receiver isn't a smi.
1944  JumpIfSmi(function, miss);
1945 
1946  // Check that the function really is a function.
1947  CmpObjectType(function, JS_FUNCTION_TYPE, result);
1948  j(not_equal, miss);
1949 
1950  // If a bound function, go to miss label.
1951  mov(scratch,
1952  FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
1953  BooleanBitTest(scratch, SharedFunctionInfo::kCompilerHintsOffset,
1954  SharedFunctionInfo::kBoundFunction);
1955  j(not_zero, miss);
1956 
1957  // Make sure that the function has an instance prototype.
1958  movzx_b(scratch, FieldOperand(result, Map::kBitFieldOffset));
1959  test(scratch, Immediate(1 << Map::kHasNonInstancePrototype));
1960  j(not_zero, &non_instance);
1961  }
1962 
1963  // Get the prototype or initial map from the function.
1964  mov(result,
1965  FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
1966 
1967  // If the prototype or initial map is the hole, don't return it and
1968  // simply miss the cache instead. This will allow us to allocate a
1969  // prototype object on-demand in the runtime system.
1970  cmp(result, Immediate(isolate()->factory()->the_hole_value()));
1971  j(equal, miss);
1972 
1973  // If the function does not have an initial map, we're done.
1974  Label done;
1975  CmpObjectType(result, MAP_TYPE, scratch);
1976  j(not_equal, &done);
1977 
1978  // Get the prototype from the initial map.
1979  mov(result, FieldOperand(result, Map::kPrototypeOffset));
1980 
1981  if (miss_on_bound_function) {
1982  jmp(&done);
1983 
1984  // Non-instance prototype: Fetch prototype from constructor field
1985  // in initial map.
1986  bind(&non_instance);
1987  mov(result, FieldOperand(result, Map::kConstructorOffset));
1988  }
1989 
1990  // All done.
1991  bind(&done);
1992 }
1993 
1994 
1995 void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id) {
1996  DCHECK(AllowThisStubCall(stub)); // Calls are not allowed in some stubs.
1997  call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id);
1998 }
1999 
2000 
2001 void MacroAssembler::TailCallStub(CodeStub* stub) {
2002  jmp(stub->GetCode(), RelocInfo::CODE_TARGET);
2003 }
2004 
2005 
2006 void MacroAssembler::StubReturn(int argc) {
2007  DCHECK(argc >= 1 && generating_stub());
2008  ret((argc - 1) * kPointerSize);
2009 }
2010 
2011 
2012 bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
2013  return has_frame_ || !stub->SometimesSetsUpAFrame();
2014 }
2015 
2016 
2017 void MacroAssembler::IndexFromHash(Register hash, Register index) {
2018  // The assert checks that the constants for the maximum number of digits
2019  // for an array index cached in the hash field and the number of bits
2020  // reserved for it does not conflict.
2021  DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
2022  (1 << String::kArrayIndexValueBits));
2023  if (!index.is(hash)) {
2024  mov(index, hash);
2025  }
2026  DecodeFieldToSmi<String::ArrayIndexValueBits>(index);
2027 }
2028 
2029 
2030 void MacroAssembler::CallRuntime(const Runtime::Function* f,
2031  int num_arguments,
2032  SaveFPRegsMode save_doubles) {
2033  // If the expected number of arguments of the runtime function is
2034  // constant, we check that the actual number of arguments match the
2035  // expectation.
2036  CHECK(f->nargs < 0 || f->nargs == num_arguments);
2037 
2038  // TODO(1236192): Most runtime routines don't need the number of
2039  // arguments passed in because it is constant. At some point we
2040  // should remove this need and make the runtime routine entry code
2041  // smarter.
2042  Move(eax, Immediate(num_arguments));
2043  mov(ebx, Immediate(ExternalReference(f, isolate())));
2044  CEntryStub ces(isolate(), 1, save_doubles);
2045  CallStub(&ces);
2046 }
2047 
2048 
2049 void MacroAssembler::CallExternalReference(ExternalReference ref,
2050  int num_arguments) {
2051  mov(eax, Immediate(num_arguments));
2052  mov(ebx, Immediate(ref));
2053 
2054  CEntryStub stub(isolate(), 1);
2055  CallStub(&stub);
2056 }
2057 
2058 
2059 void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
2060  int num_arguments,
2061  int result_size) {
2062  // TODO(1236192): Most runtime routines don't need the number of
2063  // arguments passed in because it is constant. At some point we
2064  // should remove this need and make the runtime routine entry code
2065  // smarter.
2066  Move(eax, Immediate(num_arguments));
2067  JumpToExternalReference(ext);
2068 }
2069 
2070 
2071 void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
2072  int num_arguments,
2073  int result_size) {
2074  TailCallExternalReference(ExternalReference(fid, isolate()),
2075  num_arguments,
2076  result_size);
2077 }
2078 
2079 
2080 Operand ApiParameterOperand(int index) {
2081  return Operand(esp, index * kPointerSize);
2082 }
2083 
2084 
2085 void MacroAssembler::PrepareCallApiFunction(int argc) {
2086  EnterApiExitFrame(argc);
2087  if (emit_debug_code()) {
2088  mov(esi, Immediate(bit_cast<int32_t>(kZapValue)));
2089  }
2090 }
2091 
2092 
2093 void MacroAssembler::CallApiFunctionAndReturn(
2094  Register function_address,
2095  ExternalReference thunk_ref,
2096  Operand thunk_last_arg,
2097  int stack_space,
2098  Operand return_value_operand,
2099  Operand* context_restore_operand) {
2100  ExternalReference next_address =
2101  ExternalReference::handle_scope_next_address(isolate());
2102  ExternalReference limit_address =
2103  ExternalReference::handle_scope_limit_address(isolate());
2104  ExternalReference level_address =
2105  ExternalReference::handle_scope_level_address(isolate());
2106 
2107  DCHECK(edx.is(function_address));
2108  // Allocate HandleScope in callee-save registers.
2109  mov(ebx, Operand::StaticVariable(next_address));
2110  mov(edi, Operand::StaticVariable(limit_address));
2111  add(Operand::StaticVariable(level_address), Immediate(1));
2112 
2113  if (FLAG_log_timer_events) {
2114  FrameScope frame(this, StackFrame::MANUAL);
2115  PushSafepointRegisters();
2116  PrepareCallCFunction(1, eax);
2117  mov(Operand(esp, 0),
2118  Immediate(ExternalReference::isolate_address(isolate())));
2119  CallCFunction(ExternalReference::log_enter_external_function(isolate()), 1);
2120  PopSafepointRegisters();
2121  }
2122 
2123 
2124  Label profiler_disabled;
2125  Label end_profiler_check;
2126  mov(eax, Immediate(ExternalReference::is_profiling_address(isolate())));
2127  cmpb(Operand(eax, 0), 0);
2128  j(zero, &profiler_disabled);
2129 
2130  // Additional parameter is the address of the actual getter function.
2131  mov(thunk_last_arg, function_address);
2132  // Call the api function.
2133  mov(eax, Immediate(thunk_ref));
2134  call(eax);
2135  jmp(&end_profiler_check);
2136 
2137  bind(&profiler_disabled);
2138  // Call the api function.
2139  call(function_address);
2140  bind(&end_profiler_check);
2141 
2142  if (FLAG_log_timer_events) {
2143  FrameScope frame(this, StackFrame::MANUAL);
2144  PushSafepointRegisters();
2145  PrepareCallCFunction(1, eax);
2146  mov(Operand(esp, 0),
2147  Immediate(ExternalReference::isolate_address(isolate())));
2148  CallCFunction(ExternalReference::log_leave_external_function(isolate()), 1);
2149  PopSafepointRegisters();
2150  }
2151 
2152  Label prologue;
2153  // Load the value from ReturnValue
2154  mov(eax, return_value_operand);
2155 
2156  Label promote_scheduled_exception;
2157  Label exception_handled;
2158  Label delete_allocated_handles;
2159  Label leave_exit_frame;
2160 
2161  bind(&prologue);
2162  // No more valid handles (the result handle was the last one). Restore
2163  // previous handle scope.
2164  mov(Operand::StaticVariable(next_address), ebx);
2165  sub(Operand::StaticVariable(level_address), Immediate(1));
2166  Assert(above_equal, kInvalidHandleScopeLevel);
2167  cmp(edi, Operand::StaticVariable(limit_address));
2168  j(not_equal, &delete_allocated_handles);
2169  bind(&leave_exit_frame);
2170 
2171  // Check if the function scheduled an exception.
2172  ExternalReference scheduled_exception_address =
2173  ExternalReference::scheduled_exception_address(isolate());
2174  cmp(Operand::StaticVariable(scheduled_exception_address),
2175  Immediate(isolate()->factory()->the_hole_value()));
2176  j(not_equal, &promote_scheduled_exception);
2177  bind(&exception_handled);
2178 
2179 #if ENABLE_EXTRA_CHECKS
2180  // Check if the function returned a valid JavaScript value.
2181  Label ok;
2182  Register return_value = eax;
2183  Register map = ecx;
2184 
2185  JumpIfSmi(return_value, &ok, Label::kNear);
2186  mov(map, FieldOperand(return_value, HeapObject::kMapOffset));
2187 
2188  CmpInstanceType(map, FIRST_NONSTRING_TYPE);
2189  j(below, &ok, Label::kNear);
2190 
2191  CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
2192  j(above_equal, &ok, Label::kNear);
2193 
2194  cmp(map, isolate()->factory()->heap_number_map());
2195  j(equal, &ok, Label::kNear);
2196 
2197  cmp(return_value, isolate()->factory()->undefined_value());
2198  j(equal, &ok, Label::kNear);
2199 
2200  cmp(return_value, isolate()->factory()->true_value());
2201  j(equal, &ok, Label::kNear);
2202 
2203  cmp(return_value, isolate()->factory()->false_value());
2204  j(equal, &ok, Label::kNear);
2205 
2206  cmp(return_value, isolate()->factory()->null_value());
2207  j(equal, &ok, Label::kNear);
2208 
2209  Abort(kAPICallReturnedInvalidObject);
2210 
2211  bind(&ok);
2212 #endif
2213 
2214  bool restore_context = context_restore_operand != NULL;
2215  if (restore_context) {
2216  mov(esi, *context_restore_operand);
2217  }
2218  LeaveApiExitFrame(!restore_context);
2219  ret(stack_space * kPointerSize);
2220 
2221  bind(&promote_scheduled_exception);
2222  {
2223  FrameScope frame(this, StackFrame::INTERNAL);
2224  CallRuntime(Runtime::kPromoteScheduledException, 0);
2225  }
2226  jmp(&exception_handled);
2227 
2228  // HandleScope limit has changed. Delete allocated extensions.
2229  ExternalReference delete_extensions =
2230  ExternalReference::delete_handle_scope_extensions(isolate());
2231  bind(&delete_allocated_handles);
2232  mov(Operand::StaticVariable(limit_address), edi);
2233  mov(edi, eax);
2234  mov(Operand(esp, 0),
2235  Immediate(ExternalReference::isolate_address(isolate())));
2236  mov(eax, Immediate(delete_extensions));
2237  call(eax);
2238  mov(eax, edi);
2239  jmp(&leave_exit_frame);
2240 }
2241 
2242 
2243 void MacroAssembler::JumpToExternalReference(const ExternalReference& ext) {
2244  // Set the entry point and jump to the C entry runtime stub.
2245  mov(ebx, Immediate(ext));
2246  CEntryStub ces(isolate(), 1);
2247  jmp(ces.GetCode(), RelocInfo::CODE_TARGET);
2248 }
2249 
2250 
2251 void MacroAssembler::InvokePrologue(const ParameterCount& expected,
2252  const ParameterCount& actual,
2253  Handle<Code> code_constant,
2254  const Operand& code_operand,
2255  Label* done,
2256  bool* definitely_mismatches,
2257  InvokeFlag flag,
2258  Label::Distance done_near,
2259  const CallWrapper& call_wrapper) {
2260  bool definitely_matches = false;
2261  *definitely_mismatches = false;
2262  Label invoke;
2263  if (expected.is_immediate()) {
2264  DCHECK(actual.is_immediate());
2265  if (expected.immediate() == actual.immediate()) {
2266  definitely_matches = true;
2267  } else {
2268  mov(eax, actual.immediate());
2269  const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
2270  if (expected.immediate() == sentinel) {
2271  // Don't worry about adapting arguments for builtins that
2272  // don't want that done. Skip adaption code by making it look
2273  // like we have a match between expected and actual number of
2274  // arguments.
2275  definitely_matches = true;
2276  } else {
2277  *definitely_mismatches = true;
2278  mov(ebx, expected.immediate());
2279  }
2280  }
2281  } else {
2282  if (actual.is_immediate()) {
2283  // Expected is in register, actual is immediate. This is the
2284  // case when we invoke function values without going through the
2285  // IC mechanism.
2286  cmp(expected.reg(), actual.immediate());
2287  j(equal, &invoke);
2288  DCHECK(expected.reg().is(ebx));
2289  mov(eax, actual.immediate());
2290  } else if (!expected.reg().is(actual.reg())) {
2291  // Both expected and actual are in (different) registers. This
2292  // is the case when we invoke functions using call and apply.
2293  cmp(expected.reg(), actual.reg());
2294  j(equal, &invoke);
2295  DCHECK(actual.reg().is(eax));
2296  DCHECK(expected.reg().is(ebx));
2297  }
2298  }
2299 
2300  if (!definitely_matches) {
2301  Handle<Code> adaptor =
2302  isolate()->builtins()->ArgumentsAdaptorTrampoline();
2303  if (!code_constant.is_null()) {
2304  mov(edx, Immediate(code_constant));
2305  add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag));
2306  } else if (!code_operand.is_reg(edx)) {
2307  mov(edx, code_operand);
2308  }
2309 
2310  if (flag == CALL_FUNCTION) {
2311  call_wrapper.BeforeCall(CallSize(adaptor, RelocInfo::CODE_TARGET));
2312  call(adaptor, RelocInfo::CODE_TARGET);
2313  call_wrapper.AfterCall();
2314  if (!*definitely_mismatches) {
2315  jmp(done, done_near);
2316  }
2317  } else {
2318  jmp(adaptor, RelocInfo::CODE_TARGET);
2319  }
2320  bind(&invoke);
2321  }
2322 }
2323 
2324 
2325 void MacroAssembler::InvokeCode(const Operand& code,
2326  const ParameterCount& expected,
2327  const ParameterCount& actual,
2328  InvokeFlag flag,
2329  const CallWrapper& call_wrapper) {
2330  // You can't call a function without a valid frame.
2331  DCHECK(flag == JUMP_FUNCTION || has_frame());
2332 
2333  Label done;
2334  bool definitely_mismatches = false;
2335  InvokePrologue(expected, actual, Handle<Code>::null(), code,
2336  &done, &definitely_mismatches, flag, Label::kNear,
2337  call_wrapper);
2338  if (!definitely_mismatches) {
2339  if (flag == CALL_FUNCTION) {
2340  call_wrapper.BeforeCall(CallSize(code));
2341  call(code);
2342  call_wrapper.AfterCall();
2343  } else {
2345  jmp(code);
2346  }
2347  bind(&done);
2348  }
2349 }
2350 
2351 
2352 void MacroAssembler::InvokeFunction(Register fun,
2353  const ParameterCount& actual,
2354  InvokeFlag flag,
2355  const CallWrapper& call_wrapper) {
2356  // You can't call a function without a valid frame.
2357  DCHECK(flag == JUMP_FUNCTION || has_frame());
2358 
2359  DCHECK(fun.is(edi));
2360  mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2361  mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2362  mov(ebx, FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
2363  SmiUntag(ebx);
2364 
2365  ParameterCount expected(ebx);
2366  InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
2367  expected, actual, flag, call_wrapper);
2368 }
2369 
2370 
2371 void MacroAssembler::InvokeFunction(Register fun,
2372  const ParameterCount& expected,
2373  const ParameterCount& actual,
2374  InvokeFlag flag,
2375  const CallWrapper& call_wrapper) {
2376  // You can't call a function without a valid frame.
2377  DCHECK(flag == JUMP_FUNCTION || has_frame());
2378 
2379  DCHECK(fun.is(edi));
2380  mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2381 
2382  InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
2383  expected, actual, flag, call_wrapper);
2384 }
2385 
2386 
2387 void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
2388  const ParameterCount& expected,
2389  const ParameterCount& actual,
2390  InvokeFlag flag,
2391  const CallWrapper& call_wrapper) {
2392  LoadHeapObject(edi, function);
2393  InvokeFunction(edi, expected, actual, flag, call_wrapper);
2394 }
2395 
2396 
2397 void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
2398  InvokeFlag flag,
2399  const CallWrapper& call_wrapper) {
2400  // You can't call a builtin without a valid frame.
2401  DCHECK(flag == JUMP_FUNCTION || has_frame());
2402 
2403  // Rely on the assertion to check that the number of provided
2404  // arguments match the expected number of arguments. Fake a
2405  // parameter count to avoid emitting code to do the check.
2406  ParameterCount expected(0);
2407  GetBuiltinFunction(edi, id);
2408  InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
2409  expected, expected, flag, call_wrapper);
2410 }
2411 
2412 
2413 void MacroAssembler::GetBuiltinFunction(Register target,
2414  Builtins::JavaScript id) {
2415  // Load the JavaScript builtin function from the builtins object.
2416  mov(target, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
2417  mov(target, FieldOperand(target, GlobalObject::kBuiltinsOffset));
2418  mov(target, FieldOperand(target,
2419  JSBuiltinsObject::OffsetOfFunctionWithId(id)));
2420 }
2421 
2422 
2423 void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
2424  DCHECK(!target.is(edi));
2425  // Load the JavaScript builtin function from the builtins object.
2426  GetBuiltinFunction(edi, id);
2427  // Load the code entry point from the function into the target register.
2428  mov(target, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2429 }
2430 
2431 
2432 void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
2433  if (context_chain_length > 0) {
2434  // Move up the chain of contexts to the context containing the slot.
2435  mov(dst, Operand(esi, Context::SlotOffset(Context::PREVIOUS_INDEX)));
2436  for (int i = 1; i < context_chain_length; i++) {
2437  mov(dst, Operand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX)));
2438  }
2439  } else {
2440  // Slot is in the current function context. Move it into the
2441  // destination register in case we store into it (the write barrier
2442  // cannot be allowed to destroy the context in esi).
2443  mov(dst, esi);
2444  }
2445 
2446  // We should not have found a with context by walking the context chain
2447  // (i.e., the static scope chain and runtime context chain do not agree).
2448  // A variable occurring in such a scope should have slot type LOOKUP and
2449  // not CONTEXT.
2450  if (emit_debug_code()) {
2451  cmp(FieldOperand(dst, HeapObject::kMapOffset),
2452  isolate()->factory()->with_context_map());
2453  Check(not_equal, kVariableResolvedToWithContext);
2454  }
2455 }
2456 
2457 
2458 void MacroAssembler::LoadTransitionedArrayMapConditional(
2459  ElementsKind expected_kind,
2460  ElementsKind transitioned_kind,
2461  Register map_in_out,
2462  Register scratch,
2463  Label* no_map_match) {
2464  // Load the global or builtins object from the current context.
2465  mov(scratch, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
2466  mov(scratch, FieldOperand(scratch, GlobalObject::kNativeContextOffset));
2467 
2468  // Check that the function's map is the same as the expected cached map.
2469  mov(scratch, Operand(scratch,
2470  Context::SlotOffset(Context::JS_ARRAY_MAPS_INDEX)));
2471 
2472  size_t offset = expected_kind * kPointerSize +
2473  FixedArrayBase::kHeaderSize;
2474  cmp(map_in_out, FieldOperand(scratch, offset));
2475  j(not_equal, no_map_match);
2476 
2477  // Use the transitioned cached map.
2478  offset = transitioned_kind * kPointerSize +
2479  FixedArrayBase::kHeaderSize;
2480  mov(map_in_out, FieldOperand(scratch, offset));
2481 }
2482 
2483 
2484 void MacroAssembler::LoadGlobalFunction(int index, Register function) {
2485  // Load the global or builtins object from the current context.
2486  mov(function,
2487  Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
2488  // Load the native context from the global or builtins object.
2489  mov(function,
2490  FieldOperand(function, GlobalObject::kNativeContextOffset));
2491  // Load the function from the native context.
2492  mov(function, Operand(function, Context::SlotOffset(index)));
2493 }
2494 
2495 
2496 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
2497  Register map) {
2498  // Load the initial map. The global functions all have initial maps.
2499  mov(map, FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2500  if (emit_debug_code()) {
2501  Label ok, fail;
2502  CheckMap(map, isolate()->factory()->meta_map(), &fail, DO_SMI_CHECK);
2503  jmp(&ok);
2504  bind(&fail);
2505  Abort(kGlobalFunctionsMustHaveInitialMap);
2506  bind(&ok);
2507  }
2508 }
2509 
2510 
2511 // Store the value in register src in the safepoint register stack
2512 // slot for register dst.
2513 void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, Register src) {
2514  mov(SafepointRegisterSlot(dst), src);
2515 }
2516 
2517 
2518 void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, Immediate src) {
2519  mov(SafepointRegisterSlot(dst), src);
2520 }
2521 
2522 
2523 void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) {
2524  mov(dst, SafepointRegisterSlot(src));
2525 }
2526 
2527 
2528 Operand MacroAssembler::SafepointRegisterSlot(Register reg) {
2529  return Operand(esp, SafepointRegisterStackIndex(reg.code()) * kPointerSize);
2530 }
2531 
2532 
2533 int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
2534  // The registers are pushed starting with the lowest encoding,
2535  // which means that lowest encodings are furthest away from
2536  // the stack pointer.
2537  DCHECK(reg_code >= 0 && reg_code < kNumSafepointRegisters);
2538  return kNumSafepointRegisters - reg_code - 1;
2539 }
2540 
2541 
2542 void MacroAssembler::LoadHeapObject(Register result,
2543  Handle<HeapObject> object) {
2544  AllowDeferredHandleDereference embedding_raw_address;
2545  if (isolate()->heap()->InNewSpace(*object)) {
2546  Handle<Cell> cell = isolate()->factory()->NewCell(object);
2547  mov(result, Operand::ForCell(cell));
2548  } else {
2549  mov(result, object);
2550  }
2551 }
2552 
2553 
2554 void MacroAssembler::CmpHeapObject(Register reg, Handle<HeapObject> object) {
2555  AllowDeferredHandleDereference using_raw_address;
2556  if (isolate()->heap()->InNewSpace(*object)) {
2557  Handle<Cell> cell = isolate()->factory()->NewCell(object);
2558  cmp(reg, Operand::ForCell(cell));
2559  } else {
2560  cmp(reg, object);
2561  }
2562 }
2563 
2564 
2565 void MacroAssembler::PushHeapObject(Handle<HeapObject> object) {
2566  AllowDeferredHandleDereference using_raw_address;
2567  if (isolate()->heap()->InNewSpace(*object)) {
2568  Handle<Cell> cell = isolate()->factory()->NewCell(object);
2569  push(Operand::ForCell(cell));
2570  } else {
2571  Push(object);
2572  }
2573 }
2574 
2575 
2576 void MacroAssembler::Ret() {
2577  ret(0);
2578 }
2579 
2580 
2581 void MacroAssembler::Ret(int bytes_dropped, Register scratch) {
2582  if (is_uint16(bytes_dropped)) {
2583  ret(bytes_dropped);
2584  } else {
2585  pop(scratch);
2586  add(esp, Immediate(bytes_dropped));
2587  push(scratch);
2588  ret(0);
2589  }
2590 }
2591 
2592 
2593 void MacroAssembler::Drop(int stack_elements) {
2594  if (stack_elements > 0) {
2595  add(esp, Immediate(stack_elements * kPointerSize));
2596  }
2597 }
2598 
2599 
2600 void MacroAssembler::Move(Register dst, Register src) {
2601  if (!dst.is(src)) {
2602  mov(dst, src);
2603  }
2604 }
2605 
2606 
2607 void MacroAssembler::Move(Register dst, const Immediate& x) {
2608  if (x.is_zero()) {
2609  xor_(dst, dst); // Shorter than mov of 32-bit immediate 0.
2610  } else {
2611  mov(dst, x);
2612  }
2613 }
2614 
2615 
2616 void MacroAssembler::Move(const Operand& dst, const Immediate& x) {
2617  mov(dst, x);
2618 }
2619 
2620 
2621 void MacroAssembler::Move(XMMRegister dst, double val) {
2622  // TODO(titzer): recognize double constants with ExternalReferences.
2623  uint64_t int_val = bit_cast<uint64_t, double>(val);
2624  if (int_val == 0) {
2625  xorps(dst, dst);
2626  } else {
2627  int32_t lower = static_cast<int32_t>(int_val);
2628  int32_t upper = static_cast<int32_t>(int_val >> kBitsPerInt);
2629  push(Immediate(upper));
2630  push(Immediate(lower));
2631  movsd(dst, Operand(esp, 0));
2632  add(esp, Immediate(kDoubleSize));
2633  }
2634 }
2635 
2636 
2637 void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
2638  if (FLAG_native_code_counters && counter->Enabled()) {
2639  mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value));
2640  }
2641 }
2642 
2643 
2644 void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) {
2645  DCHECK(value > 0);
2646  if (FLAG_native_code_counters && counter->Enabled()) {
2647  Operand operand = Operand::StaticVariable(ExternalReference(counter));
2648  if (value == 1) {
2649  inc(operand);
2650  } else {
2651  add(operand, Immediate(value));
2652  }
2653  }
2654 }
2655 
2656 
2657 void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) {
2658  DCHECK(value > 0);
2659  if (FLAG_native_code_counters && counter->Enabled()) {
2660  Operand operand = Operand::StaticVariable(ExternalReference(counter));
2661  if (value == 1) {
2662  dec(operand);
2663  } else {
2664  sub(operand, Immediate(value));
2665  }
2666  }
2667 }
2668 
2669 
2670 void MacroAssembler::IncrementCounter(Condition cc,
2671  StatsCounter* counter,
2672  int value) {
2673  DCHECK(value > 0);
2674  if (FLAG_native_code_counters && counter->Enabled()) {
2675  Label skip;
2676  j(NegateCondition(cc), &skip);
2677  pushfd();
2678  IncrementCounter(counter, value);
2679  popfd();
2680  bind(&skip);
2681  }
2682 }
2683 
2684 
2685 void MacroAssembler::DecrementCounter(Condition cc,
2686  StatsCounter* counter,
2687  int value) {
2688  DCHECK(value > 0);
2689  if (FLAG_native_code_counters && counter->Enabled()) {
2690  Label skip;
2691  j(NegateCondition(cc), &skip);
2692  pushfd();
2693  DecrementCounter(counter, value);
2694  popfd();
2695  bind(&skip);
2696  }
2697 }
2698 
2699 
2700 void MacroAssembler::Assert(Condition cc, BailoutReason reason) {
2701  if (emit_debug_code()) Check(cc, reason);
2702 }
2703 
2704 
2705 void MacroAssembler::AssertFastElements(Register elements) {
2706  if (emit_debug_code()) {
2707  Factory* factory = isolate()->factory();
2708  Label ok;
2709  cmp(FieldOperand(elements, HeapObject::kMapOffset),
2710  Immediate(factory->fixed_array_map()));
2711  j(equal, &ok);
2712  cmp(FieldOperand(elements, HeapObject::kMapOffset),
2713  Immediate(factory->fixed_double_array_map()));
2714  j(equal, &ok);
2715  cmp(FieldOperand(elements, HeapObject::kMapOffset),
2716  Immediate(factory->fixed_cow_array_map()));
2717  j(equal, &ok);
2718  Abort(kJSObjectWithFastElementsMapHasSlowElements);
2719  bind(&ok);
2720  }
2721 }
2722 
2723 
2724 void MacroAssembler::Check(Condition cc, BailoutReason reason) {
2725  Label L;
2726  j(cc, &L);
2727  Abort(reason);
2728  // will not return here
2729  bind(&L);
2730 }
2731 
2732 
2733 void MacroAssembler::CheckStackAlignment() {
2734  int frame_alignment = base::OS::ActivationFrameAlignment();
2735  int frame_alignment_mask = frame_alignment - 1;
2736  if (frame_alignment > kPointerSize) {
2737  DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
2738  Label alignment_as_expected;
2739  test(esp, Immediate(frame_alignment_mask));
2740  j(zero, &alignment_as_expected);
2741  // Abort if stack is not aligned.
2742  int3();
2743  bind(&alignment_as_expected);
2744  }
2745 }
2746 
2747 
2748 void MacroAssembler::Abort(BailoutReason reason) {
2749 #ifdef DEBUG
2750  const char* msg = GetBailoutReason(reason);
2751  if (msg != NULL) {
2752  RecordComment("Abort message: ");
2753  RecordComment(msg);
2754  }
2755 
2756  if (FLAG_trap_on_abort) {
2757  int3();
2758  return;
2759  }
2760 #endif
2761 
2762  push(Immediate(reinterpret_cast<intptr_t>(Smi::FromInt(reason))));
2763  // Disable stub call restrictions to always allow calls to abort.
2764  if (!has_frame_) {
2765  // We don't actually want to generate a pile of code for this, so just
2766  // claim there is a stack frame, without generating one.
2767  FrameScope scope(this, StackFrame::NONE);
2768  CallRuntime(Runtime::kAbort, 1);
2769  } else {
2770  CallRuntime(Runtime::kAbort, 1);
2771  }
2772  // will not return here
2773  int3();
2774 }
2775 
2776 
2777 void MacroAssembler::LoadInstanceDescriptors(Register map,
2778  Register descriptors) {
2779  mov(descriptors, FieldOperand(map, Map::kDescriptorsOffset));
2780 }
2781 
2782 
2783 void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) {
2784  mov(dst, FieldOperand(map, Map::kBitField3Offset));
2785  DecodeField<Map::NumberOfOwnDescriptorsBits>(dst);
2786 }
2787 
2788 
2789 void MacroAssembler::LoadPowerOf2(XMMRegister dst,
2790  Register scratch,
2791  int power) {
2792  DCHECK(is_uintn(power + HeapNumber::kExponentBias,
2793  HeapNumber::kExponentBits));
2794  mov(scratch, Immediate(power + HeapNumber::kExponentBias));
2795  movd(dst, scratch);
2796  psllq(dst, HeapNumber::kMantissaBits);
2797 }
2798 
2799 
2800 void MacroAssembler::LookupNumberStringCache(Register object,
2801  Register result,
2802  Register scratch1,
2803  Register scratch2,
2804  Label* not_found) {
2805  // Use of registers. Register result is used as a temporary.
2806  Register number_string_cache = result;
2807  Register mask = scratch1;
2808  Register scratch = scratch2;
2809 
2810  // Load the number string cache.
2811  LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex);
2812  // Make the hash mask from the length of the number string cache. It
2813  // contains two elements (number and string) for each cache entry.
2814  mov(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset));
2815  shr(mask, kSmiTagSize + 1); // Untag length and divide it by two.
2816  sub(mask, Immediate(1)); // Make mask.
2817 
2818  // Calculate the entry in the number string cache. The hash value in the
2819  // number string cache for smis is just the smi value, and the hash for
2820  // doubles is the xor of the upper and lower words. See
2821  // Heap::GetNumberStringCache.
2822  Label smi_hash_calculated;
2823  Label load_result_from_cache;
2824  Label not_smi;
2825  STATIC_ASSERT(kSmiTag == 0);
2826  JumpIfNotSmi(object, &not_smi, Label::kNear);
2827  mov(scratch, object);
2828  SmiUntag(scratch);
2829  jmp(&smi_hash_calculated, Label::kNear);
2830  bind(&not_smi);
2831  cmp(FieldOperand(object, HeapObject::kMapOffset),
2832  isolate()->factory()->heap_number_map());
2833  j(not_equal, not_found);
2834  STATIC_ASSERT(8 == kDoubleSize);
2835  mov(scratch, FieldOperand(object, HeapNumber::kValueOffset));
2836  xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4));
2837  // Object is heap number and hash is now in scratch. Calculate cache index.
2838  and_(scratch, mask);
2839  Register index = scratch;
2840  Register probe = mask;
2841  mov(probe,
2842  FieldOperand(number_string_cache,
2843  index,
2845  FixedArray::kHeaderSize));
2846  JumpIfSmi(probe, not_found);
2847  movsd(xmm0, FieldOperand(object, HeapNumber::kValueOffset));
2848  ucomisd(xmm0, FieldOperand(probe, HeapNumber::kValueOffset));
2849  j(parity_even, not_found); // Bail out if NaN is involved.
2850  j(not_equal, not_found); // The cache did not contain this value.
2851  jmp(&load_result_from_cache, Label::kNear);
2852 
2853  bind(&smi_hash_calculated);
2854  // Object is smi and hash is now in scratch. Calculate cache index.
2855  and_(scratch, mask);
2856  // Check if the entry is the smi we are looking for.
2857  cmp(object,
2858  FieldOperand(number_string_cache,
2859  index,
2861  FixedArray::kHeaderSize));
2862  j(not_equal, not_found);
2863 
2864  // Get the result from the cache.
2865  bind(&load_result_from_cache);
2866  mov(result,
2867  FieldOperand(number_string_cache,
2868  index,
2870  FixedArray::kHeaderSize + kPointerSize));
2871  IncrementCounter(isolate()->counters()->number_to_string_native(), 1);
2872 }
2873 
2874 
2875 void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte(
2876  Register instance_type, Register scratch, Label* failure) {
2877  if (!scratch.is(instance_type)) {
2878  mov(scratch, instance_type);
2879  }
2880  and_(scratch,
2882  cmp(scratch, kStringTag | kSeqStringTag | kOneByteStringTag);
2883  j(not_equal, failure);
2884 }
2885 
2886 
2887 void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register object1,
2888  Register object2,
2889  Register scratch1,
2890  Register scratch2,
2891  Label* failure) {
2892  // Check that both objects are not smis.
2893  STATIC_ASSERT(kSmiTag == 0);
2894  mov(scratch1, object1);
2895  and_(scratch1, object2);
2896  JumpIfSmi(scratch1, failure);
2897 
2898  // Load instance type for both strings.
2899  mov(scratch1, FieldOperand(object1, HeapObject::kMapOffset));
2900  mov(scratch2, FieldOperand(object2, HeapObject::kMapOffset));
2901  movzx_b(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset));
2902  movzx_b(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset));
2903 
2904  // Check that both are flat one-byte strings.
2905  const int kFlatOneByteStringMask =
2907  const int kFlatOneByteStringTag =
2909  // Interleave bits from both instance types and compare them in one check.
2910  DCHECK_EQ(0, kFlatOneByteStringMask & (kFlatOneByteStringMask << 3));
2911  and_(scratch1, kFlatOneByteStringMask);
2912  and_(scratch2, kFlatOneByteStringMask);
2913  lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
2914  cmp(scratch1, kFlatOneByteStringTag | (kFlatOneByteStringTag << 3));
2915  j(not_equal, failure);
2916 }
2917 
2918 
2919 void MacroAssembler::JumpIfNotUniqueNameInstanceType(Operand operand,
2920  Label* not_unique_name,
2921  Label::Distance distance) {
2923  Label succeed;
2924  test(operand, Immediate(kIsNotStringMask | kIsNotInternalizedMask));
2925  j(zero, &succeed);
2926  cmpb(operand, static_cast<uint8_t>(SYMBOL_TYPE));
2927  j(not_equal, not_unique_name, distance);
2928 
2929  bind(&succeed);
2930 }
2931 
2932 
2933 void MacroAssembler::EmitSeqStringSetCharCheck(Register string,
2934  Register index,
2935  Register value,
2936  uint32_t encoding_mask) {
2937  Label is_object;
2938  JumpIfNotSmi(string, &is_object, Label::kNear);
2939  Abort(kNonObject);
2940  bind(&is_object);
2941 
2942  push(value);
2943  mov(value, FieldOperand(string, HeapObject::kMapOffset));
2944  movzx_b(value, FieldOperand(value, Map::kInstanceTypeOffset));
2945 
2946  and_(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
2947  cmp(value, Immediate(encoding_mask));
2948  pop(value);
2949  Check(equal, kUnexpectedStringType);
2950 
2951  // The index is assumed to be untagged coming in, tag it to compare with the
2952  // string length without using a temp register, it is restored at the end of
2953  // this function.
2954  SmiTag(index);
2955  Check(no_overflow, kIndexIsTooLarge);
2956 
2957  cmp(index, FieldOperand(string, String::kLengthOffset));
2958  Check(less, kIndexIsTooLarge);
2959 
2960  cmp(index, Immediate(Smi::FromInt(0)));
2961  Check(greater_equal, kIndexIsNegative);
2962 
2963  // Restore the index
2964  SmiUntag(index);
2965 }
2966 
2967 
2968 void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
2969  int frame_alignment = base::OS::ActivationFrameAlignment();
2970  if (frame_alignment != 0) {
2971  // Make stack end at alignment and make room for num_arguments words
2972  // and the original value of esp.
2973  mov(scratch, esp);
2974  sub(esp, Immediate((num_arguments + 1) * kPointerSize));
2975  DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
2976  and_(esp, -frame_alignment);
2977  mov(Operand(esp, num_arguments * kPointerSize), scratch);
2978  } else {
2979  sub(esp, Immediate(num_arguments * kPointerSize));
2980  }
2981 }
2982 
2983 
2984 void MacroAssembler::CallCFunction(ExternalReference function,
2985  int num_arguments) {
2986  // Trashing eax is ok as it will be the return value.
2987  mov(eax, Immediate(function));
2988  CallCFunction(eax, num_arguments);
2989 }
2990 
2991 
2992 void MacroAssembler::CallCFunction(Register function,
2993  int num_arguments) {
2994  DCHECK(has_frame());
2995  // Check stack alignment.
2996  if (emit_debug_code()) {
2997  CheckStackAlignment();
2998  }
2999 
3000  call(function);
3001  if (base::OS::ActivationFrameAlignment() != 0) {
3002  mov(esp, Operand(esp, num_arguments * kPointerSize));
3003  } else {
3004  add(esp, Immediate(num_arguments * kPointerSize));
3005  }
3006 }
3007 
3008 
3009 #ifdef DEBUG
3010 bool AreAliased(Register reg1,
3011  Register reg2,
3012  Register reg3,
3013  Register reg4,
3014  Register reg5,
3015  Register reg6,
3016  Register reg7,
3017  Register reg8) {
3018  int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() +
3019  reg3.is_valid() + reg4.is_valid() + reg5.is_valid() + reg6.is_valid() +
3020  reg7.is_valid() + reg8.is_valid();
3021 
3022  RegList regs = 0;
3023  if (reg1.is_valid()) regs |= reg1.bit();
3024  if (reg2.is_valid()) regs |= reg2.bit();
3025  if (reg3.is_valid()) regs |= reg3.bit();
3026  if (reg4.is_valid()) regs |= reg4.bit();
3027  if (reg5.is_valid()) regs |= reg5.bit();
3028  if (reg6.is_valid()) regs |= reg6.bit();
3029  if (reg7.is_valid()) regs |= reg7.bit();
3030  if (reg8.is_valid()) regs |= reg8.bit();
3031  int n_of_non_aliasing_regs = NumRegs(regs);
3032 
3033  return n_of_valid_regs != n_of_non_aliasing_regs;
3034 }
3035 #endif
3036 
3037 
3038 CodePatcher::CodePatcher(byte* address, int size)
3039  : address_(address),
3040  size_(size),
3041  masm_(NULL, address, size + Assembler::kGap) {
3042  // Create a new macro assembler pointing to the address of the code to patch.
3043  // The size is adjusted with kGap on order for the assembler to generate size
3044  // bytes of instructions without failing with buffer size constraints.
3045  DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
3046 }
3047 
3048 
3049 CodePatcher::~CodePatcher() {
3050  // Indicate that code has changed.
3051  CpuFeatures::FlushICache(address_, size_);
3052 
3053  // Check that the code was patched as expected.
3054  DCHECK(masm_.pc_ == address_ + size_);
3055  DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
3056 }
3057 
3058 
3059 void MacroAssembler::CheckPageFlag(
3060  Register object,
3061  Register scratch,
3062  int mask,
3063  Condition cc,
3064  Label* condition_met,
3065  Label::Distance condition_met_distance) {
3066  DCHECK(cc == zero || cc == not_zero);
3067  if (scratch.is(object)) {
3068  and_(scratch, Immediate(~Page::kPageAlignmentMask));
3069  } else {
3070  mov(scratch, Immediate(~Page::kPageAlignmentMask));
3071  and_(scratch, object);
3072  }
3073  if (mask < (1 << kBitsPerByte)) {
3074  test_b(Operand(scratch, MemoryChunk::kFlagsOffset),
3075  static_cast<uint8_t>(mask));
3076  } else {
3077  test(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask));
3078  }
3079  j(cc, condition_met, condition_met_distance);
3080 }
3081 
3082 
3083 void MacroAssembler::CheckPageFlagForMap(
3084  Handle<Map> map,
3085  int mask,
3086  Condition cc,
3087  Label* condition_met,
3088  Label::Distance condition_met_distance) {
3089  DCHECK(cc == zero || cc == not_zero);
3090  Page* page = Page::FromAddress(map->address());
3091  DCHECK(!serializer_enabled()); // Serializer cannot match page_flags.
3092  ExternalReference reference(ExternalReference::page_flags(page));
3093  // The inlined static address check of the page's flags relies
3094  // on maps never being compacted.
3095  DCHECK(!isolate()->heap()->mark_compact_collector()->
3096  IsOnEvacuationCandidate(*map));
3097  if (mask < (1 << kBitsPerByte)) {
3098  test_b(Operand::StaticVariable(reference), static_cast<uint8_t>(mask));
3099  } else {
3100  test(Operand::StaticVariable(reference), Immediate(mask));
3101  }
3102  j(cc, condition_met, condition_met_distance);
3103 }
3104 
3105 
3106 void MacroAssembler::CheckMapDeprecated(Handle<Map> map,
3107  Register scratch,
3108  Label* if_deprecated) {
3109  if (map->CanBeDeprecated()) {
3110  mov(scratch, map);
3111  mov(scratch, FieldOperand(scratch, Map::kBitField3Offset));
3112  and_(scratch, Immediate(Map::Deprecated::kMask));
3113  j(not_zero, if_deprecated);
3114  }
3115 }
3116 
3117 
3118 void MacroAssembler::JumpIfBlack(Register object,
3119  Register scratch0,
3120  Register scratch1,
3121  Label* on_black,
3122  Label::Distance on_black_near) {
3123  HasColor(object, scratch0, scratch1,
3124  on_black, on_black_near,
3125  1, 0); // kBlackBitPattern.
3126  DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0);
3127 }
3128 
3129 
3130 void MacroAssembler::HasColor(Register object,
3131  Register bitmap_scratch,
3132  Register mask_scratch,
3133  Label* has_color,
3134  Label::Distance has_color_distance,
3135  int first_bit,
3136  int second_bit) {
3137  DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, ecx));
3138 
3139  GetMarkBits(object, bitmap_scratch, mask_scratch);
3140 
3141  Label other_color, word_boundary;
3142  test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
3143  j(first_bit == 1 ? zero : not_zero, &other_color, Label::kNear);
3144  add(mask_scratch, mask_scratch); // Shift left 1 by adding.
3145  j(zero, &word_boundary, Label::kNear);
3146  test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
3147  j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance);
3148  jmp(&other_color, Label::kNear);
3149 
3150  bind(&word_boundary);
3151  test_b(Operand(bitmap_scratch, MemoryChunk::kHeaderSize + kPointerSize), 1);
3152 
3153  j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance);
3154  bind(&other_color);
3155 }
3156 
3157 
3158 void MacroAssembler::GetMarkBits(Register addr_reg,
3159  Register bitmap_reg,
3160  Register mask_reg) {
3161  DCHECK(!AreAliased(addr_reg, mask_reg, bitmap_reg, ecx));
3162  mov(bitmap_reg, Immediate(~Page::kPageAlignmentMask));
3163  and_(bitmap_reg, addr_reg);
3164  mov(ecx, addr_reg);
3165  int shift =
3166  Bitmap::kBitsPerCellLog2 + kPointerSizeLog2 - Bitmap::kBytesPerCellLog2;
3167  shr(ecx, shift);
3168  and_(ecx,
3169  (Page::kPageAlignmentMask >> shift) & ~(Bitmap::kBytesPerCell - 1));
3170 
3171  add(bitmap_reg, ecx);
3172  mov(ecx, addr_reg);
3173  shr(ecx, kPointerSizeLog2);
3174  and_(ecx, (1 << Bitmap::kBitsPerCellLog2) - 1);
3175  mov(mask_reg, Immediate(1));
3176  shl_cl(mask_reg);
3177 }
3178 
3179 
3180 void MacroAssembler::EnsureNotWhite(
3181  Register value,
3182  Register bitmap_scratch,
3183  Register mask_scratch,
3184  Label* value_is_white_and_not_data,
3185  Label::Distance distance) {
3186  DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, ecx));
3187  GetMarkBits(value, bitmap_scratch, mask_scratch);
3188 
3189  // If the value is black or grey we don't need to do anything.
3190  DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0);
3191  DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0);
3192  DCHECK(strcmp(Marking::kGreyBitPattern, "11") == 0);
3193  DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
3194 
3195  Label done;
3196 
3197  // Since both black and grey have a 1 in the first position and white does
3198  // not have a 1 there we only need to check one bit.
3199  test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
3200  j(not_zero, &done, Label::kNear);
3201 
3202  if (emit_debug_code()) {
3203  // Check for impossible bit pattern.
3204  Label ok;
3205  push(mask_scratch);
3206  // shl. May overflow making the check conservative.
3207  add(mask_scratch, mask_scratch);
3208  test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
3209  j(zero, &ok, Label::kNear);
3210  int3();
3211  bind(&ok);
3212  pop(mask_scratch);
3213  }
3214 
3215  // Value is white. We check whether it is data that doesn't need scanning.
3216  // Currently only checks for HeapNumber and non-cons strings.
3217  Register map = ecx; // Holds map while checking type.
3218  Register length = ecx; // Holds length of object after checking type.
3219  Label not_heap_number;
3220  Label is_data_object;
3221 
3222  // Check for heap-number
3223  mov(map, FieldOperand(value, HeapObject::kMapOffset));
3224  cmp(map, isolate()->factory()->heap_number_map());
3225  j(not_equal, &not_heap_number, Label::kNear);
3226  mov(length, Immediate(HeapNumber::kSize));
3227  jmp(&is_data_object, Label::kNear);
3228 
3229  bind(&not_heap_number);
3230  // Check for strings.
3232  DCHECK(kNotStringTag == 0x80 && kIsNotStringMask == 0x80);
3233  // If it's a string and it's not a cons string then it's an object containing
3234  // no GC pointers.
3235  Register instance_type = ecx;
3236  movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
3237  test_b(instance_type, kIsIndirectStringMask | kIsNotStringMask);
3238  j(not_zero, value_is_white_and_not_data);
3239  // It's a non-indirect (non-cons and non-slice) string.
3240  // If it's external, the length is just ExternalString::kSize.
3241  // Otherwise it's String::kHeaderSize + string->length() * (1 or 2).
3242  Label not_external;
3243  // External strings are the only ones with the kExternalStringTag bit
3244  // set.
3247  test_b(instance_type, kExternalStringTag);
3248  j(zero, &not_external, Label::kNear);
3249  mov(length, Immediate(ExternalString::kSize));
3250  jmp(&is_data_object, Label::kNear);
3251 
3252  bind(&not_external);
3253  // Sequential string, either Latin1 or UC16.
3254  DCHECK(kOneByteStringTag == 0x04);
3255  and_(length, Immediate(kStringEncodingMask));
3256  xor_(length, Immediate(kStringEncodingMask));
3257  add(length, Immediate(0x04));
3258  // Value now either 4 (if Latin1) or 8 (if UC16), i.e., char-size shifted
3259  // by 2. If we multiply the string length as smi by this, it still
3260  // won't overflow a 32-bit value.
3261  DCHECK_EQ(SeqOneByteString::kMaxSize, SeqTwoByteString::kMaxSize);
3262  DCHECK(SeqOneByteString::kMaxSize <=
3263  static_cast<int>(0xffffffffu >> (2 + kSmiTagSize)));
3264  imul(length, FieldOperand(value, String::kLengthOffset));
3265  shr(length, 2 + kSmiTagSize + kSmiShiftSize);
3266  add(length, Immediate(SeqString::kHeaderSize + kObjectAlignmentMask));
3267  and_(length, Immediate(~kObjectAlignmentMask));
3268 
3269  bind(&is_data_object);
3270  // Value is a data object, and it is white. Mark it black. Since we know
3271  // that the object is white we can make it black by flipping one bit.
3272  or_(Operand(bitmap_scratch, MemoryChunk::kHeaderSize), mask_scratch);
3273 
3274  and_(bitmap_scratch, Immediate(~Page::kPageAlignmentMask));
3275  add(Operand(bitmap_scratch, MemoryChunk::kLiveBytesOffset),
3276  length);
3277  if (emit_debug_code()) {
3278  mov(length, Operand(bitmap_scratch, MemoryChunk::kLiveBytesOffset));
3279  cmp(length, Operand(bitmap_scratch, MemoryChunk::kSizeOffset));
3280  Check(less_equal, kLiveBytesCountOverflowChunkSize);
3281  }
3282 
3283  bind(&done);
3284 }
3285 
3286 
3287 void MacroAssembler::EnumLength(Register dst, Register map) {
3288  STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
3289  mov(dst, FieldOperand(map, Map::kBitField3Offset));
3290  and_(dst, Immediate(Map::EnumLengthBits::kMask));
3291  SmiTag(dst);
3292 }
3293 
3294 
3295 void MacroAssembler::CheckEnumCache(Label* call_runtime) {
3296  Label next, start;
3297  mov(ecx, eax);
3298 
3299  // Check if the enum length field is properly initialized, indicating that
3300  // there is an enum cache.
3301  mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
3302 
3303  EnumLength(edx, ebx);
3304  cmp(edx, Immediate(Smi::FromInt(kInvalidEnumCacheSentinel)));
3305  j(equal, call_runtime);
3306 
3307  jmp(&start);
3308 
3309  bind(&next);
3310  mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
3311 
3312  // For all objects but the receiver, check that the cache is empty.
3313  EnumLength(edx, ebx);
3314  cmp(edx, Immediate(Smi::FromInt(0)));
3315  j(not_equal, call_runtime);
3316 
3317  bind(&start);
3318 
3319  // Check that there are no elements. Register rcx contains the current JS
3320  // object we've reached through the prototype chain.
3321  Label no_elements;
3322  mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset));
3323  cmp(ecx, isolate()->factory()->empty_fixed_array());
3324  j(equal, &no_elements);
3325 
3326  // Second chance, the object may be using the empty slow element dictionary.
3327  cmp(ecx, isolate()->factory()->empty_slow_element_dictionary());
3328  j(not_equal, call_runtime);
3329 
3330  bind(&no_elements);
3331  mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
3332  cmp(ecx, isolate()->factory()->null_value());
3333  j(not_equal, &next);
3334 }
3335 
3336 
3337 void MacroAssembler::TestJSArrayForAllocationMemento(
3338  Register receiver_reg,
3339  Register scratch_reg,
3340  Label* no_memento_found) {
3341  ExternalReference new_space_start =
3342  ExternalReference::new_space_start(isolate());
3343  ExternalReference new_space_allocation_top =
3344  ExternalReference::new_space_allocation_top_address(isolate());
3345 
3346  lea(scratch_reg, Operand(receiver_reg,
3347  JSArray::kSize + AllocationMemento::kSize - kHeapObjectTag));
3348  cmp(scratch_reg, Immediate(new_space_start));
3349  j(less, no_memento_found);
3350  cmp(scratch_reg, Operand::StaticVariable(new_space_allocation_top));
3351  j(greater, no_memento_found);
3352  cmp(MemOperand(scratch_reg, -AllocationMemento::kSize),
3353  Immediate(isolate()->factory()->allocation_memento_map()));
3354 }
3355 
3356 
3357 void MacroAssembler::JumpIfDictionaryInPrototypeChain(
3358  Register object,
3359  Register scratch0,
3360  Register scratch1,
3361  Label* found) {
3362  DCHECK(!scratch1.is(scratch0));
3363  Factory* factory = isolate()->factory();
3364  Register current = scratch0;
3365  Label loop_again;
3366 
3367  // scratch contained elements pointer.
3368  mov(current, object);
3369 
3370  // Loop based on the map going up the prototype chain.
3371  bind(&loop_again);
3372  mov(current, FieldOperand(current, HeapObject::kMapOffset));
3373  mov(scratch1, FieldOperand(current, Map::kBitField2Offset));
3374  DecodeField<Map::ElementsKindBits>(scratch1);
3375  cmp(scratch1, Immediate(DICTIONARY_ELEMENTS));
3376  j(equal, found);
3377  mov(current, FieldOperand(current, Map::kPrototypeOffset));
3378  cmp(current, Immediate(factory->null_value()));
3379  j(not_equal, &loop_again);
3380 }
3381 
3382 
3383 void MacroAssembler::TruncatingDiv(Register dividend, int32_t divisor) {
3384  DCHECK(!dividend.is(eax));
3385  DCHECK(!dividend.is(edx));
3386  base::MagicNumbersForDivision<uint32_t> mag =
3387  base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
3388  mov(eax, Immediate(mag.multiplier));
3389  imul(dividend);
3390  bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
3391  if (divisor > 0 && neg) add(edx, dividend);
3392  if (divisor < 0 && !neg && mag.multiplier > 0) sub(edx, dividend);
3393  if (mag.shift > 0) sar(edx, mag.shift);
3394  mov(eax, dividend);
3395  shr(eax, 31);
3396  add(edx, eax);
3397 }
3398 
3399 
3400 } } // namespace v8::internal
3401 
3402 #endif // V8_TARGET_ARCH_IA32
MacroAssembler(Isolate *isolate, void *buffer, int size)
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf map
enable harmony numeric enable harmony object literal extensions Optimize object size
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long mode(MIPS only)") DEFINE_BOOL(enable_always_align_csp
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi space(in MBytes)
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
enable harmony numeric enable harmony object literal extensions Optimize object Array shift
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be aligned(ARM64 only)") DEFINE_STRING(expose_gc_as
#define CHECK(condition)
Definition: logging.h:36
#define DCHECK(condition)
Definition: logging.h:205
#define DCHECK_EQ(v1, v2)
Definition: logging.h:206
InvokeFlag
@ JUMP_FUNCTION
@ CALL_FUNCTION
AllocationFlags
@ RESULT_CONTAINS_TOP
@ DOUBLE_ALIGNMENT
@ SIZE_IN_WORDS
@ PRETENURE_OLD_POINTER_SPACE
@ TAG_OBJECT
@ PRETENURE_OLD_DATA_SPACE
#define STATIC_ASSERT(test)
Definition: macros.h:311
int int32_t
Definition: unicode.cc:24
bool IsPowerOfTwo32(uint32_t value)
Definition: bits.h:77
MagicNumbersForDivision< T > SignedDivisionByConstant(T d)
static int Push(SpecialRPOStackFrame *stack, int depth, BasicBlock *child, int unvisited)
Definition: scheduler.cc:773
const intptr_t kHeapObjectTagMask
Definition: v8.h:5739
const int kPointerSize
Definition: globals.h:129
const Register edx
const uint32_t kStringEncodingMask
Definition: objects.h:555
const Register edi
const Register r2
@ DONT_DO_SMI_CHECK
Definition: globals.h:640
@ DO_SMI_CHECK
Definition: globals.h:641
const int kBitsPerInt
Definition: globals.h:165
@ kSeqStringTag
Definition: objects.h:563
@ kConsStringTag
Definition: objects.h:564
@ kExternalStringTag
Definition: objects.h:565
bool AreAliased(const CPURegister &reg1, const CPURegister &reg2, const CPURegister &reg3=NoReg, const CPURegister &reg4=NoReg, const CPURegister &reg5=NoReg, const CPURegister &reg6=NoReg, const CPURegister &reg7=NoReg, const CPURegister &reg8=NoReg)
const Register esp
TypeImpl< ZoneTypeConfig > Type
bool is_uintn(int64_t x, unsigned n)
Definition: utils.h:904
const Register r0
const int kSmiTagSize
Definition: v8.h:5743
const int kNumSafepointRegisters
Definition: frames-arm.h:67
const int kDoubleSize
Definition: globals.h:127
const uint32_t kNotStringTag
Definition: objects.h:545
Operand FieldOperand(Register object, int offset)
const Address kZapValue
Definition: globals.h:269
const int kPointerSizeLog2
Definition: globals.h:147
const uint32_t kStringTag
Definition: objects.h:544
@ LAST_NONCALLABLE_SPEC_OBJECT_TYPE
Definition: objects.h:785
@ FIRST_NONCALLABLE_SPEC_OBJECT_TYPE
Definition: objects.h:784
@ FIRST_NONSTRING_TYPE
Definition: objects.h:758
@ LAST_NAME_TYPE
Definition: objects.h:755
@ FIRST_SPEC_OBJECT_TYPE
Definition: objects.h:781
@ JS_FUNCTION_TYPE
Definition: objects.h:749
@ FAST_HOLEY_SMI_ELEMENTS
Definition: elements-kind.h:17
const uint32_t kOneByteStringTag
Definition: objects.h:557
const intptr_t kObjectAlignmentMask
Definition: globals.h:227
const Register esi
@ FAIL_ON_MINUS_ZERO
Definition: globals.h:768
const Register eax
const int kShortSize
Definition: globals.h:123
const Register ebx
int NumRegs(RegList reglist)
Definition: frames.cc:1582
static const int kInvalidEnumCacheSentinel
const XMMRegister xmm0
const char * GetBailoutReason(BailoutReason reason)
Condition NegateCondition(Condition cond)
Definition: constants-arm.h:86
const uint32_t kStringRepresentationMask
Definition: objects.h:561
uint32_t RegList
Definition: frames.h:18
const Register r1
OStream & dec(OStream &os)
Definition: ostreams.cc:122
const int kHeapObjectTag
Definition: v8.h:5737
const int kSmiShiftSize
Definition: v8.h:5805
const Register no_reg
const uint32_t kIsIndirectStringTag
Definition: objects.h:569
int TenToThe(int exponent)
Definition: utils.h:733
kFeedbackVectorOffset flag
Definition: objects-inl.h:5418
const uint32_t kInternalizedTag
Definition: objects.h:551
static const int kNumberDictionaryProbes
Definition: codegen.h:149
const int kBitsPerByte
Definition: globals.h:162
const intptr_t kSmiTagMask
Definition: v8.h:5744
const uint32_t kIsNotInternalizedMask
Definition: objects.h:549
const Register ebp
Operand ApiParameterOperand(int index)
const uint32_t kNaNOrInfinityLowerBoundUpper32
Definition: globals.h:658
bool is_intn(int64_t x, unsigned n)
Definition: utils.h:898
const int kSmiTag
Definition: v8.h:5742
static const int kNoCodeAgeSequenceLength
const uint32_t kHoleNanLower32
Definition: globals.h:657
const uint32_t kIsNotStringMask
Definition: objects.h:543
bool IsAligned(T value, U alignment)
Definition: utils.h:123
const int kCharSize
Definition: globals.h:122
const intptr_t kDoubleAlignment
Definition: globals.h:234
@ kPointersToHereAreAlwaysInteresting
const intptr_t kPointerAlignment
Definition: globals.h:230
void CopyBytes(uint8_t *target, uint8_t *source)
const intptr_t kDoubleAlignmentMask
Definition: globals.h:235
const uint32_t kIsIndirectStringMask
Definition: objects.h:568
PerThreadAssertScopeDebugOnly< DEFERRED_HANDLE_DEREFERENCE_ASSERT, true > AllowDeferredHandleDereference
Definition: assert-scope.h:130
const Register ecx
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
static Handle< Value > Throw(Isolate *isolate, const char *message)
Definition: d8.cc:72
@ NONE
bool is(Register reg) const