blob: ef9691242ae843b491afd1ec5c3411441256845e [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#if V8_TARGET_ARCH_X87
6
7#include "src/base/bits.h"
8#include "src/base/division-by-constant.h"
9#include "src/bootstrapper.h"
10#include "src/codegen.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011#include "src/debug/debug.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012#include "src/runtime/runtime.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013#include "src/x87/frames-x87.h"
14#include "src/x87/macro-assembler-x87.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015
16namespace v8 {
17namespace internal {
18
19// -------------------------------------------------------------------------
20// MacroAssembler implementation.
21
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000022MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size,
23 CodeObjectRequired create_code_object)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024 : Assembler(arg_isolate, buffer, size),
25 generating_stub_(false),
26 has_frame_(false) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000027 if (create_code_object == CodeObjectRequired::kYes) {
28 code_object_ =
29 Handle<Object>::New(isolate()->heap()->undefined_value(), isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030 }
31}
32
33
34void MacroAssembler::Load(Register dst, const Operand& src, Representation r) {
35 DCHECK(!r.IsDouble());
36 if (r.IsInteger8()) {
37 movsx_b(dst, src);
38 } else if (r.IsUInteger8()) {
39 movzx_b(dst, src);
40 } else if (r.IsInteger16()) {
41 movsx_w(dst, src);
42 } else if (r.IsUInteger16()) {
43 movzx_w(dst, src);
44 } else {
45 mov(dst, src);
46 }
47}
48
49
50void MacroAssembler::Store(Register src, const Operand& dst, Representation r) {
51 DCHECK(!r.IsDouble());
52 if (r.IsInteger8() || r.IsUInteger8()) {
53 mov_b(dst, src);
54 } else if (r.IsInteger16() || r.IsUInteger16()) {
55 mov_w(dst, src);
56 } else {
57 if (r.IsHeapObject()) {
58 AssertNotSmi(src);
59 } else if (r.IsSmi()) {
60 AssertSmi(src);
61 }
62 mov(dst, src);
63 }
64}
65
66
67void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index) {
68 if (isolate()->heap()->RootCanBeTreatedAsConstant(index)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000069 mov(destination, isolate()->heap()->root_handle(index));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000070 return;
71 }
72 ExternalReference roots_array_start =
73 ExternalReference::roots_array_start(isolate());
74 mov(destination, Immediate(index));
75 mov(destination, Operand::StaticArray(destination,
76 times_pointer_size,
77 roots_array_start));
78}
79
80
81void MacroAssembler::StoreRoot(Register source,
82 Register scratch,
83 Heap::RootListIndex index) {
84 DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
85 ExternalReference roots_array_start =
86 ExternalReference::roots_array_start(isolate());
87 mov(scratch, Immediate(index));
88 mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start),
89 source);
90}
91
92
93void MacroAssembler::CompareRoot(Register with,
94 Register scratch,
95 Heap::RootListIndex index) {
96 ExternalReference roots_array_start =
97 ExternalReference::roots_array_start(isolate());
98 mov(scratch, Immediate(index));
99 cmp(with, Operand::StaticArray(scratch,
100 times_pointer_size,
101 roots_array_start));
102}
103
104
105void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) {
106 DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000107 cmp(with, isolate()->heap()->root_handle(index));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000108}
109
110
111void MacroAssembler::CompareRoot(const Operand& with,
112 Heap::RootListIndex index) {
113 DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000114 cmp(with, isolate()->heap()->root_handle(index));
115}
116
117
118void MacroAssembler::PushRoot(Heap::RootListIndex index) {
119 DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(index));
120 Push(isolate()->heap()->root_handle(index));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000121}
122
Ben Murdoch097c5b22016-05-18 11:27:45 +0100123#define REG(Name) \
124 { Register::kCode_##Name }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000125
Ben Murdoch097c5b22016-05-18 11:27:45 +0100126static const Register saved_regs[] = {REG(eax), REG(ecx), REG(edx)};
127
128#undef REG
129
130static const int kNumberOfSavedRegs = sizeof(saved_regs) / sizeof(Register);
131
132void MacroAssembler::PushCallerSaved(SaveFPRegsMode fp_mode,
133 Register exclusion1, Register exclusion2,
134 Register exclusion3) {
135 // We don't allow a GC during a store buffer overflow so there is no need to
136 // store the registers in any particular way, but we do have to store and
137 // restore them.
138 for (int i = 0; i < kNumberOfSavedRegs; i++) {
139 Register reg = saved_regs[i];
140 if (!reg.is(exclusion1) && !reg.is(exclusion2) && !reg.is(exclusion3)) {
141 push(reg);
142 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000143 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100144 if (fp_mode == kSaveFPRegs) {
145 // Save FPU state in m108byte.
146 sub(esp, Immediate(108));
147 fnsave(Operand(esp, 0));
148 }
149}
150
151void MacroAssembler::PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1,
152 Register exclusion2, Register exclusion3) {
153 if (fp_mode == kSaveFPRegs) {
154 // Restore FPU state in m108byte.
155 frstor(Operand(esp, 0));
156 add(esp, Immediate(108));
157 }
158
159 for (int i = kNumberOfSavedRegs - 1; i >= 0; i--) {
160 Register reg = saved_regs[i];
161 if (!reg.is(exclusion1) && !reg.is(exclusion2) && !reg.is(exclusion3)) {
162 pop(reg);
163 }
164 }
165}
166
167void MacroAssembler::InNewSpace(Register object, Register scratch, Condition cc,
168 Label* condition_met,
169 Label::Distance distance) {
170 const int mask =
171 (1 << MemoryChunk::IN_FROM_SPACE) | (1 << MemoryChunk::IN_TO_SPACE);
172 CheckPageFlag(object, scratch, mask, cc, condition_met, distance);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000173}
174
175
176void MacroAssembler::RememberedSetHelper(
177 Register object, // Only used for debug checks.
178 Register addr, Register scratch, SaveFPRegsMode save_fp,
179 MacroAssembler::RememberedSetFinalAction and_then) {
180 Label done;
181 if (emit_debug_code()) {
182 Label ok;
183 JumpIfNotInNewSpace(object, scratch, &ok, Label::kNear);
184 int3();
185 bind(&ok);
186 }
187 // Load store buffer top.
188 ExternalReference store_buffer =
189 ExternalReference::store_buffer_top(isolate());
190 mov(scratch, Operand::StaticVariable(store_buffer));
191 // Store pointer to buffer.
192 mov(Operand(scratch, 0), addr);
193 // Increment buffer top.
194 add(scratch, Immediate(kPointerSize));
195 // Write back new top of buffer.
196 mov(Operand::StaticVariable(store_buffer), scratch);
197 // Call stub on end of buffer.
198 // Check for end of buffer.
Ben Murdochda12d292016-06-02 14:46:10 +0100199 test(scratch, Immediate(StoreBuffer::kStoreBufferMask));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000200 if (and_then == kReturnAtEnd) {
201 Label buffer_overflowed;
Ben Murdochda12d292016-06-02 14:46:10 +0100202 j(equal, &buffer_overflowed, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000203 ret(0);
204 bind(&buffer_overflowed);
205 } else {
206 DCHECK(and_then == kFallThroughAtEnd);
Ben Murdochda12d292016-06-02 14:46:10 +0100207 j(not_equal, &done, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000208 }
209 StoreBufferOverflowStub store_buffer_overflow(isolate(), save_fp);
210 CallStub(&store_buffer_overflow);
211 if (and_then == kReturnAtEnd) {
212 ret(0);
213 } else {
214 DCHECK(and_then == kFallThroughAtEnd);
215 bind(&done);
216 }
217}
218
219
220void MacroAssembler::ClampTOSToUint8(Register result_reg) {
221 Label done, conv_failure;
222 sub(esp, Immediate(kPointerSize));
223 fnclex();
224 fist_s(Operand(esp, 0));
225 pop(result_reg);
226 X87CheckIA();
227 j(equal, &conv_failure, Label::kNear);
228 test(result_reg, Immediate(0xFFFFFF00));
229 j(zero, &done, Label::kNear);
230 setcc(sign, result_reg);
231 sub(result_reg, Immediate(1));
232 and_(result_reg, Immediate(255));
233 jmp(&done, Label::kNear);
234 bind(&conv_failure);
235 fnclex();
236 fldz();
237 fld(1);
238 FCmp();
239 setcc(below, result_reg); // 1 if negative, 0 if positive.
240 dec_b(result_reg); // 0 if negative, 255 if positive.
241 bind(&done);
242}
243
244
245void MacroAssembler::ClampUint8(Register reg) {
246 Label done;
247 test(reg, Immediate(0xFFFFFF00));
248 j(zero, &done, Label::kNear);
249 setcc(negative, reg); // 1 if negative, 0 if positive.
250 dec_b(reg); // 0 if negative, 255 if positive.
251 bind(&done);
252}
253
254
255void MacroAssembler::SlowTruncateToI(Register result_reg,
256 Register input_reg,
257 int offset) {
258 DoubleToIStub stub(isolate(), input_reg, result_reg, offset, true);
259 call(stub.GetCode(), RelocInfo::CODE_TARGET);
260}
261
262
263void MacroAssembler::TruncateX87TOSToI(Register result_reg) {
264 sub(esp, Immediate(kDoubleSize));
265 fst_d(MemOperand(esp, 0));
266 SlowTruncateToI(result_reg, esp, 0);
267 add(esp, Immediate(kDoubleSize));
268}
269
270
271void MacroAssembler::X87TOSToI(Register result_reg,
272 MinusZeroMode minus_zero_mode,
273 Label* lost_precision, Label* is_nan,
274 Label* minus_zero, Label::Distance dst) {
275 Label done;
276 sub(esp, Immediate(kPointerSize));
277 fld(0);
278 fist_s(MemOperand(esp, 0));
279 fild_s(MemOperand(esp, 0));
280 pop(result_reg);
281 FCmp();
282 j(not_equal, lost_precision, dst);
283 j(parity_even, is_nan, dst);
284 if (minus_zero_mode == FAIL_ON_MINUS_ZERO) {
285 test(result_reg, Operand(result_reg));
286 j(not_zero, &done, Label::kNear);
287 // To check for minus zero, we load the value again as float, and check
288 // if that is still 0.
289 sub(esp, Immediate(kPointerSize));
290 fst_s(MemOperand(esp, 0));
291 pop(result_reg);
292 test(result_reg, Operand(result_reg));
293 j(not_zero, minus_zero, dst);
294 }
295 bind(&done);
296}
297
298
299void MacroAssembler::TruncateHeapNumberToI(Register result_reg,
300 Register input_reg) {
301 Label done, slow_case;
302
303 SlowTruncateToI(result_reg, input_reg);
304 bind(&done);
305}
306
307
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400308void MacroAssembler::LoadUint32NoSSE2(const Operand& src) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000309 Label done;
310 push(src);
311 fild_s(Operand(esp, 0));
312 cmp(src, Immediate(0));
313 j(not_sign, &done, Label::kNear);
314 ExternalReference uint32_bias =
315 ExternalReference::address_of_uint32_bias();
316 fld_d(Operand::StaticVariable(uint32_bias));
317 faddp(1);
318 bind(&done);
319 add(esp, Immediate(kPointerSize));
320}
321
322
323void MacroAssembler::RecordWriteArray(
324 Register object, Register value, Register index, SaveFPRegsMode save_fp,
325 RememberedSetAction remembered_set_action, SmiCheck smi_check,
326 PointersToHereCheck pointers_to_here_check_for_value) {
327 // First, check if a write barrier is even needed. The tests below
328 // catch stores of Smis.
329 Label done;
330
331 // Skip barrier if writing a smi.
332 if (smi_check == INLINE_SMI_CHECK) {
333 DCHECK_EQ(0, kSmiTag);
334 test(value, Immediate(kSmiTagMask));
335 j(zero, &done);
336 }
337
338 // Array access: calculate the destination address in the same manner as
339 // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset
340 // into an array of words.
341 Register dst = index;
342 lea(dst, Operand(object, index, times_half_pointer_size,
343 FixedArray::kHeaderSize - kHeapObjectTag));
344
345 RecordWrite(object, dst, value, save_fp, remembered_set_action,
346 OMIT_SMI_CHECK, pointers_to_here_check_for_value);
347
348 bind(&done);
349
350 // Clobber clobbered input registers when running with the debug-code flag
351 // turned on to provoke errors.
352 if (emit_debug_code()) {
353 mov(value, Immediate(bit_cast<int32_t>(kZapValue)));
354 mov(index, Immediate(bit_cast<int32_t>(kZapValue)));
355 }
356}
357
358
359void MacroAssembler::RecordWriteField(
360 Register object, int offset, Register value, Register dst,
361 SaveFPRegsMode save_fp, RememberedSetAction remembered_set_action,
362 SmiCheck smi_check, PointersToHereCheck pointers_to_here_check_for_value) {
363 // First, check if a write barrier is even needed. The tests below
364 // catch stores of Smis.
365 Label done;
366
367 // Skip barrier if writing a smi.
368 if (smi_check == INLINE_SMI_CHECK) {
369 JumpIfSmi(value, &done, Label::kNear);
370 }
371
372 // Although the object register is tagged, the offset is relative to the start
373 // of the object, so so offset must be a multiple of kPointerSize.
374 DCHECK(IsAligned(offset, kPointerSize));
375
376 lea(dst, FieldOperand(object, offset));
377 if (emit_debug_code()) {
378 Label ok;
Ben Murdochda12d292016-06-02 14:46:10 +0100379 test_b(dst, Immediate((1 << kPointerSizeLog2) - 1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000380 j(zero, &ok, Label::kNear);
381 int3();
382 bind(&ok);
383 }
384
385 RecordWrite(object, dst, value, save_fp, remembered_set_action,
386 OMIT_SMI_CHECK, pointers_to_here_check_for_value);
387
388 bind(&done);
389
390 // Clobber clobbered input registers when running with the debug-code flag
391 // turned on to provoke errors.
392 if (emit_debug_code()) {
393 mov(value, Immediate(bit_cast<int32_t>(kZapValue)));
394 mov(dst, Immediate(bit_cast<int32_t>(kZapValue)));
395 }
396}
397
398
399void MacroAssembler::RecordWriteForMap(Register object, Handle<Map> map,
400 Register scratch1, Register scratch2,
401 SaveFPRegsMode save_fp) {
402 Label done;
403
404 Register address = scratch1;
405 Register value = scratch2;
406 if (emit_debug_code()) {
407 Label ok;
408 lea(address, FieldOperand(object, HeapObject::kMapOffset));
Ben Murdochda12d292016-06-02 14:46:10 +0100409 test_b(address, Immediate((1 << kPointerSizeLog2) - 1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000410 j(zero, &ok, Label::kNear);
411 int3();
412 bind(&ok);
413 }
414
415 DCHECK(!object.is(value));
416 DCHECK(!object.is(address));
417 DCHECK(!value.is(address));
418 AssertNotSmi(object);
419
420 if (!FLAG_incremental_marking) {
421 return;
422 }
423
424 // Compute the address.
425 lea(address, FieldOperand(object, HeapObject::kMapOffset));
426
427 // A single check of the map's pages interesting flag suffices, since it is
428 // only set during incremental collection, and then it's also guaranteed that
429 // the from object's page's interesting flag is also set. This optimization
430 // relies on the fact that maps can never be in new space.
431 DCHECK(!isolate()->heap()->InNewSpace(*map));
432 CheckPageFlagForMap(map,
433 MemoryChunk::kPointersToHereAreInterestingMask,
434 zero,
435 &done,
436 Label::kNear);
437
438 RecordWriteStub stub(isolate(), object, value, address, OMIT_REMEMBERED_SET,
439 save_fp);
440 CallStub(&stub);
441
442 bind(&done);
443
444 // Count number of write barriers in generated code.
445 isolate()->counters()->write_barriers_static()->Increment();
446 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1);
447
448 // Clobber clobbered input registers when running with the debug-code flag
449 // turned on to provoke errors.
450 if (emit_debug_code()) {
451 mov(value, Immediate(bit_cast<int32_t>(kZapValue)));
452 mov(scratch1, Immediate(bit_cast<int32_t>(kZapValue)));
453 mov(scratch2, Immediate(bit_cast<int32_t>(kZapValue)));
454 }
455}
456
457
458void MacroAssembler::RecordWrite(
459 Register object, Register address, Register value, SaveFPRegsMode fp_mode,
460 RememberedSetAction remembered_set_action, SmiCheck smi_check,
461 PointersToHereCheck pointers_to_here_check_for_value) {
462 DCHECK(!object.is(value));
463 DCHECK(!object.is(address));
464 DCHECK(!value.is(address));
465 AssertNotSmi(object);
466
467 if (remembered_set_action == OMIT_REMEMBERED_SET &&
468 !FLAG_incremental_marking) {
469 return;
470 }
471
472 if (emit_debug_code()) {
473 Label ok;
474 cmp(value, Operand(address, 0));
475 j(equal, &ok, Label::kNear);
476 int3();
477 bind(&ok);
478 }
479
480 // First, check if a write barrier is even needed. The tests below
481 // catch stores of Smis and stores into young gen.
482 Label done;
483
484 if (smi_check == INLINE_SMI_CHECK) {
485 // Skip barrier if writing a smi.
486 JumpIfSmi(value, &done, Label::kNear);
487 }
488
489 if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) {
490 CheckPageFlag(value,
491 value, // Used as scratch.
492 MemoryChunk::kPointersToHereAreInterestingMask,
493 zero,
494 &done,
495 Label::kNear);
496 }
497 CheckPageFlag(object,
498 value, // Used as scratch.
499 MemoryChunk::kPointersFromHereAreInterestingMask,
500 zero,
501 &done,
502 Label::kNear);
503
504 RecordWriteStub stub(isolate(), object, value, address, remembered_set_action,
505 fp_mode);
506 CallStub(&stub);
507
508 bind(&done);
509
510 // Count number of write barriers in generated code.
511 isolate()->counters()->write_barriers_static()->Increment();
512 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1);
513
514 // Clobber clobbered registers when running with the debug-code flag
515 // turned on to provoke errors.
516 if (emit_debug_code()) {
517 mov(address, Immediate(bit_cast<int32_t>(kZapValue)));
518 mov(value, Immediate(bit_cast<int32_t>(kZapValue)));
519 }
520}
521
Ben Murdoch097c5b22016-05-18 11:27:45 +0100522void MacroAssembler::RecordWriteCodeEntryField(Register js_function,
523 Register code_entry,
524 Register scratch) {
525 const int offset = JSFunction::kCodeEntryOffset;
526
527 // Since a code entry (value) is always in old space, we don't need to update
528 // remembered set. If incremental marking is off, there is nothing for us to
529 // do.
530 if (!FLAG_incremental_marking) return;
531
532 DCHECK(!js_function.is(code_entry));
533 DCHECK(!js_function.is(scratch));
534 DCHECK(!code_entry.is(scratch));
535 AssertNotSmi(js_function);
536
537 if (emit_debug_code()) {
538 Label ok;
539 lea(scratch, FieldOperand(js_function, offset));
540 cmp(code_entry, Operand(scratch, 0));
541 j(equal, &ok, Label::kNear);
542 int3();
543 bind(&ok);
544 }
545
546 // First, check if a write barrier is even needed. The tests below
547 // catch stores of Smis and stores into young gen.
548 Label done;
549
550 CheckPageFlag(code_entry, scratch,
551 MemoryChunk::kPointersToHereAreInterestingMask, zero, &done,
552 Label::kNear);
553 CheckPageFlag(js_function, scratch,
554 MemoryChunk::kPointersFromHereAreInterestingMask, zero, &done,
555 Label::kNear);
556
557 // Save input registers.
558 push(js_function);
559 push(code_entry);
560
561 const Register dst = scratch;
562 lea(dst, FieldOperand(js_function, offset));
563
564 // Save caller-saved registers.
565 PushCallerSaved(kDontSaveFPRegs, js_function, code_entry);
566
567 int argument_count = 3;
568 PrepareCallCFunction(argument_count, code_entry);
569 mov(Operand(esp, 0 * kPointerSize), js_function);
570 mov(Operand(esp, 1 * kPointerSize), dst); // Slot.
571 mov(Operand(esp, 2 * kPointerSize),
572 Immediate(ExternalReference::isolate_address(isolate())));
573
574 {
575 AllowExternalCallThatCantCauseGC scope(this);
576 CallCFunction(
577 ExternalReference::incremental_marking_record_write_code_entry_function(
578 isolate()),
579 argument_count);
580 }
581
582 // Restore caller-saved registers.
583 PopCallerSaved(kDontSaveFPRegs, js_function, code_entry);
584
585 // Restore input registers.
586 pop(code_entry);
587 pop(js_function);
588
589 bind(&done);
590}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000591
592void MacroAssembler::DebugBreak() {
593 Move(eax, Immediate(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000594 mov(ebx, Immediate(ExternalReference(Runtime::kHandleDebuggerStatement,
595 isolate())));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000596 CEntryStub ces(isolate(), 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000597 call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000598}
599
Ben Murdochda12d292016-06-02 14:46:10 +0100600void MacroAssembler::ShlPair(Register high, Register low, uint8_t shift) {
601 if (shift >= 32) {
602 mov(high, low);
603 shl(high, shift - 32);
604 xor_(low, low);
605 } else {
606 shld(high, low, shift);
607 shl(low, shift);
608 }
609}
610
611void MacroAssembler::ShlPair_cl(Register high, Register low) {
612 shld_cl(high, low);
613 shl_cl(low);
614 Label done;
615 test(ecx, Immediate(0x20));
616 j(equal, &done, Label::kNear);
617 mov(high, low);
618 xor_(low, low);
619 bind(&done);
620}
621
622void MacroAssembler::ShrPair(Register high, Register low, uint8_t shift) {
623 if (shift >= 32) {
624 mov(low, high);
625 shr(low, shift - 32);
626 xor_(high, high);
627 } else {
628 shrd(high, low, shift);
629 shr(high, shift);
630 }
631}
632
633void MacroAssembler::ShrPair_cl(Register high, Register low) {
634 shrd_cl(low, high);
635 shr_cl(high);
636 Label done;
637 test(ecx, Immediate(0x20));
638 j(equal, &done, Label::kNear);
639 mov(low, high);
640 xor_(high, high);
641 bind(&done);
642}
643
644void MacroAssembler::SarPair(Register high, Register low, uint8_t shift) {
645 if (shift >= 32) {
646 mov(low, high);
647 sar(low, shift - 32);
648 sar(high, 31);
649 } else {
650 shrd(high, low, shift);
651 sar(high, shift);
652 }
653}
654
655void MacroAssembler::SarPair_cl(Register high, Register low) {
656 shrd_cl(low, high);
657 sar_cl(high);
658 Label done;
659 test(ecx, Immediate(0x20));
660 j(equal, &done, Label::kNear);
661 mov(low, high);
662 sar(high, 31);
663 bind(&done);
664}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000665
666bool MacroAssembler::IsUnsafeImmediate(const Immediate& x) {
667 static const int kMaxImmediateBits = 17;
668 if (!RelocInfo::IsNone(x.rmode_)) return false;
669 return !is_intn(x.x_, kMaxImmediateBits);
670}
671
672
673void MacroAssembler::SafeMove(Register dst, const Immediate& x) {
674 if (IsUnsafeImmediate(x) && jit_cookie() != 0) {
675 Move(dst, Immediate(x.x_ ^ jit_cookie()));
676 xor_(dst, jit_cookie());
677 } else {
678 Move(dst, x);
679 }
680}
681
682
683void MacroAssembler::SafePush(const Immediate& x) {
684 if (IsUnsafeImmediate(x) && jit_cookie() != 0) {
685 push(Immediate(x.x_ ^ jit_cookie()));
686 xor_(Operand(esp, 0), Immediate(jit_cookie()));
687 } else {
688 push(x);
689 }
690}
691
692
693void MacroAssembler::CmpObjectType(Register heap_object,
694 InstanceType type,
695 Register map) {
696 mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
697 CmpInstanceType(map, type);
698}
699
700
701void MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
Ben Murdochda12d292016-06-02 14:46:10 +0100702 cmpb(FieldOperand(map, Map::kInstanceTypeOffset), Immediate(type));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000703}
704
705
706void MacroAssembler::CheckFastElements(Register map,
707 Label* fail,
708 Label::Distance distance) {
709 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
710 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
711 STATIC_ASSERT(FAST_ELEMENTS == 2);
712 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
713 cmpb(FieldOperand(map, Map::kBitField2Offset),
Ben Murdochda12d292016-06-02 14:46:10 +0100714 Immediate(Map::kMaximumBitField2FastHoleyElementValue));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000715 j(above, fail, distance);
716}
717
718
719void MacroAssembler::CheckFastObjectElements(Register map,
720 Label* fail,
721 Label::Distance distance) {
722 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
723 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
724 STATIC_ASSERT(FAST_ELEMENTS == 2);
725 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
726 cmpb(FieldOperand(map, Map::kBitField2Offset),
Ben Murdochda12d292016-06-02 14:46:10 +0100727 Immediate(Map::kMaximumBitField2FastHoleySmiElementValue));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000728 j(below_equal, fail, distance);
729 cmpb(FieldOperand(map, Map::kBitField2Offset),
Ben Murdochda12d292016-06-02 14:46:10 +0100730 Immediate(Map::kMaximumBitField2FastHoleyElementValue));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000731 j(above, fail, distance);
732}
733
734
735void MacroAssembler::CheckFastSmiElements(Register map,
736 Label* fail,
737 Label::Distance distance) {
738 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
739 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
740 cmpb(FieldOperand(map, Map::kBitField2Offset),
Ben Murdochda12d292016-06-02 14:46:10 +0100741 Immediate(Map::kMaximumBitField2FastHoleySmiElementValue));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000742 j(above, fail, distance);
743}
744
745
746void MacroAssembler::StoreNumberToDoubleElements(
747 Register maybe_number,
748 Register elements,
749 Register key,
750 Register scratch,
751 Label* fail,
752 int elements_offset) {
753 Label smi_value, done, maybe_nan, not_nan, is_nan, have_double_value;
754 JumpIfSmi(maybe_number, &smi_value, Label::kNear);
755
756 CheckMap(maybe_number,
757 isolate()->factory()->heap_number_map(),
758 fail,
759 DONT_DO_SMI_CHECK);
760
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000761 fld_d(FieldOperand(maybe_number, HeapNumber::kValueOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000762 jmp(&done, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000763
764 bind(&smi_value);
765 // Value is a smi. Convert to a double and store.
766 // Preserve original value.
767 mov(scratch, maybe_number);
768 SmiUntag(scratch);
769 push(scratch);
770 fild_s(Operand(esp, 0));
771 pop(scratch);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000772 bind(&done);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000773 fstp_d(FieldOperand(elements, key, times_4,
774 FixedDoubleArray::kHeaderSize - elements_offset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000775}
776
777
778void MacroAssembler::CompareMap(Register obj, Handle<Map> map) {
779 cmp(FieldOperand(obj, HeapObject::kMapOffset), map);
780}
781
782
783void MacroAssembler::CheckMap(Register obj,
784 Handle<Map> map,
785 Label* fail,
786 SmiCheckType smi_check_type) {
787 if (smi_check_type == DO_SMI_CHECK) {
788 JumpIfSmi(obj, fail);
789 }
790
791 CompareMap(obj, map);
792 j(not_equal, fail);
793}
794
795
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400796void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1,
797 Register scratch2, Handle<WeakCell> cell,
798 Handle<Code> success,
799 SmiCheckType smi_check_type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000800 Label fail;
801 if (smi_check_type == DO_SMI_CHECK) {
802 JumpIfSmi(obj, &fail);
803 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400804 mov(scratch1, FieldOperand(obj, HeapObject::kMapOffset));
805 CmpWeakValue(scratch1, cell, scratch2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000806 j(equal, success);
807
808 bind(&fail);
809}
810
811
812Condition MacroAssembler::IsObjectStringType(Register heap_object,
813 Register map,
814 Register instance_type) {
815 mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
816 movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
817 STATIC_ASSERT(kNotStringTag != 0);
818 test(instance_type, Immediate(kIsNotStringMask));
819 return zero;
820}
821
822
823Condition MacroAssembler::IsObjectNameType(Register heap_object,
824 Register map,
825 Register instance_type) {
826 mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
827 movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
Ben Murdochda12d292016-06-02 14:46:10 +0100828 cmpb(instance_type, Immediate(LAST_NAME_TYPE));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000829 return below_equal;
830}
831
832
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000833void MacroAssembler::FCmp() {
834 fucompp();
835 push(eax);
836 fnstsw_ax();
837 sahf();
838 pop(eax);
839}
840
841
842void MacroAssembler::FXamMinusZero() {
843 fxam();
844 push(eax);
845 fnstsw_ax();
846 and_(eax, Immediate(0x4700));
847 // For minus zero, C3 == 1 && C1 == 1.
848 cmp(eax, Immediate(0x4200));
849 pop(eax);
850 fstp(0);
851}
852
853
854void MacroAssembler::FXamSign() {
855 fxam();
856 push(eax);
857 fnstsw_ax();
858 // For negative value (including -0.0), C1 == 1.
859 and_(eax, Immediate(0x0200));
860 pop(eax);
861 fstp(0);
862}
863
864
865void MacroAssembler::X87CheckIA() {
866 push(eax);
867 fnstsw_ax();
868 // For #IA, IE == 1 && SF == 0.
869 and_(eax, Immediate(0x0041));
870 cmp(eax, Immediate(0x0001));
871 pop(eax);
872}
873
874
875// rc=00B, round to nearest.
876// rc=01B, round down.
877// rc=10B, round up.
878// rc=11B, round toward zero.
879void MacroAssembler::X87SetRC(int rc) {
880 sub(esp, Immediate(kPointerSize));
881 fnstcw(MemOperand(esp, 0));
882 and_(MemOperand(esp, 0), Immediate(0xF3FF));
883 or_(MemOperand(esp, 0), Immediate(rc));
884 fldcw(MemOperand(esp, 0));
885 add(esp, Immediate(kPointerSize));
886}
887
888
889void MacroAssembler::X87SetFPUCW(int cw) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000890 RecordComment("-- X87SetFPUCW start --");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000891 push(Immediate(cw));
892 fldcw(MemOperand(esp, 0));
893 add(esp, Immediate(kPointerSize));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000894 RecordComment("-- X87SetFPUCW end--");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000895}
896
897
898void MacroAssembler::AssertNumber(Register object) {
899 if (emit_debug_code()) {
900 Label ok;
901 JumpIfSmi(object, &ok);
902 cmp(FieldOperand(object, HeapObject::kMapOffset),
903 isolate()->factory()->heap_number_map());
904 Check(equal, kOperandNotANumber);
905 bind(&ok);
906 }
907}
908
Ben Murdochda12d292016-06-02 14:46:10 +0100909void MacroAssembler::AssertNotNumber(Register object) {
910 if (emit_debug_code()) {
911 test(object, Immediate(kSmiTagMask));
912 Check(not_equal, kOperandIsANumber);
913 cmp(FieldOperand(object, HeapObject::kMapOffset),
914 isolate()->factory()->heap_number_map());
915 Check(not_equal, kOperandIsANumber);
916 }
917}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000918
919void MacroAssembler::AssertSmi(Register object) {
920 if (emit_debug_code()) {
921 test(object, Immediate(kSmiTagMask));
922 Check(equal, kOperandIsNotASmi);
923 }
924}
925
926
927void MacroAssembler::AssertString(Register object) {
928 if (emit_debug_code()) {
929 test(object, Immediate(kSmiTagMask));
930 Check(not_equal, kOperandIsASmiAndNotAString);
931 push(object);
932 mov(object, FieldOperand(object, HeapObject::kMapOffset));
933 CmpInstanceType(object, FIRST_NONSTRING_TYPE);
934 pop(object);
935 Check(below, kOperandIsNotAString);
936 }
937}
938
939
940void MacroAssembler::AssertName(Register object) {
941 if (emit_debug_code()) {
942 test(object, Immediate(kSmiTagMask));
943 Check(not_equal, kOperandIsASmiAndNotAName);
944 push(object);
945 mov(object, FieldOperand(object, HeapObject::kMapOffset));
946 CmpInstanceType(object, LAST_NAME_TYPE);
947 pop(object);
948 Check(below_equal, kOperandIsNotAName);
949 }
950}
951
952
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000953void MacroAssembler::AssertFunction(Register object) {
954 if (emit_debug_code()) {
955 test(object, Immediate(kSmiTagMask));
956 Check(not_equal, kOperandIsASmiAndNotAFunction);
957 Push(object);
958 CmpObjectType(object, JS_FUNCTION_TYPE, object);
959 Pop(object);
960 Check(equal, kOperandIsNotAFunction);
961 }
962}
963
964
965void MacroAssembler::AssertBoundFunction(Register object) {
966 if (emit_debug_code()) {
967 test(object, Immediate(kSmiTagMask));
968 Check(not_equal, kOperandIsASmiAndNotABoundFunction);
969 Push(object);
970 CmpObjectType(object, JS_BOUND_FUNCTION_TYPE, object);
971 Pop(object);
972 Check(equal, kOperandIsNotABoundFunction);
973 }
974}
975
Ben Murdochc5610432016-08-08 18:44:38 +0100976void MacroAssembler::AssertGeneratorObject(Register object) {
977 if (emit_debug_code()) {
978 test(object, Immediate(kSmiTagMask));
979 Check(not_equal, kOperandIsASmiAndNotAGeneratorObject);
980 Push(object);
981 CmpObjectType(object, JS_GENERATOR_OBJECT_TYPE, object);
982 Pop(object);
983 Check(equal, kOperandIsNotAGeneratorObject);
984 }
985}
986
Ben Murdoch097c5b22016-05-18 11:27:45 +0100987void MacroAssembler::AssertReceiver(Register object) {
988 if (emit_debug_code()) {
989 test(object, Immediate(kSmiTagMask));
990 Check(not_equal, kOperandIsASmiAndNotAReceiver);
991 Push(object);
992 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
993 CmpObjectType(object, FIRST_JS_RECEIVER_TYPE, object);
994 Pop(object);
995 Check(above_equal, kOperandIsNotAReceiver);
996 }
997}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000998
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000999void MacroAssembler::AssertUndefinedOrAllocationSite(Register object) {
1000 if (emit_debug_code()) {
1001 Label done_checking;
1002 AssertNotSmi(object);
1003 cmp(object, isolate()->factory()->undefined_value());
1004 j(equal, &done_checking);
1005 cmp(FieldOperand(object, 0),
1006 Immediate(isolate()->factory()->allocation_site_map()));
1007 Assert(equal, kExpectedUndefinedOrCell);
1008 bind(&done_checking);
1009 }
1010}
1011
1012
1013void MacroAssembler::AssertNotSmi(Register object) {
1014 if (emit_debug_code()) {
1015 test(object, Immediate(kSmiTagMask));
1016 Check(not_equal, kOperandIsASmi);
1017 }
1018}
1019
Ben Murdochda12d292016-06-02 14:46:10 +01001020void MacroAssembler::StubPrologue(StackFrame::Type type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001021 push(ebp); // Caller's frame pointer.
1022 mov(ebp, esp);
Ben Murdochda12d292016-06-02 14:46:10 +01001023 push(Immediate(Smi::FromInt(type)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001024}
1025
1026
1027void MacroAssembler::Prologue(bool code_pre_aging) {
1028 PredictableCodeSizeScope predictible_code_size_scope(this,
1029 kNoCodeAgeSequenceLength);
1030 if (code_pre_aging) {
1031 // Pre-age the code.
1032 call(isolate()->builtins()->MarkCodeAsExecutedOnce(),
1033 RelocInfo::CODE_AGE_SEQUENCE);
1034 Nop(kNoCodeAgeSequenceLength - Assembler::kCallInstructionLength);
1035 } else {
1036 push(ebp); // Caller's frame pointer.
1037 mov(ebp, esp);
1038 push(esi); // Callee's context.
1039 push(edi); // Callee's JS function.
1040 }
1041}
1042
1043
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001044void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) {
1045 mov(vector, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdoch61f157c2016-09-16 13:49:30 +01001046 mov(vector, FieldOperand(vector, JSFunction::kLiteralsOffset));
1047 mov(vector, FieldOperand(vector, LiteralsArray::kFeedbackVectorOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001048}
1049
1050
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001051void MacroAssembler::EnterFrame(StackFrame::Type type,
1052 bool load_constant_pool_pointer_reg) {
1053 // Out-of-line constant pool not implemented on x87.
1054 UNREACHABLE();
1055}
1056
1057
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001058void MacroAssembler::EnterFrame(StackFrame::Type type) {
1059 push(ebp);
1060 mov(ebp, esp);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001061 push(Immediate(Smi::FromInt(type)));
Ben Murdochda12d292016-06-02 14:46:10 +01001062 if (type == StackFrame::INTERNAL) {
1063 push(Immediate(CodeObject()));
1064 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001065 if (emit_debug_code()) {
1066 cmp(Operand(esp, 0), Immediate(isolate()->factory()->undefined_value()));
1067 Check(not_equal, kCodeObjectNotProperlyPatched);
1068 }
1069}
1070
1071
1072void MacroAssembler::LeaveFrame(StackFrame::Type type) {
1073 if (emit_debug_code()) {
Ben Murdochda12d292016-06-02 14:46:10 +01001074 cmp(Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001075 Immediate(Smi::FromInt(type)));
1076 Check(equal, kStackFrameTypesMustMatch);
1077 }
1078 leave();
1079}
1080
1081
1082void MacroAssembler::EnterExitFramePrologue() {
1083 // Set up the frame structure on the stack.
Ben Murdochda12d292016-06-02 14:46:10 +01001084 DCHECK_EQ(+2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement);
1085 DCHECK_EQ(+1 * kPointerSize, ExitFrameConstants::kCallerPCOffset);
1086 DCHECK_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001087 push(ebp);
1088 mov(ebp, esp);
1089
1090 // Reserve room for entry stack pointer and push the code object.
Ben Murdochda12d292016-06-02 14:46:10 +01001091 push(Immediate(Smi::FromInt(StackFrame::EXIT)));
1092 DCHECK_EQ(-2 * kPointerSize, ExitFrameConstants::kSPOffset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001093 push(Immediate(0)); // Saved entry sp, patched before call.
Ben Murdochda12d292016-06-02 14:46:10 +01001094 DCHECK_EQ(-3 * kPointerSize, ExitFrameConstants::kCodeOffset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001095 push(Immediate(CodeObject())); // Accessed from ExitFrame::code_slot.
1096
1097 // Save the frame pointer and the context in top.
1098 ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress, isolate());
1099 ExternalReference context_address(Isolate::kContextAddress, isolate());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001100 ExternalReference c_function_address(Isolate::kCFunctionAddress, isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001101 mov(Operand::StaticVariable(c_entry_fp_address), ebp);
1102 mov(Operand::StaticVariable(context_address), esi);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001103 mov(Operand::StaticVariable(c_function_address), ebx);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001104}
1105
1106
1107void MacroAssembler::EnterExitFrameEpilogue(int argc, bool save_doubles) {
1108 // Optionally save FPU state.
1109 if (save_doubles) {
1110 // Store FPU state to m108byte.
1111 int space = 108 + argc * kPointerSize;
1112 sub(esp, Immediate(space));
Ben Murdochda12d292016-06-02 14:46:10 +01001113 const int offset = -ExitFrameConstants::kFixedFrameSizeFromFp;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001114 fnsave(MemOperand(ebp, offset - 108));
1115 } else {
1116 sub(esp, Immediate(argc * kPointerSize));
1117 }
1118
1119 // Get the required frame alignment for the OS.
1120 const int kFrameAlignment = base::OS::ActivationFrameAlignment();
1121 if (kFrameAlignment > 0) {
1122 DCHECK(base::bits::IsPowerOfTwo32(kFrameAlignment));
1123 and_(esp, -kFrameAlignment);
1124 }
1125
1126 // Patch the saved entry sp.
1127 mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp);
1128}
1129
1130
Ben Murdoch097c5b22016-05-18 11:27:45 +01001131void MacroAssembler::EnterExitFrame(int argc, bool save_doubles) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001132 EnterExitFramePrologue();
1133
1134 // Set up argc and argv in callee-saved registers.
1135 int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
1136 mov(edi, eax);
1137 lea(esi, Operand(ebp, eax, times_4, offset));
1138
1139 // Reserve space for argc, argv and isolate.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001140 EnterExitFrameEpilogue(argc, save_doubles);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001141}
1142
1143
1144void MacroAssembler::EnterApiExitFrame(int argc) {
1145 EnterExitFramePrologue();
1146 EnterExitFrameEpilogue(argc, false);
1147}
1148
1149
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001150void MacroAssembler::LeaveExitFrame(bool save_doubles, bool pop_arguments) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001151 // Optionally restore FPU state.
1152 if (save_doubles) {
Ben Murdochda12d292016-06-02 14:46:10 +01001153 const int offset = -ExitFrameConstants::kFixedFrameSizeFromFp;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001154 frstor(MemOperand(ebp, offset - 108));
1155 }
1156
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001157 if (pop_arguments) {
1158 // Get the return address from the stack and restore the frame pointer.
1159 mov(ecx, Operand(ebp, 1 * kPointerSize));
1160 mov(ebp, Operand(ebp, 0 * kPointerSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001161
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001162 // Pop the arguments and the receiver from the caller stack.
1163 lea(esp, Operand(esi, 1 * kPointerSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001164
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001165 // Push the return address to get ready to return.
1166 push(ecx);
1167 } else {
1168 // Otherwise just leave the exit frame.
1169 leave();
1170 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001171
1172 LeaveExitFrameEpilogue(true);
1173}
1174
1175
1176void MacroAssembler::LeaveExitFrameEpilogue(bool restore_context) {
1177 // Restore current context from top and clear it in debug mode.
1178 ExternalReference context_address(Isolate::kContextAddress, isolate());
1179 if (restore_context) {
1180 mov(esi, Operand::StaticVariable(context_address));
1181 }
1182#ifdef DEBUG
1183 mov(Operand::StaticVariable(context_address), Immediate(0));
1184#endif
1185
1186 // Clear the top frame.
1187 ExternalReference c_entry_fp_address(Isolate::kCEntryFPAddress,
1188 isolate());
1189 mov(Operand::StaticVariable(c_entry_fp_address), Immediate(0));
1190}
1191
1192
1193void MacroAssembler::LeaveApiExitFrame(bool restore_context) {
1194 mov(esp, ebp);
1195 pop(ebp);
1196
1197 LeaveExitFrameEpilogue(restore_context);
1198}
1199
1200
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001201void MacroAssembler::PushStackHandler() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001202 // Adjust this code if not the case.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001203 STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001204 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001205
1206 // Link the current handler as the next handler.
1207 ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
1208 push(Operand::StaticVariable(handler_address));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001209
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001210 // Set this new handler as the current one.
1211 mov(Operand::StaticVariable(handler_address), esp);
1212}
1213
1214
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001215void MacroAssembler::PopStackHandler() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001216 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
1217 ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
1218 pop(Operand::StaticVariable(handler_address));
1219 add(esp, Immediate(StackHandlerConstants::kSize - kPointerSize));
1220}
1221
1222
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001223void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
1224 Register scratch1,
1225 Register scratch2,
1226 Label* miss) {
1227 Label same_contexts;
1228
1229 DCHECK(!holder_reg.is(scratch1));
1230 DCHECK(!holder_reg.is(scratch2));
1231 DCHECK(!scratch1.is(scratch2));
1232
Ben Murdochda12d292016-06-02 14:46:10 +01001233 // Load current lexical context from the active StandardFrame, which
1234 // may require crawling past STUB frames.
1235 Label load_context;
1236 Label has_context;
1237 mov(scratch2, ebp);
1238 bind(&load_context);
1239 mov(scratch1,
1240 MemOperand(scratch2, CommonFrameConstants::kContextOrFrameTypeOffset));
1241 JumpIfNotSmi(scratch1, &has_context);
1242 mov(scratch2, MemOperand(scratch2, CommonFrameConstants::kCallerFPOffset));
1243 jmp(&load_context);
1244 bind(&has_context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001245
1246 // When generating debug code, make sure the lexical context is set.
1247 if (emit_debug_code()) {
1248 cmp(scratch1, Immediate(0));
1249 Check(not_equal, kWeShouldNotHaveAnEmptyLexicalContext);
1250 }
1251 // Load the native context of the current context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001252 mov(scratch1, ContextOperand(scratch1, Context::NATIVE_CONTEXT_INDEX));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001253
1254 // Check the context is a native context.
1255 if (emit_debug_code()) {
1256 // Read the first word and compare to native_context_map.
1257 cmp(FieldOperand(scratch1, HeapObject::kMapOffset),
1258 isolate()->factory()->native_context_map());
1259 Check(equal, kJSGlobalObjectNativeContextShouldBeANativeContext);
1260 }
1261
1262 // Check if both contexts are the same.
1263 cmp(scratch1, FieldOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
1264 j(equal, &same_contexts);
1265
1266 // Compare security tokens, save holder_reg on the stack so we can use it
1267 // as a temporary register.
1268 //
1269 // Check that the security token in the calling global object is
1270 // compatible with the security token in the receiving global
1271 // object.
1272 mov(scratch2,
1273 FieldOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
1274
1275 // Check the context is a native context.
1276 if (emit_debug_code()) {
1277 cmp(scratch2, isolate()->factory()->null_value());
1278 Check(not_equal, kJSGlobalProxyContextShouldNotBeNull);
1279
1280 // Read the first word and compare to native_context_map(),
1281 cmp(FieldOperand(scratch2, HeapObject::kMapOffset),
1282 isolate()->factory()->native_context_map());
1283 Check(equal, kJSGlobalObjectNativeContextShouldBeANativeContext);
1284 }
1285
1286 int token_offset = Context::kHeaderSize +
1287 Context::SECURITY_TOKEN_INDEX * kPointerSize;
1288 mov(scratch1, FieldOperand(scratch1, token_offset));
1289 cmp(scratch1, FieldOperand(scratch2, token_offset));
1290 j(not_equal, miss);
1291
1292 bind(&same_contexts);
1293}
1294
1295
1296// Compute the hash code from the untagged key. This must be kept in sync with
1297// ComputeIntegerHash in utils.h and KeyedLoadGenericStub in
1298// code-stub-hydrogen.cc
1299//
1300// Note: r0 will contain hash code
1301void MacroAssembler::GetNumberHash(Register r0, Register scratch) {
1302 // Xor original key with a seed.
1303 if (serializer_enabled()) {
1304 ExternalReference roots_array_start =
1305 ExternalReference::roots_array_start(isolate());
1306 mov(scratch, Immediate(Heap::kHashSeedRootIndex));
1307 mov(scratch,
1308 Operand::StaticArray(scratch, times_pointer_size, roots_array_start));
1309 SmiUntag(scratch);
1310 xor_(r0, scratch);
1311 } else {
1312 int32_t seed = isolate()->heap()->HashSeed();
1313 xor_(r0, Immediate(seed));
1314 }
1315
1316 // hash = ~hash + (hash << 15);
1317 mov(scratch, r0);
1318 not_(r0);
1319 shl(scratch, 15);
1320 add(r0, scratch);
1321 // hash = hash ^ (hash >> 12);
1322 mov(scratch, r0);
1323 shr(scratch, 12);
1324 xor_(r0, scratch);
1325 // hash = hash + (hash << 2);
1326 lea(r0, Operand(r0, r0, times_4, 0));
1327 // hash = hash ^ (hash >> 4);
1328 mov(scratch, r0);
1329 shr(scratch, 4);
1330 xor_(r0, scratch);
1331 // hash = hash * 2057;
1332 imul(r0, r0, 2057);
1333 // hash = hash ^ (hash >> 16);
1334 mov(scratch, r0);
1335 shr(scratch, 16);
1336 xor_(r0, scratch);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001337 and_(r0, 0x3fffffff);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001338}
1339
1340
1341
1342void MacroAssembler::LoadFromNumberDictionary(Label* miss,
1343 Register elements,
1344 Register key,
1345 Register r0,
1346 Register r1,
1347 Register r2,
1348 Register result) {
1349 // Register use:
1350 //
1351 // elements - holds the slow-case elements of the receiver and is unchanged.
1352 //
1353 // key - holds the smi key on entry and is unchanged.
1354 //
1355 // Scratch registers:
1356 //
1357 // r0 - holds the untagged key on entry and holds the hash once computed.
1358 //
1359 // r1 - used to hold the capacity mask of the dictionary
1360 //
1361 // r2 - used for the index into the dictionary.
1362 //
1363 // result - holds the result on exit if the load succeeds and we fall through.
1364
1365 Label done;
1366
1367 GetNumberHash(r0, r1);
1368
1369 // Compute capacity mask.
1370 mov(r1, FieldOperand(elements, SeededNumberDictionary::kCapacityOffset));
1371 shr(r1, kSmiTagSize); // convert smi to int
1372 dec(r1);
1373
1374 // Generate an unrolled loop that performs a few probes before giving up.
1375 for (int i = 0; i < kNumberDictionaryProbes; i++) {
1376 // Use r2 for index calculations and keep the hash intact in r0.
1377 mov(r2, r0);
1378 // Compute the masked index: (hash + i + i * i) & mask.
1379 if (i > 0) {
1380 add(r2, Immediate(SeededNumberDictionary::GetProbeOffset(i)));
1381 }
1382 and_(r2, r1);
1383
1384 // Scale the index by multiplying by the entry size.
1385 DCHECK(SeededNumberDictionary::kEntrySize == 3);
1386 lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3
1387
1388 // Check if the key matches.
1389 cmp(key, FieldOperand(elements,
1390 r2,
1391 times_pointer_size,
1392 SeededNumberDictionary::kElementsStartOffset));
1393 if (i != (kNumberDictionaryProbes - 1)) {
1394 j(equal, &done);
1395 } else {
1396 j(not_equal, miss);
1397 }
1398 }
1399
1400 bind(&done);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001401 // Check that the value is a field property.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001402 const int kDetailsOffset =
1403 SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001404 DCHECK_EQ(DATA, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001405 test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
1406 Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
1407 j(not_zero, miss);
1408
1409 // Get the value at the masked, scaled index.
1410 const int kValueOffset =
1411 SeededNumberDictionary::kElementsStartOffset + kPointerSize;
1412 mov(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset));
1413}
1414
1415
1416void MacroAssembler::LoadAllocationTopHelper(Register result,
1417 Register scratch,
1418 AllocationFlags flags) {
1419 ExternalReference allocation_top =
1420 AllocationUtils::GetAllocationTopReference(isolate(), flags);
1421
1422 // Just return if allocation top is already known.
1423 if ((flags & RESULT_CONTAINS_TOP) != 0) {
1424 // No use of scratch if allocation top is provided.
1425 DCHECK(scratch.is(no_reg));
1426#ifdef DEBUG
1427 // Assert that result actually contains top on entry.
1428 cmp(result, Operand::StaticVariable(allocation_top));
1429 Check(equal, kUnexpectedAllocationTop);
1430#endif
1431 return;
1432 }
1433
1434 // Move address of new object to result. Use scratch register if available.
1435 if (scratch.is(no_reg)) {
1436 mov(result, Operand::StaticVariable(allocation_top));
1437 } else {
1438 mov(scratch, Immediate(allocation_top));
1439 mov(result, Operand(scratch, 0));
1440 }
1441}
1442
1443
1444void MacroAssembler::UpdateAllocationTopHelper(Register result_end,
1445 Register scratch,
1446 AllocationFlags flags) {
1447 if (emit_debug_code()) {
1448 test(result_end, Immediate(kObjectAlignmentMask));
1449 Check(zero, kUnalignedAllocationInNewSpace);
1450 }
1451
1452 ExternalReference allocation_top =
1453 AllocationUtils::GetAllocationTopReference(isolate(), flags);
1454
1455 // Update new top. Use scratch if available.
1456 if (scratch.is(no_reg)) {
1457 mov(Operand::StaticVariable(allocation_top), result_end);
1458 } else {
1459 mov(Operand(scratch, 0), result_end);
1460 }
1461}
1462
1463
1464void MacroAssembler::Allocate(int object_size,
1465 Register result,
1466 Register result_end,
1467 Register scratch,
1468 Label* gc_required,
1469 AllocationFlags flags) {
1470 DCHECK((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0);
1471 DCHECK(object_size <= Page::kMaxRegularHeapObjectSize);
Ben Murdochc5610432016-08-08 18:44:38 +01001472 DCHECK((flags & ALLOCATION_FOLDED) == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001473 if (!FLAG_inline_new) {
1474 if (emit_debug_code()) {
1475 // Trash the registers to simulate an allocation failure.
1476 mov(result, Immediate(0x7091));
1477 if (result_end.is_valid()) {
1478 mov(result_end, Immediate(0x7191));
1479 }
1480 if (scratch.is_valid()) {
1481 mov(scratch, Immediate(0x7291));
1482 }
1483 }
1484 jmp(gc_required);
1485 return;
1486 }
1487 DCHECK(!result.is(result_end));
1488
1489 // Load address of new object into result.
1490 LoadAllocationTopHelper(result, scratch, flags);
1491
1492 ExternalReference allocation_limit =
1493 AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1494
1495 // Align the next allocation. Storing the filler map without checking top is
1496 // safe in new-space because the limit of the heap is aligned there.
1497 if ((flags & DOUBLE_ALIGNMENT) != 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001498 DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
1499 Label aligned;
1500 test(result, Immediate(kDoubleAlignmentMask));
1501 j(zero, &aligned, Label::kNear);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001502 if ((flags & PRETENURE) != 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001503 cmp(result, Operand::StaticVariable(allocation_limit));
1504 j(above_equal, gc_required);
1505 }
1506 mov(Operand(result, 0),
1507 Immediate(isolate()->factory()->one_pointer_filler_map()));
1508 add(result, Immediate(kDoubleSize / 2));
1509 bind(&aligned);
1510 }
1511
1512 // Calculate new top and bail out if space is exhausted.
1513 Register top_reg = result_end.is_valid() ? result_end : result;
Ben Murdochc5610432016-08-08 18:44:38 +01001514
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001515 if (!top_reg.is(result)) {
1516 mov(top_reg, result);
1517 }
1518 add(top_reg, Immediate(object_size));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001519 cmp(top_reg, Operand::StaticVariable(allocation_limit));
1520 j(above, gc_required);
1521
Ben Murdochc5610432016-08-08 18:44:38 +01001522 if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) {
1523 // The top pointer is not updated for allocation folding dominators.
1524 UpdateAllocationTopHelper(top_reg, scratch, flags);
1525 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001526
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001527 if (top_reg.is(result)) {
Ben Murdochc5610432016-08-08 18:44:38 +01001528 sub(result, Immediate(object_size - kHeapObjectTag));
1529 } else {
1530 // Tag the result.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001531 DCHECK(kHeapObjectTag == 1);
1532 inc(result);
1533 }
1534}
1535
1536
1537void MacroAssembler::Allocate(int header_size,
1538 ScaleFactor element_size,
1539 Register element_count,
1540 RegisterValueType element_count_type,
1541 Register result,
1542 Register result_end,
1543 Register scratch,
1544 Label* gc_required,
1545 AllocationFlags flags) {
1546 DCHECK((flags & SIZE_IN_WORDS) == 0);
Ben Murdochc5610432016-08-08 18:44:38 +01001547 DCHECK((flags & ALLOCATION_FOLDING_DOMINATOR) == 0);
1548 DCHECK((flags & ALLOCATION_FOLDED) == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001549 if (!FLAG_inline_new) {
1550 if (emit_debug_code()) {
1551 // Trash the registers to simulate an allocation failure.
1552 mov(result, Immediate(0x7091));
1553 mov(result_end, Immediate(0x7191));
1554 if (scratch.is_valid()) {
1555 mov(scratch, Immediate(0x7291));
1556 }
1557 // Register element_count is not modified by the function.
1558 }
1559 jmp(gc_required);
1560 return;
1561 }
1562 DCHECK(!result.is(result_end));
1563
1564 // Load address of new object into result.
1565 LoadAllocationTopHelper(result, scratch, flags);
1566
1567 ExternalReference allocation_limit =
1568 AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1569
1570 // Align the next allocation. Storing the filler map without checking top is
1571 // safe in new-space because the limit of the heap is aligned there.
1572 if ((flags & DOUBLE_ALIGNMENT) != 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001573 DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
1574 Label aligned;
1575 test(result, Immediate(kDoubleAlignmentMask));
1576 j(zero, &aligned, Label::kNear);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001577 if ((flags & PRETENURE) != 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001578 cmp(result, Operand::StaticVariable(allocation_limit));
1579 j(above_equal, gc_required);
1580 }
1581 mov(Operand(result, 0),
1582 Immediate(isolate()->factory()->one_pointer_filler_map()));
1583 add(result, Immediate(kDoubleSize / 2));
1584 bind(&aligned);
1585 }
1586
1587 // Calculate new top and bail out if space is exhausted.
1588 // We assume that element_count*element_size + header_size does not
1589 // overflow.
1590 if (element_count_type == REGISTER_VALUE_IS_SMI) {
1591 STATIC_ASSERT(static_cast<ScaleFactor>(times_2 - 1) == times_1);
1592 STATIC_ASSERT(static_cast<ScaleFactor>(times_4 - 1) == times_2);
1593 STATIC_ASSERT(static_cast<ScaleFactor>(times_8 - 1) == times_4);
1594 DCHECK(element_size >= times_2);
1595 DCHECK(kSmiTagSize == 1);
1596 element_size = static_cast<ScaleFactor>(element_size - 1);
1597 } else {
1598 DCHECK(element_count_type == REGISTER_VALUE_IS_INT32);
1599 }
1600 lea(result_end, Operand(element_count, element_size, header_size));
1601 add(result_end, result);
1602 j(carry, gc_required);
1603 cmp(result_end, Operand::StaticVariable(allocation_limit));
1604 j(above, gc_required);
1605
Ben Murdochc5610432016-08-08 18:44:38 +01001606 // Tag result.
1607 DCHECK(kHeapObjectTag == 1);
1608 inc(result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001609
1610 // Update allocation top.
1611 UpdateAllocationTopHelper(result_end, scratch, flags);
1612}
1613
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001614void MacroAssembler::Allocate(Register object_size,
1615 Register result,
1616 Register result_end,
1617 Register scratch,
1618 Label* gc_required,
1619 AllocationFlags flags) {
1620 DCHECK((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0);
Ben Murdochc5610432016-08-08 18:44:38 +01001621 DCHECK((flags & ALLOCATION_FOLDED) == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001622 if (!FLAG_inline_new) {
1623 if (emit_debug_code()) {
1624 // Trash the registers to simulate an allocation failure.
1625 mov(result, Immediate(0x7091));
1626 mov(result_end, Immediate(0x7191));
1627 if (scratch.is_valid()) {
1628 mov(scratch, Immediate(0x7291));
1629 }
1630 // object_size is left unchanged by this function.
1631 }
1632 jmp(gc_required);
1633 return;
1634 }
1635 DCHECK(!result.is(result_end));
1636
1637 // Load address of new object into result.
1638 LoadAllocationTopHelper(result, scratch, flags);
1639
1640 ExternalReference allocation_limit =
1641 AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1642
1643 // Align the next allocation. Storing the filler map without checking top is
1644 // safe in new-space because the limit of the heap is aligned there.
1645 if ((flags & DOUBLE_ALIGNMENT) != 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001646 DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
1647 Label aligned;
1648 test(result, Immediate(kDoubleAlignmentMask));
1649 j(zero, &aligned, Label::kNear);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001650 if ((flags & PRETENURE) != 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001651 cmp(result, Operand::StaticVariable(allocation_limit));
1652 j(above_equal, gc_required);
1653 }
1654 mov(Operand(result, 0),
1655 Immediate(isolate()->factory()->one_pointer_filler_map()));
1656 add(result, Immediate(kDoubleSize / 2));
1657 bind(&aligned);
1658 }
1659
1660 // Calculate new top and bail out if space is exhausted.
1661 if (!object_size.is(result_end)) {
1662 mov(result_end, object_size);
1663 }
1664 add(result_end, result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001665 cmp(result_end, Operand::StaticVariable(allocation_limit));
1666 j(above, gc_required);
1667
Ben Murdochc5610432016-08-08 18:44:38 +01001668 // Tag result.
1669 DCHECK(kHeapObjectTag == 1);
1670 inc(result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001671
Ben Murdochc5610432016-08-08 18:44:38 +01001672 if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) {
1673 // The top pointer is not updated for allocation folding dominators.
1674 UpdateAllocationTopHelper(result_end, scratch, flags);
1675 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001676}
1677
Ben Murdochc5610432016-08-08 18:44:38 +01001678void MacroAssembler::FastAllocate(int object_size, Register result,
1679 Register result_end, AllocationFlags flags) {
1680 DCHECK(!result.is(result_end));
1681 // Load address of new object into result.
1682 LoadAllocationTopHelper(result, no_reg, flags);
1683
1684 if ((flags & DOUBLE_ALIGNMENT) != 0) {
1685 DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
1686 Label aligned;
1687 test(result, Immediate(kDoubleAlignmentMask));
1688 j(zero, &aligned, Label::kNear);
1689 mov(Operand(result, 0),
1690 Immediate(isolate()->factory()->one_pointer_filler_map()));
1691 add(result, Immediate(kDoubleSize / 2));
1692 bind(&aligned);
1693 }
1694
1695 lea(result_end, Operand(result, object_size));
1696 UpdateAllocationTopHelper(result_end, no_reg, flags);
1697
1698 DCHECK(kHeapObjectTag == 1);
1699 inc(result);
1700}
1701
1702void MacroAssembler::FastAllocate(Register object_size, Register result,
1703 Register result_end, AllocationFlags flags) {
1704 DCHECK(!result.is(result_end));
1705 // Load address of new object into result.
1706 LoadAllocationTopHelper(result, no_reg, flags);
1707
1708 if ((flags & DOUBLE_ALIGNMENT) != 0) {
1709 DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
1710 Label aligned;
1711 test(result, Immediate(kDoubleAlignmentMask));
1712 j(zero, &aligned, Label::kNear);
1713 mov(Operand(result, 0),
1714 Immediate(isolate()->factory()->one_pointer_filler_map()));
1715 add(result, Immediate(kDoubleSize / 2));
1716 bind(&aligned);
1717 }
1718
1719 lea(result_end, Operand(result, object_size, times_1, 0));
1720 UpdateAllocationTopHelper(result_end, no_reg, flags);
1721
1722 DCHECK(kHeapObjectTag == 1);
1723 inc(result);
1724}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001725
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001726void MacroAssembler::AllocateHeapNumber(Register result,
1727 Register scratch1,
1728 Register scratch2,
1729 Label* gc_required,
1730 MutableMode mode) {
1731 // Allocate heap number in new space.
1732 Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required,
Ben Murdochc5610432016-08-08 18:44:38 +01001733 NO_ALLOCATION_FLAGS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001734
1735 Handle<Map> map = mode == MUTABLE
1736 ? isolate()->factory()->mutable_heap_number_map()
1737 : isolate()->factory()->heap_number_map();
1738
1739 // Set the map.
1740 mov(FieldOperand(result, HeapObject::kMapOffset), Immediate(map));
1741}
1742
1743
1744void MacroAssembler::AllocateTwoByteString(Register result,
1745 Register length,
1746 Register scratch1,
1747 Register scratch2,
1748 Register scratch3,
1749 Label* gc_required) {
1750 // Calculate the number of bytes needed for the characters in the string while
1751 // observing object alignment.
1752 DCHECK((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
1753 DCHECK(kShortSize == 2);
1754 // scratch1 = length * 2 + kObjectAlignmentMask.
1755 lea(scratch1, Operand(length, length, times_1, kObjectAlignmentMask));
1756 and_(scratch1, Immediate(~kObjectAlignmentMask));
1757
1758 // Allocate two byte string in new space.
Ben Murdochc5610432016-08-08 18:44:38 +01001759 Allocate(SeqTwoByteString::kHeaderSize, times_1, scratch1,
1760 REGISTER_VALUE_IS_INT32, result, scratch2, scratch3, gc_required,
1761 NO_ALLOCATION_FLAGS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001762
1763 // Set the map, length and hash field.
1764 mov(FieldOperand(result, HeapObject::kMapOffset),
1765 Immediate(isolate()->factory()->string_map()));
1766 mov(scratch1, length);
1767 SmiTag(scratch1);
1768 mov(FieldOperand(result, String::kLengthOffset), scratch1);
1769 mov(FieldOperand(result, String::kHashFieldOffset),
1770 Immediate(String::kEmptyHashField));
1771}
1772
1773
1774void MacroAssembler::AllocateOneByteString(Register result, Register length,
1775 Register scratch1, Register scratch2,
1776 Register scratch3,
1777 Label* gc_required) {
1778 // Calculate the number of bytes needed for the characters in the string while
1779 // observing object alignment.
1780 DCHECK((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
1781 mov(scratch1, length);
1782 DCHECK(kCharSize == 1);
1783 add(scratch1, Immediate(kObjectAlignmentMask));
1784 and_(scratch1, Immediate(~kObjectAlignmentMask));
1785
1786 // Allocate one-byte string in new space.
Ben Murdochc5610432016-08-08 18:44:38 +01001787 Allocate(SeqOneByteString::kHeaderSize, times_1, scratch1,
1788 REGISTER_VALUE_IS_INT32, result, scratch2, scratch3, gc_required,
1789 NO_ALLOCATION_FLAGS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001790
1791 // Set the map, length and hash field.
1792 mov(FieldOperand(result, HeapObject::kMapOffset),
1793 Immediate(isolate()->factory()->one_byte_string_map()));
1794 mov(scratch1, length);
1795 SmiTag(scratch1);
1796 mov(FieldOperand(result, String::kLengthOffset), scratch1);
1797 mov(FieldOperand(result, String::kHashFieldOffset),
1798 Immediate(String::kEmptyHashField));
1799}
1800
1801
1802void MacroAssembler::AllocateOneByteString(Register result, int length,
1803 Register scratch1, Register scratch2,
1804 Label* gc_required) {
1805 DCHECK(length > 0);
1806
1807 // Allocate one-byte string in new space.
1808 Allocate(SeqOneByteString::SizeFor(length), result, scratch1, scratch2,
Ben Murdochc5610432016-08-08 18:44:38 +01001809 gc_required, NO_ALLOCATION_FLAGS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001810
1811 // Set the map, length and hash field.
1812 mov(FieldOperand(result, HeapObject::kMapOffset),
1813 Immediate(isolate()->factory()->one_byte_string_map()));
1814 mov(FieldOperand(result, String::kLengthOffset),
1815 Immediate(Smi::FromInt(length)));
1816 mov(FieldOperand(result, String::kHashFieldOffset),
1817 Immediate(String::kEmptyHashField));
1818}
1819
1820
1821void MacroAssembler::AllocateTwoByteConsString(Register result,
1822 Register scratch1,
1823 Register scratch2,
1824 Label* gc_required) {
1825 // Allocate heap number in new space.
1826 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
Ben Murdochc5610432016-08-08 18:44:38 +01001827 NO_ALLOCATION_FLAGS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001828
1829 // Set the map. The other fields are left uninitialized.
1830 mov(FieldOperand(result, HeapObject::kMapOffset),
1831 Immediate(isolate()->factory()->cons_string_map()));
1832}
1833
1834
1835void MacroAssembler::AllocateOneByteConsString(Register result,
1836 Register scratch1,
1837 Register scratch2,
1838 Label* gc_required) {
Ben Murdochc5610432016-08-08 18:44:38 +01001839 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
1840 NO_ALLOCATION_FLAGS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001841
1842 // Set the map. The other fields are left uninitialized.
1843 mov(FieldOperand(result, HeapObject::kMapOffset),
1844 Immediate(isolate()->factory()->cons_one_byte_string_map()));
1845}
1846
1847
1848void MacroAssembler::AllocateTwoByteSlicedString(Register result,
1849 Register scratch1,
1850 Register scratch2,
1851 Label* gc_required) {
1852 // Allocate heap number in new space.
1853 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
Ben Murdochc5610432016-08-08 18:44:38 +01001854 NO_ALLOCATION_FLAGS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001855
1856 // Set the map. The other fields are left uninitialized.
1857 mov(FieldOperand(result, HeapObject::kMapOffset),
1858 Immediate(isolate()->factory()->sliced_string_map()));
1859}
1860
1861
1862void MacroAssembler::AllocateOneByteSlicedString(Register result,
1863 Register scratch1,
1864 Register scratch2,
1865 Label* gc_required) {
1866 // Allocate heap number in new space.
1867 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
Ben Murdochc5610432016-08-08 18:44:38 +01001868 NO_ALLOCATION_FLAGS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001869
1870 // Set the map. The other fields are left uninitialized.
1871 mov(FieldOperand(result, HeapObject::kMapOffset),
1872 Immediate(isolate()->factory()->sliced_one_byte_string_map()));
1873}
1874
1875
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001876void MacroAssembler::AllocateJSValue(Register result, Register constructor,
1877 Register value, Register scratch,
1878 Label* gc_required) {
1879 DCHECK(!result.is(constructor));
1880 DCHECK(!result.is(scratch));
1881 DCHECK(!result.is(value));
1882
1883 // Allocate JSValue in new space.
Ben Murdochc5610432016-08-08 18:44:38 +01001884 Allocate(JSValue::kSize, result, scratch, no_reg, gc_required,
1885 NO_ALLOCATION_FLAGS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001886
1887 // Initialize the JSValue.
1888 LoadGlobalFunctionInitialMap(constructor, scratch);
1889 mov(FieldOperand(result, HeapObject::kMapOffset), scratch);
1890 LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex);
1891 mov(FieldOperand(result, JSObject::kPropertiesOffset), scratch);
1892 mov(FieldOperand(result, JSObject::kElementsOffset), scratch);
1893 mov(FieldOperand(result, JSValue::kValueOffset), value);
1894 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
1895}
1896
1897
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001898// Copy memory, byte-by-byte, from source to destination. Not optimized for
1899// long or aligned copies. The contents of scratch and length are destroyed.
1900// Source and destination are incremented by length.
1901// Many variants of movsb, loop unrolling, word moves, and indexed operands
1902// have been tried here already, and this is fastest.
1903// A simpler loop is faster on small copies, but 30% slower on large ones.
1904// The cld() instruction must have been emitted, to set the direction flag(),
1905// before calling this function.
1906void MacroAssembler::CopyBytes(Register source,
1907 Register destination,
1908 Register length,
1909 Register scratch) {
1910 Label short_loop, len4, len8, len12, done, short_string;
1911 DCHECK(source.is(esi));
1912 DCHECK(destination.is(edi));
1913 DCHECK(length.is(ecx));
1914 cmp(length, Immediate(4));
1915 j(below, &short_string, Label::kNear);
1916
1917 // Because source is 4-byte aligned in our uses of this function,
1918 // we keep source aligned for the rep_movs call by copying the odd bytes
1919 // at the end of the ranges.
1920 mov(scratch, Operand(source, length, times_1, -4));
1921 mov(Operand(destination, length, times_1, -4), scratch);
1922
1923 cmp(length, Immediate(8));
1924 j(below_equal, &len4, Label::kNear);
1925 cmp(length, Immediate(12));
1926 j(below_equal, &len8, Label::kNear);
1927 cmp(length, Immediate(16));
1928 j(below_equal, &len12, Label::kNear);
1929
1930 mov(scratch, ecx);
1931 shr(ecx, 2);
1932 rep_movs();
1933 and_(scratch, Immediate(0x3));
1934 add(destination, scratch);
1935 jmp(&done, Label::kNear);
1936
1937 bind(&len12);
1938 mov(scratch, Operand(source, 8));
1939 mov(Operand(destination, 8), scratch);
1940 bind(&len8);
1941 mov(scratch, Operand(source, 4));
1942 mov(Operand(destination, 4), scratch);
1943 bind(&len4);
1944 mov(scratch, Operand(source, 0));
1945 mov(Operand(destination, 0), scratch);
1946 add(destination, length);
1947 jmp(&done, Label::kNear);
1948
1949 bind(&short_string);
1950 test(length, length);
1951 j(zero, &done, Label::kNear);
1952
1953 bind(&short_loop);
1954 mov_b(scratch, Operand(source, 0));
1955 mov_b(Operand(destination, 0), scratch);
1956 inc(source);
1957 inc(destination);
1958 dec(length);
1959 j(not_zero, &short_loop);
1960
1961 bind(&done);
1962}
1963
1964
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001965void MacroAssembler::InitializeFieldsWithFiller(Register current_address,
1966 Register end_address,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001967 Register filler) {
1968 Label loop, entry;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001969 jmp(&entry, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001970 bind(&loop);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001971 mov(Operand(current_address, 0), filler);
1972 add(current_address, Immediate(kPointerSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001973 bind(&entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001974 cmp(current_address, end_address);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001975 j(below, &loop, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001976}
1977
1978
1979void MacroAssembler::BooleanBitTest(Register object,
1980 int field_offset,
1981 int bit_index) {
1982 bit_index += kSmiTagSize + kSmiShiftSize;
1983 DCHECK(base::bits::IsPowerOfTwo32(kBitsPerByte));
1984 int byte_index = bit_index / kBitsPerByte;
1985 int byte_bit_index = bit_index & (kBitsPerByte - 1);
1986 test_b(FieldOperand(object, field_offset + byte_index),
Ben Murdochda12d292016-06-02 14:46:10 +01001987 Immediate(1 << byte_bit_index));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001988}
1989
1990
1991
1992void MacroAssembler::NegativeZeroTest(Register result,
1993 Register op,
1994 Label* then_label) {
1995 Label ok;
1996 test(result, result);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001997 j(not_zero, &ok, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001998 test(op, op);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001999 j(sign, then_label, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002000 bind(&ok);
2001}
2002
2003
2004void MacroAssembler::NegativeZeroTest(Register result,
2005 Register op1,
2006 Register op2,
2007 Register scratch,
2008 Label* then_label) {
2009 Label ok;
2010 test(result, result);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002011 j(not_zero, &ok, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002012 mov(scratch, op1);
2013 or_(scratch, op2);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002014 j(sign, then_label, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002015 bind(&ok);
2016}
2017
2018
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002019void MacroAssembler::GetMapConstructor(Register result, Register map,
2020 Register temp) {
2021 Label done, loop;
2022 mov(result, FieldOperand(map, Map::kConstructorOrBackPointerOffset));
2023 bind(&loop);
2024 JumpIfSmi(result, &done, Label::kNear);
2025 CmpObjectType(result, MAP_TYPE, temp);
2026 j(not_equal, &done, Label::kNear);
2027 mov(result, FieldOperand(result, Map::kConstructorOrBackPointerOffset));
2028 jmp(&loop);
2029 bind(&done);
2030}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002031
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002032
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002033void MacroAssembler::TryGetFunctionPrototype(Register function, Register result,
2034 Register scratch, Label* miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002035 // Get the prototype or initial map from the function.
2036 mov(result,
2037 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2038
2039 // If the prototype or initial map is the hole, don't return it and
2040 // simply miss the cache instead. This will allow us to allocate a
2041 // prototype object on-demand in the runtime system.
2042 cmp(result, Immediate(isolate()->factory()->the_hole_value()));
2043 j(equal, miss);
2044
2045 // If the function does not have an initial map, we're done.
2046 Label done;
2047 CmpObjectType(result, MAP_TYPE, scratch);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002048 j(not_equal, &done, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002049
2050 // Get the prototype from the initial map.
2051 mov(result, FieldOperand(result, Map::kPrototypeOffset));
2052
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002053 // All done.
2054 bind(&done);
2055}
2056
2057
2058void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id) {
2059 DCHECK(AllowThisStubCall(stub)); // Calls are not allowed in some stubs.
2060 call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id);
2061}
2062
2063
2064void MacroAssembler::TailCallStub(CodeStub* stub) {
2065 jmp(stub->GetCode(), RelocInfo::CODE_TARGET);
2066}
2067
2068
2069void MacroAssembler::StubReturn(int argc) {
2070 DCHECK(argc >= 1 && generating_stub());
2071 ret((argc - 1) * kPointerSize);
2072}
2073
2074
2075bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
2076 return has_frame_ || !stub->SometimesSetsUpAFrame();
2077}
2078
2079
2080void MacroAssembler::IndexFromHash(Register hash, Register index) {
2081 // The assert checks that the constants for the maximum number of digits
2082 // for an array index cached in the hash field and the number of bits
2083 // reserved for it does not conflict.
2084 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
2085 (1 << String::kArrayIndexValueBits));
2086 if (!index.is(hash)) {
2087 mov(index, hash);
2088 }
2089 DecodeFieldToSmi<String::ArrayIndexValueBits>(index);
2090}
2091
2092
2093void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments,
2094 SaveFPRegsMode save_doubles) {
2095 // If the expected number of arguments of the runtime function is
2096 // constant, we check that the actual number of arguments match the
2097 // expectation.
2098 CHECK(f->nargs < 0 || f->nargs == num_arguments);
2099
2100 // TODO(1236192): Most runtime routines don't need the number of
2101 // arguments passed in because it is constant. At some point we
2102 // should remove this need and make the runtime routine entry code
2103 // smarter.
2104 Move(eax, Immediate(num_arguments));
2105 mov(ebx, Immediate(ExternalReference(f, isolate())));
2106 CEntryStub ces(isolate(), 1, save_doubles);
2107 CallStub(&ces);
2108}
2109
2110
2111void MacroAssembler::CallExternalReference(ExternalReference ref,
2112 int num_arguments) {
2113 mov(eax, Immediate(num_arguments));
2114 mov(ebx, Immediate(ref));
2115
2116 CEntryStub stub(isolate(), 1);
2117 CallStub(&stub);
2118}
2119
2120
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002121void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
2122 // ----------- S t a t e -------------
2123 // -- esp[0] : return address
2124 // -- esp[8] : argument num_arguments - 1
2125 // ...
2126 // -- esp[8 * num_arguments] : argument 0 (receiver)
2127 //
2128 // For runtime functions with variable arguments:
2129 // -- eax : number of arguments
2130 // -----------------------------------
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002131
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002132 const Runtime::Function* function = Runtime::FunctionForId(fid);
2133 DCHECK_EQ(1, function->result_size);
2134 if (function->nargs >= 0) {
2135 // TODO(1236192): Most runtime routines don't need the number of
2136 // arguments passed in because it is constant. At some point we
2137 // should remove this need and make the runtime routine entry code
2138 // smarter.
2139 mov(eax, Immediate(function->nargs));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002140 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002141 JumpToExternalReference(ExternalReference(fid, isolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002142}
2143
2144
2145void MacroAssembler::JumpToExternalReference(const ExternalReference& ext) {
2146 // Set the entry point and jump to the C entry runtime stub.
2147 mov(ebx, Immediate(ext));
2148 CEntryStub ces(isolate(), 1);
2149 jmp(ces.GetCode(), RelocInfo::CODE_TARGET);
2150}
2151
Ben Murdochda12d292016-06-02 14:46:10 +01002152void MacroAssembler::PrepareForTailCall(
2153 const ParameterCount& callee_args_count, Register caller_args_count_reg,
2154 Register scratch0, Register scratch1, ReturnAddressState ra_state,
2155 int number_of_temp_values_after_return_address) {
2156#if DEBUG
2157 if (callee_args_count.is_reg()) {
2158 DCHECK(!AreAliased(callee_args_count.reg(), caller_args_count_reg, scratch0,
2159 scratch1));
2160 } else {
2161 DCHECK(!AreAliased(caller_args_count_reg, scratch0, scratch1));
2162 }
2163 DCHECK(ra_state != ReturnAddressState::kNotOnStack ||
2164 number_of_temp_values_after_return_address == 0);
2165#endif
2166
2167 // Calculate the destination address where we will put the return address
2168 // after we drop current frame.
2169 Register new_sp_reg = scratch0;
2170 if (callee_args_count.is_reg()) {
2171 sub(caller_args_count_reg, callee_args_count.reg());
2172 lea(new_sp_reg,
2173 Operand(ebp, caller_args_count_reg, times_pointer_size,
2174 StandardFrameConstants::kCallerPCOffset -
2175 number_of_temp_values_after_return_address * kPointerSize));
2176 } else {
2177 lea(new_sp_reg, Operand(ebp, caller_args_count_reg, times_pointer_size,
2178 StandardFrameConstants::kCallerPCOffset -
2179 (callee_args_count.immediate() +
2180 number_of_temp_values_after_return_address) *
2181 kPointerSize));
2182 }
2183
2184 if (FLAG_debug_code) {
2185 cmp(esp, new_sp_reg);
2186 Check(below, kStackAccessBelowStackPointer);
2187 }
2188
2189 // Copy return address from caller's frame to current frame's return address
2190 // to avoid its trashing and let the following loop copy it to the right
2191 // place.
2192 Register tmp_reg = scratch1;
2193 if (ra_state == ReturnAddressState::kOnStack) {
2194 mov(tmp_reg, Operand(ebp, StandardFrameConstants::kCallerPCOffset));
2195 mov(Operand(esp, number_of_temp_values_after_return_address * kPointerSize),
2196 tmp_reg);
2197 } else {
2198 DCHECK(ReturnAddressState::kNotOnStack == ra_state);
2199 DCHECK_EQ(0, number_of_temp_values_after_return_address);
2200 Push(Operand(ebp, StandardFrameConstants::kCallerPCOffset));
2201 }
2202
2203 // Restore caller's frame pointer now as it could be overwritten by
2204 // the copying loop.
2205 mov(ebp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2206
2207 // +2 here is to copy both receiver and return address.
2208 Register count_reg = caller_args_count_reg;
2209 if (callee_args_count.is_reg()) {
2210 lea(count_reg, Operand(callee_args_count.reg(),
2211 2 + number_of_temp_values_after_return_address));
2212 } else {
2213 mov(count_reg, Immediate(callee_args_count.immediate() + 2 +
2214 number_of_temp_values_after_return_address));
2215 // TODO(ishell): Unroll copying loop for small immediate values.
2216 }
2217
2218 // Now copy callee arguments to the caller frame going backwards to avoid
2219 // callee arguments corruption (source and destination areas could overlap).
2220 Label loop, entry;
2221 jmp(&entry, Label::kNear);
2222 bind(&loop);
2223 dec(count_reg);
2224 mov(tmp_reg, Operand(esp, count_reg, times_pointer_size, 0));
2225 mov(Operand(new_sp_reg, count_reg, times_pointer_size, 0), tmp_reg);
2226 bind(&entry);
2227 cmp(count_reg, Immediate(0));
2228 j(not_equal, &loop, Label::kNear);
2229
2230 // Leave current frame.
2231 mov(esp, new_sp_reg);
2232}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002233
2234void MacroAssembler::InvokePrologue(const ParameterCount& expected,
2235 const ParameterCount& actual,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002236 Label* done,
2237 bool* definitely_mismatches,
2238 InvokeFlag flag,
2239 Label::Distance done_near,
2240 const CallWrapper& call_wrapper) {
2241 bool definitely_matches = false;
2242 *definitely_mismatches = false;
2243 Label invoke;
2244 if (expected.is_immediate()) {
2245 DCHECK(actual.is_immediate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002246 mov(eax, actual.immediate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002247 if (expected.immediate() == actual.immediate()) {
2248 definitely_matches = true;
2249 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002250 const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
2251 if (expected.immediate() == sentinel) {
2252 // Don't worry about adapting arguments for builtins that
2253 // don't want that done. Skip adaption code by making it look
2254 // like we have a match between expected and actual number of
2255 // arguments.
2256 definitely_matches = true;
2257 } else {
2258 *definitely_mismatches = true;
2259 mov(ebx, expected.immediate());
2260 }
2261 }
2262 } else {
2263 if (actual.is_immediate()) {
2264 // Expected is in register, actual is immediate. This is the
2265 // case when we invoke function values without going through the
2266 // IC mechanism.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002267 mov(eax, actual.immediate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002268 cmp(expected.reg(), actual.immediate());
2269 j(equal, &invoke);
2270 DCHECK(expected.reg().is(ebx));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002271 } else if (!expected.reg().is(actual.reg())) {
2272 // Both expected and actual are in (different) registers. This
2273 // is the case when we invoke functions using call and apply.
2274 cmp(expected.reg(), actual.reg());
2275 j(equal, &invoke);
2276 DCHECK(actual.reg().is(eax));
2277 DCHECK(expected.reg().is(ebx));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002278 } else {
2279 Move(eax, actual.reg());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002280 }
2281 }
2282
2283 if (!definitely_matches) {
2284 Handle<Code> adaptor =
2285 isolate()->builtins()->ArgumentsAdaptorTrampoline();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002286 if (flag == CALL_FUNCTION) {
2287 call_wrapper.BeforeCall(CallSize(adaptor, RelocInfo::CODE_TARGET));
2288 call(adaptor, RelocInfo::CODE_TARGET);
2289 call_wrapper.AfterCall();
2290 if (!*definitely_mismatches) {
2291 jmp(done, done_near);
2292 }
2293 } else {
2294 jmp(adaptor, RelocInfo::CODE_TARGET);
2295 }
2296 bind(&invoke);
2297 }
2298}
2299
2300
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002301void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target,
2302 const ParameterCount& expected,
2303 const ParameterCount& actual) {
2304 Label skip_flooding;
Ben Murdoch61f157c2016-09-16 13:49:30 +01002305 ExternalReference last_step_action =
2306 ExternalReference::debug_last_step_action_address(isolate());
2307 STATIC_ASSERT(StepFrame > StepIn);
2308 cmpb(Operand::StaticVariable(last_step_action), Immediate(StepIn));
2309 j(less, &skip_flooding);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002310 {
2311 FrameScope frame(this,
2312 has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
2313 if (expected.is_reg()) {
2314 SmiTag(expected.reg());
2315 Push(expected.reg());
2316 }
2317 if (actual.is_reg()) {
2318 SmiTag(actual.reg());
2319 Push(actual.reg());
2320 }
2321 if (new_target.is_valid()) {
2322 Push(new_target);
2323 }
2324 Push(fun);
2325 Push(fun);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002326 CallRuntime(Runtime::kDebugPrepareStepInIfStepping);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002327 Pop(fun);
2328 if (new_target.is_valid()) {
2329 Pop(new_target);
2330 }
2331 if (actual.is_reg()) {
2332 Pop(actual.reg());
2333 SmiUntag(actual.reg());
2334 }
2335 if (expected.is_reg()) {
2336 Pop(expected.reg());
2337 SmiUntag(expected.reg());
2338 }
2339 }
2340 bind(&skip_flooding);
2341}
2342
2343
2344void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
2345 const ParameterCount& expected,
2346 const ParameterCount& actual,
2347 InvokeFlag flag,
2348 const CallWrapper& call_wrapper) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002349 // You can't call a function without a valid frame.
2350 DCHECK(flag == JUMP_FUNCTION || has_frame());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002351 DCHECK(function.is(edi));
2352 DCHECK_IMPLIES(new_target.is_valid(), new_target.is(edx));
2353
2354 if (call_wrapper.NeedsDebugStepCheck()) {
2355 FloodFunctionIfStepping(function, new_target, expected, actual);
2356 }
2357
2358 // Clear the new.target register if not given.
2359 if (!new_target.is_valid()) {
2360 mov(edx, isolate()->factory()->undefined_value());
2361 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002362
2363 Label done;
2364 bool definitely_mismatches = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002365 InvokePrologue(expected, actual, &done, &definitely_mismatches, flag,
2366 Label::kNear, call_wrapper);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002367 if (!definitely_mismatches) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002368 // We call indirectly through the code field in the function to
2369 // allow recompilation to take effect without changing any of the
2370 // call sites.
2371 Operand code = FieldOperand(function, JSFunction::kCodeEntryOffset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002372 if (flag == CALL_FUNCTION) {
2373 call_wrapper.BeforeCall(CallSize(code));
2374 call(code);
2375 call_wrapper.AfterCall();
2376 } else {
2377 DCHECK(flag == JUMP_FUNCTION);
2378 jmp(code);
2379 }
2380 bind(&done);
2381 }
2382}
2383
2384
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002385void MacroAssembler::InvokeFunction(Register fun, Register new_target,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002386 const ParameterCount& actual,
2387 InvokeFlag flag,
2388 const CallWrapper& call_wrapper) {
2389 // You can't call a function without a valid frame.
2390 DCHECK(flag == JUMP_FUNCTION || has_frame());
2391
2392 DCHECK(fun.is(edi));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002393 mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002394 mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002395 mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kFormalParameterCountOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002396 SmiUntag(ebx);
2397
2398 ParameterCount expected(ebx);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002399 InvokeFunctionCode(edi, new_target, expected, actual, flag, call_wrapper);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002400}
2401
2402
2403void MacroAssembler::InvokeFunction(Register fun,
2404 const ParameterCount& expected,
2405 const ParameterCount& actual,
2406 InvokeFlag flag,
2407 const CallWrapper& call_wrapper) {
2408 // You can't call a function without a valid frame.
2409 DCHECK(flag == JUMP_FUNCTION || has_frame());
2410
2411 DCHECK(fun.is(edi));
2412 mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2413
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002414 InvokeFunctionCode(edi, no_reg, expected, actual, flag, call_wrapper);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002415}
2416
2417
2418void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
2419 const ParameterCount& expected,
2420 const ParameterCount& actual,
2421 InvokeFlag flag,
2422 const CallWrapper& call_wrapper) {
2423 LoadHeapObject(edi, function);
2424 InvokeFunction(edi, expected, actual, flag, call_wrapper);
2425}
2426
2427
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002428void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
2429 if (context_chain_length > 0) {
2430 // Move up the chain of contexts to the context containing the slot.
2431 mov(dst, Operand(esi, Context::SlotOffset(Context::PREVIOUS_INDEX)));
2432 for (int i = 1; i < context_chain_length; i++) {
2433 mov(dst, Operand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX)));
2434 }
2435 } else {
2436 // Slot is in the current function context. Move it into the
2437 // destination register in case we store into it (the write barrier
2438 // cannot be allowed to destroy the context in esi).
2439 mov(dst, esi);
2440 }
2441
2442 // We should not have found a with context by walking the context chain
2443 // (i.e., the static scope chain and runtime context chain do not agree).
2444 // A variable occurring in such a scope should have slot type LOOKUP and
2445 // not CONTEXT.
2446 if (emit_debug_code()) {
2447 cmp(FieldOperand(dst, HeapObject::kMapOffset),
2448 isolate()->factory()->with_context_map());
2449 Check(not_equal, kVariableResolvedToWithContext);
2450 }
2451}
2452
2453
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002454void MacroAssembler::LoadGlobalProxy(Register dst) {
2455 mov(dst, NativeContextOperand());
2456 mov(dst, ContextOperand(dst, Context::GLOBAL_PROXY_INDEX));
2457}
2458
2459
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002460void MacroAssembler::LoadTransitionedArrayMapConditional(
2461 ElementsKind expected_kind,
2462 ElementsKind transitioned_kind,
2463 Register map_in_out,
2464 Register scratch,
2465 Label* no_map_match) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002466 DCHECK(IsFastElementsKind(expected_kind));
2467 DCHECK(IsFastElementsKind(transitioned_kind));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002468
2469 // Check that the function's map is the same as the expected cached map.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002470 mov(scratch, NativeContextOperand());
2471 cmp(map_in_out,
2472 ContextOperand(scratch, Context::ArrayMapIndex(expected_kind)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002473 j(not_equal, no_map_match);
2474
2475 // Use the transitioned cached map.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002476 mov(map_in_out,
2477 ContextOperand(scratch, Context::ArrayMapIndex(transitioned_kind)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002478}
2479
2480
2481void MacroAssembler::LoadGlobalFunction(int index, Register function) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002482 // Load the native context from the current context.
2483 mov(function, NativeContextOperand());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002484 // Load the function from the native context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002485 mov(function, ContextOperand(function, index));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002486}
2487
2488
2489void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
2490 Register map) {
2491 // Load the initial map. The global functions all have initial maps.
2492 mov(map, FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2493 if (emit_debug_code()) {
2494 Label ok, fail;
2495 CheckMap(map, isolate()->factory()->meta_map(), &fail, DO_SMI_CHECK);
2496 jmp(&ok);
2497 bind(&fail);
2498 Abort(kGlobalFunctionsMustHaveInitialMap);
2499 bind(&ok);
2500 }
2501}
2502
2503
2504// Store the value in register src in the safepoint register stack
2505// slot for register dst.
2506void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, Register src) {
2507 mov(SafepointRegisterSlot(dst), src);
2508}
2509
2510
2511void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, Immediate src) {
2512 mov(SafepointRegisterSlot(dst), src);
2513}
2514
2515
2516void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) {
2517 mov(dst, SafepointRegisterSlot(src));
2518}
2519
2520
2521Operand MacroAssembler::SafepointRegisterSlot(Register reg) {
2522 return Operand(esp, SafepointRegisterStackIndex(reg.code()) * kPointerSize);
2523}
2524
2525
2526int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
2527 // The registers are pushed starting with the lowest encoding,
2528 // which means that lowest encodings are furthest away from
2529 // the stack pointer.
2530 DCHECK(reg_code >= 0 && reg_code < kNumSafepointRegisters);
2531 return kNumSafepointRegisters - reg_code - 1;
2532}
2533
2534
2535void MacroAssembler::LoadHeapObject(Register result,
2536 Handle<HeapObject> object) {
2537 AllowDeferredHandleDereference embedding_raw_address;
2538 if (isolate()->heap()->InNewSpace(*object)) {
2539 Handle<Cell> cell = isolate()->factory()->NewCell(object);
2540 mov(result, Operand::ForCell(cell));
2541 } else {
2542 mov(result, object);
2543 }
2544}
2545
2546
2547void MacroAssembler::CmpHeapObject(Register reg, Handle<HeapObject> object) {
2548 AllowDeferredHandleDereference using_raw_address;
2549 if (isolate()->heap()->InNewSpace(*object)) {
2550 Handle<Cell> cell = isolate()->factory()->NewCell(object);
2551 cmp(reg, Operand::ForCell(cell));
2552 } else {
2553 cmp(reg, object);
2554 }
2555}
2556
2557
2558void MacroAssembler::PushHeapObject(Handle<HeapObject> object) {
2559 AllowDeferredHandleDereference using_raw_address;
2560 if (isolate()->heap()->InNewSpace(*object)) {
2561 Handle<Cell> cell = isolate()->factory()->NewCell(object);
2562 push(Operand::ForCell(cell));
2563 } else {
2564 Push(object);
2565 }
2566}
2567
2568
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002569void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell,
2570 Register scratch) {
2571 mov(scratch, cell);
2572 cmp(value, FieldOperand(scratch, WeakCell::kValueOffset));
2573}
2574
2575
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002576void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002577 mov(value, cell);
2578 mov(value, FieldOperand(value, WeakCell::kValueOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002579}
2580
2581
2582void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
2583 Label* miss) {
2584 GetWeakValue(value, cell);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002585 JumpIfSmi(value, miss);
2586}
2587
2588
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002589void MacroAssembler::Ret() {
2590 ret(0);
2591}
2592
2593
2594void MacroAssembler::Ret(int bytes_dropped, Register scratch) {
2595 if (is_uint16(bytes_dropped)) {
2596 ret(bytes_dropped);
2597 } else {
2598 pop(scratch);
2599 add(esp, Immediate(bytes_dropped));
2600 push(scratch);
2601 ret(0);
2602 }
2603}
2604
2605
2606void MacroAssembler::VerifyX87StackDepth(uint32_t depth) {
2607 // Turn off the stack depth check when serializer is enabled to reduce the
2608 // code size.
2609 if (serializer_enabled()) return;
2610 // Make sure the floating point stack is either empty or has depth items.
2611 DCHECK(depth <= 7);
2612 // This is very expensive.
2613 DCHECK(FLAG_debug_code && FLAG_enable_slow_asserts);
2614
2615 // The top-of-stack (tos) is 7 if there is one item pushed.
2616 int tos = (8 - depth) % 8;
2617 const int kTopMask = 0x3800;
2618 push(eax);
2619 fwait();
2620 fnstsw_ax();
2621 and_(eax, kTopMask);
2622 shr(eax, 11);
2623 cmp(eax, Immediate(tos));
2624 Check(equal, kUnexpectedFPUStackDepthAfterInstruction);
2625 fnclex();
2626 pop(eax);
2627}
2628
2629
2630void MacroAssembler::Drop(int stack_elements) {
2631 if (stack_elements > 0) {
2632 add(esp, Immediate(stack_elements * kPointerSize));
2633 }
2634}
2635
2636
2637void MacroAssembler::Move(Register dst, Register src) {
2638 if (!dst.is(src)) {
2639 mov(dst, src);
2640 }
2641}
2642
2643
2644void MacroAssembler::Move(Register dst, const Immediate& x) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01002645 if (x.is_zero() && RelocInfo::IsNone(x.rmode_)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002646 xor_(dst, dst); // Shorter than mov of 32-bit immediate 0.
2647 } else {
2648 mov(dst, x);
2649 }
2650}
2651
2652
2653void MacroAssembler::Move(const Operand& dst, const Immediate& x) {
2654 mov(dst, x);
2655}
2656
2657
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002658void MacroAssembler::Lzcnt(Register dst, const Operand& src) {
2659 // TODO(intel): Add support for LZCNT (with ABM/BMI1).
2660 Label not_zero_src;
2661 bsr(dst, src);
2662 j(not_zero, &not_zero_src, Label::kNear);
2663 Move(dst, Immediate(63)); // 63^31 == 32
2664 bind(&not_zero_src);
2665 xor_(dst, Immediate(31)); // for x in [0..31], 31^x == 31-x.
2666}
2667
2668
2669void MacroAssembler::Tzcnt(Register dst, const Operand& src) {
2670 // TODO(intel): Add support for TZCNT (with ABM/BMI1).
2671 Label not_zero_src;
2672 bsf(dst, src);
2673 j(not_zero, &not_zero_src, Label::kNear);
2674 Move(dst, Immediate(32)); // The result of tzcnt is 32 if src = 0.
2675 bind(&not_zero_src);
2676}
2677
2678
2679void MacroAssembler::Popcnt(Register dst, const Operand& src) {
2680 // TODO(intel): Add support for POPCNT (with POPCNT)
2681 // if (CpuFeatures::IsSupported(POPCNT)) {
2682 // CpuFeatureScope scope(this, POPCNT);
2683 // popcnt(dst, src);
2684 // return;
2685 // }
2686 UNREACHABLE();
2687}
2688
2689
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002690void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
2691 if (FLAG_native_code_counters && counter->Enabled()) {
2692 mov(Operand::StaticVariable(ExternalReference(counter)), Immediate(value));
2693 }
2694}
2695
2696
2697void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) {
2698 DCHECK(value > 0);
2699 if (FLAG_native_code_counters && counter->Enabled()) {
2700 Operand operand = Operand::StaticVariable(ExternalReference(counter));
2701 if (value == 1) {
2702 inc(operand);
2703 } else {
2704 add(operand, Immediate(value));
2705 }
2706 }
2707}
2708
2709
2710void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) {
2711 DCHECK(value > 0);
2712 if (FLAG_native_code_counters && counter->Enabled()) {
2713 Operand operand = Operand::StaticVariable(ExternalReference(counter));
2714 if (value == 1) {
2715 dec(operand);
2716 } else {
2717 sub(operand, Immediate(value));
2718 }
2719 }
2720}
2721
2722
2723void MacroAssembler::IncrementCounter(Condition cc,
2724 StatsCounter* counter,
2725 int value) {
2726 DCHECK(value > 0);
2727 if (FLAG_native_code_counters && counter->Enabled()) {
2728 Label skip;
2729 j(NegateCondition(cc), &skip);
2730 pushfd();
2731 IncrementCounter(counter, value);
2732 popfd();
2733 bind(&skip);
2734 }
2735}
2736
2737
2738void MacroAssembler::DecrementCounter(Condition cc,
2739 StatsCounter* counter,
2740 int value) {
2741 DCHECK(value > 0);
2742 if (FLAG_native_code_counters && counter->Enabled()) {
2743 Label skip;
2744 j(NegateCondition(cc), &skip);
2745 pushfd();
2746 DecrementCounter(counter, value);
2747 popfd();
2748 bind(&skip);
2749 }
2750}
2751
2752
2753void MacroAssembler::Assert(Condition cc, BailoutReason reason) {
2754 if (emit_debug_code()) Check(cc, reason);
2755}
2756
2757
2758void MacroAssembler::AssertFastElements(Register elements) {
2759 if (emit_debug_code()) {
2760 Factory* factory = isolate()->factory();
2761 Label ok;
2762 cmp(FieldOperand(elements, HeapObject::kMapOffset),
2763 Immediate(factory->fixed_array_map()));
2764 j(equal, &ok);
2765 cmp(FieldOperand(elements, HeapObject::kMapOffset),
2766 Immediate(factory->fixed_double_array_map()));
2767 j(equal, &ok);
2768 cmp(FieldOperand(elements, HeapObject::kMapOffset),
2769 Immediate(factory->fixed_cow_array_map()));
2770 j(equal, &ok);
2771 Abort(kJSObjectWithFastElementsMapHasSlowElements);
2772 bind(&ok);
2773 }
2774}
2775
2776
2777void MacroAssembler::Check(Condition cc, BailoutReason reason) {
2778 Label L;
2779 j(cc, &L);
2780 Abort(reason);
2781 // will not return here
2782 bind(&L);
2783}
2784
2785
2786void MacroAssembler::CheckStackAlignment() {
2787 int frame_alignment = base::OS::ActivationFrameAlignment();
2788 int frame_alignment_mask = frame_alignment - 1;
2789 if (frame_alignment > kPointerSize) {
2790 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
2791 Label alignment_as_expected;
2792 test(esp, Immediate(frame_alignment_mask));
2793 j(zero, &alignment_as_expected);
2794 // Abort if stack is not aligned.
2795 int3();
2796 bind(&alignment_as_expected);
2797 }
2798}
2799
2800
2801void MacroAssembler::Abort(BailoutReason reason) {
2802#ifdef DEBUG
2803 const char* msg = GetBailoutReason(reason);
2804 if (msg != NULL) {
2805 RecordComment("Abort message: ");
2806 RecordComment(msg);
2807 }
2808
2809 if (FLAG_trap_on_abort) {
2810 int3();
2811 return;
2812 }
2813#endif
2814
2815 push(Immediate(reinterpret_cast<intptr_t>(Smi::FromInt(reason))));
2816 // Disable stub call restrictions to always allow calls to abort.
2817 if (!has_frame_) {
2818 // We don't actually want to generate a pile of code for this, so just
2819 // claim there is a stack frame, without generating one.
2820 FrameScope scope(this, StackFrame::NONE);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002821 CallRuntime(Runtime::kAbort);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002822 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002823 CallRuntime(Runtime::kAbort);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002824 }
2825 // will not return here
2826 int3();
2827}
2828
2829
2830void MacroAssembler::LoadInstanceDescriptors(Register map,
2831 Register descriptors) {
2832 mov(descriptors, FieldOperand(map, Map::kDescriptorsOffset));
2833}
2834
2835
2836void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) {
2837 mov(dst, FieldOperand(map, Map::kBitField3Offset));
2838 DecodeField<Map::NumberOfOwnDescriptorsBits>(dst);
2839}
2840
2841
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002842void MacroAssembler::LoadAccessor(Register dst, Register holder,
2843 int accessor_index,
2844 AccessorComponent accessor) {
2845 mov(dst, FieldOperand(holder, HeapObject::kMapOffset));
2846 LoadInstanceDescriptors(dst, dst);
2847 mov(dst, FieldOperand(dst, DescriptorArray::GetValueOffset(accessor_index)));
2848 int offset = accessor == ACCESSOR_GETTER ? AccessorPair::kGetterOffset
2849 : AccessorPair::kSetterOffset;
2850 mov(dst, FieldOperand(dst, offset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002851}
2852
2853
2854void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte(
2855 Register instance_type, Register scratch, Label* failure) {
2856 if (!scratch.is(instance_type)) {
2857 mov(scratch, instance_type);
2858 }
2859 and_(scratch,
2860 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask);
2861 cmp(scratch, kStringTag | kSeqStringTag | kOneByteStringTag);
2862 j(not_equal, failure);
2863}
2864
2865
2866void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register object1,
2867 Register object2,
2868 Register scratch1,
2869 Register scratch2,
2870 Label* failure) {
2871 // Check that both objects are not smis.
2872 STATIC_ASSERT(kSmiTag == 0);
2873 mov(scratch1, object1);
2874 and_(scratch1, object2);
2875 JumpIfSmi(scratch1, failure);
2876
2877 // Load instance type for both strings.
2878 mov(scratch1, FieldOperand(object1, HeapObject::kMapOffset));
2879 mov(scratch2, FieldOperand(object2, HeapObject::kMapOffset));
2880 movzx_b(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset));
2881 movzx_b(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset));
2882
2883 // Check that both are flat one-byte strings.
2884 const int kFlatOneByteStringMask =
2885 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
2886 const int kFlatOneByteStringTag =
2887 kStringTag | kOneByteStringTag | kSeqStringTag;
2888 // Interleave bits from both instance types and compare them in one check.
2889 DCHECK_EQ(0, kFlatOneByteStringMask & (kFlatOneByteStringMask << 3));
2890 and_(scratch1, kFlatOneByteStringMask);
2891 and_(scratch2, kFlatOneByteStringMask);
2892 lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
2893 cmp(scratch1, kFlatOneByteStringTag | (kFlatOneByteStringTag << 3));
2894 j(not_equal, failure);
2895}
2896
2897
2898void MacroAssembler::JumpIfNotUniqueNameInstanceType(Operand operand,
2899 Label* not_unique_name,
2900 Label::Distance distance) {
2901 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
2902 Label succeed;
2903 test(operand, Immediate(kIsNotStringMask | kIsNotInternalizedMask));
2904 j(zero, &succeed);
Ben Murdochda12d292016-06-02 14:46:10 +01002905 cmpb(operand, Immediate(SYMBOL_TYPE));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002906 j(not_equal, not_unique_name, distance);
2907
2908 bind(&succeed);
2909}
2910
2911
2912void MacroAssembler::EmitSeqStringSetCharCheck(Register string,
2913 Register index,
2914 Register value,
2915 uint32_t encoding_mask) {
2916 Label is_object;
2917 JumpIfNotSmi(string, &is_object, Label::kNear);
2918 Abort(kNonObject);
2919 bind(&is_object);
2920
2921 push(value);
2922 mov(value, FieldOperand(string, HeapObject::kMapOffset));
2923 movzx_b(value, FieldOperand(value, Map::kInstanceTypeOffset));
2924
2925 and_(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
2926 cmp(value, Immediate(encoding_mask));
2927 pop(value);
2928 Check(equal, kUnexpectedStringType);
2929
2930 // The index is assumed to be untagged coming in, tag it to compare with the
2931 // string length without using a temp register, it is restored at the end of
2932 // this function.
2933 SmiTag(index);
2934 Check(no_overflow, kIndexIsTooLarge);
2935
2936 cmp(index, FieldOperand(string, String::kLengthOffset));
2937 Check(less, kIndexIsTooLarge);
2938
2939 cmp(index, Immediate(Smi::FromInt(0)));
2940 Check(greater_equal, kIndexIsNegative);
2941
2942 // Restore the index
2943 SmiUntag(index);
2944}
2945
2946
2947void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) {
2948 int frame_alignment = base::OS::ActivationFrameAlignment();
2949 if (frame_alignment != 0) {
2950 // Make stack end at alignment and make room for num_arguments words
2951 // and the original value of esp.
2952 mov(scratch, esp);
2953 sub(esp, Immediate((num_arguments + 1) * kPointerSize));
2954 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
2955 and_(esp, -frame_alignment);
2956 mov(Operand(esp, num_arguments * kPointerSize), scratch);
2957 } else {
2958 sub(esp, Immediate(num_arguments * kPointerSize));
2959 }
2960}
2961
2962
2963void MacroAssembler::CallCFunction(ExternalReference function,
2964 int num_arguments) {
2965 // Trashing eax is ok as it will be the return value.
2966 mov(eax, Immediate(function));
2967 CallCFunction(eax, num_arguments);
2968}
2969
2970
2971void MacroAssembler::CallCFunction(Register function,
2972 int num_arguments) {
2973 DCHECK(has_frame());
2974 // Check stack alignment.
2975 if (emit_debug_code()) {
2976 CheckStackAlignment();
2977 }
2978
2979 call(function);
2980 if (base::OS::ActivationFrameAlignment() != 0) {
2981 mov(esp, Operand(esp, num_arguments * kPointerSize));
2982 } else {
2983 add(esp, Immediate(num_arguments * kPointerSize));
2984 }
2985}
2986
2987
2988#ifdef DEBUG
2989bool AreAliased(Register reg1,
2990 Register reg2,
2991 Register reg3,
2992 Register reg4,
2993 Register reg5,
2994 Register reg6,
2995 Register reg7,
2996 Register reg8) {
2997 int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() +
2998 reg3.is_valid() + reg4.is_valid() + reg5.is_valid() + reg6.is_valid() +
2999 reg7.is_valid() + reg8.is_valid();
3000
3001 RegList regs = 0;
3002 if (reg1.is_valid()) regs |= reg1.bit();
3003 if (reg2.is_valid()) regs |= reg2.bit();
3004 if (reg3.is_valid()) regs |= reg3.bit();
3005 if (reg4.is_valid()) regs |= reg4.bit();
3006 if (reg5.is_valid()) regs |= reg5.bit();
3007 if (reg6.is_valid()) regs |= reg6.bit();
3008 if (reg7.is_valid()) regs |= reg7.bit();
3009 if (reg8.is_valid()) regs |= reg8.bit();
3010 int n_of_non_aliasing_regs = NumRegs(regs);
3011
3012 return n_of_valid_regs != n_of_non_aliasing_regs;
3013}
3014#endif
3015
3016
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003017CodePatcher::CodePatcher(Isolate* isolate, byte* address, int size)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003018 : address_(address),
3019 size_(size),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003020 masm_(isolate, address, size + Assembler::kGap, CodeObjectRequired::kNo) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003021 // Create a new macro assembler pointing to the address of the code to patch.
3022 // The size is adjusted with kGap on order for the assembler to generate size
3023 // bytes of instructions without failing with buffer size constraints.
3024 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
3025}
3026
3027
3028CodePatcher::~CodePatcher() {
3029 // Indicate that code has changed.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003030 Assembler::FlushICache(masm_.isolate(), address_, size_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003031
3032 // Check that the code was patched as expected.
3033 DCHECK(masm_.pc_ == address_ + size_);
3034 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
3035}
3036
3037
3038void MacroAssembler::CheckPageFlag(
3039 Register object,
3040 Register scratch,
3041 int mask,
3042 Condition cc,
3043 Label* condition_met,
3044 Label::Distance condition_met_distance) {
3045 DCHECK(cc == zero || cc == not_zero);
3046 if (scratch.is(object)) {
3047 and_(scratch, Immediate(~Page::kPageAlignmentMask));
3048 } else {
3049 mov(scratch, Immediate(~Page::kPageAlignmentMask));
3050 and_(scratch, object);
3051 }
3052 if (mask < (1 << kBitsPerByte)) {
Ben Murdochda12d292016-06-02 14:46:10 +01003053 test_b(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003054 } else {
3055 test(Operand(scratch, MemoryChunk::kFlagsOffset), Immediate(mask));
3056 }
3057 j(cc, condition_met, condition_met_distance);
3058}
3059
3060
3061void MacroAssembler::CheckPageFlagForMap(
3062 Handle<Map> map,
3063 int mask,
3064 Condition cc,
3065 Label* condition_met,
3066 Label::Distance condition_met_distance) {
3067 DCHECK(cc == zero || cc == not_zero);
3068 Page* page = Page::FromAddress(map->address());
3069 DCHECK(!serializer_enabled()); // Serializer cannot match page_flags.
3070 ExternalReference reference(ExternalReference::page_flags(page));
3071 // The inlined static address check of the page's flags relies
3072 // on maps never being compacted.
3073 DCHECK(!isolate()->heap()->mark_compact_collector()->
3074 IsOnEvacuationCandidate(*map));
3075 if (mask < (1 << kBitsPerByte)) {
Ben Murdochda12d292016-06-02 14:46:10 +01003076 test_b(Operand::StaticVariable(reference), Immediate(mask));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003077 } else {
3078 test(Operand::StaticVariable(reference), Immediate(mask));
3079 }
3080 j(cc, condition_met, condition_met_distance);
3081}
3082
3083
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003084void MacroAssembler::JumpIfBlack(Register object,
3085 Register scratch0,
3086 Register scratch1,
3087 Label* on_black,
3088 Label::Distance on_black_near) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003089 HasColor(object, scratch0, scratch1, on_black, on_black_near, 1,
3090 1); // kBlackBitPattern.
3091 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003092}
3093
3094
3095void MacroAssembler::HasColor(Register object,
3096 Register bitmap_scratch,
3097 Register mask_scratch,
3098 Label* has_color,
3099 Label::Distance has_color_distance,
3100 int first_bit,
3101 int second_bit) {
3102 DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, ecx));
3103
3104 GetMarkBits(object, bitmap_scratch, mask_scratch);
3105
3106 Label other_color, word_boundary;
3107 test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
3108 j(first_bit == 1 ? zero : not_zero, &other_color, Label::kNear);
3109 add(mask_scratch, mask_scratch); // Shift left 1 by adding.
3110 j(zero, &word_boundary, Label::kNear);
3111 test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
3112 j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance);
3113 jmp(&other_color, Label::kNear);
3114
3115 bind(&word_boundary);
Ben Murdochda12d292016-06-02 14:46:10 +01003116 test_b(Operand(bitmap_scratch, MemoryChunk::kHeaderSize + kPointerSize),
3117 Immediate(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003118
3119 j(second_bit == 1 ? not_zero : zero, has_color, has_color_distance);
3120 bind(&other_color);
3121}
3122
3123
3124void MacroAssembler::GetMarkBits(Register addr_reg,
3125 Register bitmap_reg,
3126 Register mask_reg) {
3127 DCHECK(!AreAliased(addr_reg, mask_reg, bitmap_reg, ecx));
3128 mov(bitmap_reg, Immediate(~Page::kPageAlignmentMask));
3129 and_(bitmap_reg, addr_reg);
3130 mov(ecx, addr_reg);
3131 int shift =
3132 Bitmap::kBitsPerCellLog2 + kPointerSizeLog2 - Bitmap::kBytesPerCellLog2;
3133 shr(ecx, shift);
3134 and_(ecx,
3135 (Page::kPageAlignmentMask >> shift) & ~(Bitmap::kBytesPerCell - 1));
3136
3137 add(bitmap_reg, ecx);
3138 mov(ecx, addr_reg);
3139 shr(ecx, kPointerSizeLog2);
3140 and_(ecx, (1 << Bitmap::kBitsPerCellLog2) - 1);
3141 mov(mask_reg, Immediate(1));
3142 shl_cl(mask_reg);
3143}
3144
3145
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003146void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch,
3147 Register mask_scratch, Label* value_is_white,
3148 Label::Distance distance) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003149 DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, ecx));
3150 GetMarkBits(value, bitmap_scratch, mask_scratch);
3151
3152 // If the value is black or grey we don't need to do anything.
3153 DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003154 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
3155 DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003156 DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
3157
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003158 // Since both black and grey have a 1 in the first position and white does
3159 // not have a 1 there we only need to check one bit.
3160 test(mask_scratch, Operand(bitmap_scratch, MemoryChunk::kHeaderSize));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003161 j(zero, value_is_white, Label::kNear);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003162}
3163
3164
3165void MacroAssembler::EnumLength(Register dst, Register map) {
3166 STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
3167 mov(dst, FieldOperand(map, Map::kBitField3Offset));
3168 and_(dst, Immediate(Map::EnumLengthBits::kMask));
3169 SmiTag(dst);
3170}
3171
3172
3173void MacroAssembler::CheckEnumCache(Label* call_runtime) {
3174 Label next, start;
3175 mov(ecx, eax);
3176
3177 // Check if the enum length field is properly initialized, indicating that
3178 // there is an enum cache.
3179 mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
3180
3181 EnumLength(edx, ebx);
3182 cmp(edx, Immediate(Smi::FromInt(kInvalidEnumCacheSentinel)));
3183 j(equal, call_runtime);
3184
3185 jmp(&start);
3186
3187 bind(&next);
3188 mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
3189
3190 // For all objects but the receiver, check that the cache is empty.
3191 EnumLength(edx, ebx);
3192 cmp(edx, Immediate(Smi::FromInt(0)));
3193 j(not_equal, call_runtime);
3194
3195 bind(&start);
3196
3197 // Check that there are no elements. Register rcx contains the current JS
3198 // object we've reached through the prototype chain.
3199 Label no_elements;
3200 mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset));
3201 cmp(ecx, isolate()->factory()->empty_fixed_array());
3202 j(equal, &no_elements);
3203
3204 // Second chance, the object may be using the empty slow element dictionary.
3205 cmp(ecx, isolate()->factory()->empty_slow_element_dictionary());
3206 j(not_equal, call_runtime);
3207
3208 bind(&no_elements);
3209 mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
3210 cmp(ecx, isolate()->factory()->null_value());
3211 j(not_equal, &next);
3212}
3213
3214
3215void MacroAssembler::TestJSArrayForAllocationMemento(
3216 Register receiver_reg,
3217 Register scratch_reg,
3218 Label* no_memento_found) {
Ben Murdochda12d292016-06-02 14:46:10 +01003219 Label map_check;
3220 Label top_check;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003221 ExternalReference new_space_allocation_top =
3222 ExternalReference::new_space_allocation_top_address(isolate());
Ben Murdochda12d292016-06-02 14:46:10 +01003223 const int kMementoMapOffset = JSArray::kSize - kHeapObjectTag;
3224 const int kMementoEndOffset = kMementoMapOffset + AllocationMemento::kSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003225
Ben Murdochda12d292016-06-02 14:46:10 +01003226 // Bail out if the object is not in new space.
3227 JumpIfNotInNewSpace(receiver_reg, scratch_reg, no_memento_found);
3228 // If the object is in new space, we need to check whether it is on the same
3229 // page as the current top.
3230 lea(scratch_reg, Operand(receiver_reg, kMementoEndOffset));
3231 xor_(scratch_reg, Operand::StaticVariable(new_space_allocation_top));
3232 test(scratch_reg, Immediate(~Page::kPageAlignmentMask));
3233 j(zero, &top_check);
3234 // The object is on a different page than allocation top. Bail out if the
3235 // object sits on the page boundary as no memento can follow and we cannot
3236 // touch the memory following it.
3237 lea(scratch_reg, Operand(receiver_reg, kMementoEndOffset));
3238 xor_(scratch_reg, receiver_reg);
3239 test(scratch_reg, Immediate(~Page::kPageAlignmentMask));
3240 j(not_zero, no_memento_found);
3241 // Continue with the actual map check.
3242 jmp(&map_check);
3243 // If top is on the same page as the current object, we need to check whether
3244 // we are below top.
3245 bind(&top_check);
3246 lea(scratch_reg, Operand(receiver_reg, kMementoEndOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003247 cmp(scratch_reg, Operand::StaticVariable(new_space_allocation_top));
3248 j(greater, no_memento_found);
Ben Murdochda12d292016-06-02 14:46:10 +01003249 // Memento map check.
3250 bind(&map_check);
3251 mov(scratch_reg, Operand(receiver_reg, kMementoMapOffset));
3252 cmp(scratch_reg, Immediate(isolate()->factory()->allocation_memento_map()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003253}
3254
3255
3256void MacroAssembler::JumpIfDictionaryInPrototypeChain(
3257 Register object,
3258 Register scratch0,
3259 Register scratch1,
3260 Label* found) {
3261 DCHECK(!scratch1.is(scratch0));
3262 Factory* factory = isolate()->factory();
3263 Register current = scratch0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003264 Label loop_again, end;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003265
3266 // scratch contained elements pointer.
3267 mov(current, object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003268 mov(current, FieldOperand(current, HeapObject::kMapOffset));
3269 mov(current, FieldOperand(current, Map::kPrototypeOffset));
3270 cmp(current, Immediate(factory->null_value()));
3271 j(equal, &end);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003272
3273 // Loop based on the map going up the prototype chain.
3274 bind(&loop_again);
3275 mov(current, FieldOperand(current, HeapObject::kMapOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003276 STATIC_ASSERT(JS_PROXY_TYPE < JS_OBJECT_TYPE);
3277 STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE);
3278 CmpInstanceType(current, JS_OBJECT_TYPE);
3279 j(below, found);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003280 mov(scratch1, FieldOperand(current, Map::kBitField2Offset));
3281 DecodeField<Map::ElementsKindBits>(scratch1);
3282 cmp(scratch1, Immediate(DICTIONARY_ELEMENTS));
3283 j(equal, found);
3284 mov(current, FieldOperand(current, Map::kPrototypeOffset));
3285 cmp(current, Immediate(factory->null_value()));
3286 j(not_equal, &loop_again);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003287
3288 bind(&end);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003289}
3290
3291
3292void MacroAssembler::TruncatingDiv(Register dividend, int32_t divisor) {
3293 DCHECK(!dividend.is(eax));
3294 DCHECK(!dividend.is(edx));
3295 base::MagicNumbersForDivision<uint32_t> mag =
3296 base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
3297 mov(eax, Immediate(mag.multiplier));
3298 imul(dividend);
3299 bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
3300 if (divisor > 0 && neg) add(edx, dividend);
3301 if (divisor < 0 && !neg && mag.multiplier > 0) sub(edx, dividend);
3302 if (mag.shift > 0) sar(edx, mag.shift);
3303 mov(eax, dividend);
3304 shr(eax, 31);
3305 add(edx, eax);
3306}
3307
3308
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003309} // namespace internal
3310} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003311
3312#endif // V8_TARGET_ARCH_X87