blob: ca48614cc4190d443163de00a790b2227a67ec42 [file] [log] [blame]
Ben Murdochda12d292016-06-02 14:46:10 +01001// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <assert.h> // For assert
6#include <limits.h> // For LONG_MIN, LONG_MAX.
7
8#if V8_TARGET_ARCH_S390
9
10#include "src/base/bits.h"
11#include "src/base/division-by-constant.h"
12#include "src/bootstrapper.h"
13#include "src/codegen.h"
14#include "src/debug/debug.h"
15#include "src/register-configuration.h"
16#include "src/runtime/runtime.h"
17
18#include "src/s390/macro-assembler-s390.h"
19
20namespace v8 {
21namespace internal {
22
23MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size,
24 CodeObjectRequired create_code_object)
25 : Assembler(arg_isolate, buffer, size),
26 generating_stub_(false),
27 has_frame_(false) {
28 if (create_code_object == CodeObjectRequired::kYes) {
29 code_object_ =
30 Handle<Object>::New(isolate()->heap()->undefined_value(), isolate());
31 }
32}
33
34void MacroAssembler::Jump(Register target) { b(target); }
35
36void MacroAssembler::JumpToJSEntry(Register target) {
37 Move(ip, target);
38 Jump(ip);
39}
40
41void MacroAssembler::Jump(intptr_t target, RelocInfo::Mode rmode,
42 Condition cond, CRegister) {
43 Label skip;
44
45 if (cond != al) b(NegateCondition(cond), &skip);
46
47 DCHECK(rmode == RelocInfo::CODE_TARGET || rmode == RelocInfo::RUNTIME_ENTRY);
48
49 mov(ip, Operand(target, rmode));
50 b(ip);
51
52 bind(&skip);
53}
54
55void MacroAssembler::Jump(Address target, RelocInfo::Mode rmode, Condition cond,
56 CRegister cr) {
57 DCHECK(!RelocInfo::IsCodeTarget(rmode));
58 Jump(reinterpret_cast<intptr_t>(target), rmode, cond, cr);
59}
60
61void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
62 Condition cond) {
63 DCHECK(RelocInfo::IsCodeTarget(rmode));
64 jump(code, rmode, cond);
65}
66
67int MacroAssembler::CallSize(Register target) { return 2; } // BASR
68
69void MacroAssembler::Call(Register target) {
70 Label start;
71 bind(&start);
72
Ben Murdochda12d292016-06-02 14:46:10 +010073 // Branch to target via indirect branch
74 basr(r14, target);
75
76 DCHECK_EQ(CallSize(target), SizeOfCodeGeneratedSince(&start));
77}
78
79void MacroAssembler::CallJSEntry(Register target) {
80 DCHECK(target.is(ip));
81 Call(target);
82}
83
84int MacroAssembler::CallSize(Address target, RelocInfo::Mode rmode,
85 Condition cond) {
86 // S390 Assembler::move sequence is IILF / IIHF
87 int size;
88#if V8_TARGET_ARCH_S390X
89 size = 14; // IILF + IIHF + BASR
90#else
91 size = 8; // IILF + BASR
92#endif
93 return size;
94}
95
96int MacroAssembler::CallSizeNotPredictableCodeSize(Address target,
97 RelocInfo::Mode rmode,
98 Condition cond) {
99 // S390 Assembler::move sequence is IILF / IIHF
100 int size;
101#if V8_TARGET_ARCH_S390X
102 size = 14; // IILF + IIHF + BASR
103#else
104 size = 8; // IILF + BASR
105#endif
106 return size;
107}
108
109void MacroAssembler::Call(Address target, RelocInfo::Mode rmode,
110 Condition cond) {
111 DCHECK(cond == al);
112
113#ifdef DEBUG
114 // Check the expected size before generating code to ensure we assume the same
115 // constant pool availability (e.g., whether constant pool is full or not).
116 int expected_size = CallSize(target, rmode, cond);
117 Label start;
118 bind(&start);
119#endif
120
Ben Murdochda12d292016-06-02 14:46:10 +0100121 mov(ip, Operand(reinterpret_cast<intptr_t>(target), rmode));
122 basr(r14, ip);
123
124 DCHECK_EQ(expected_size, SizeOfCodeGeneratedSince(&start));
125}
126
127int MacroAssembler::CallSize(Handle<Code> code, RelocInfo::Mode rmode,
128 TypeFeedbackId ast_id, Condition cond) {
129 return 6; // BRASL
130}
131
132void MacroAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode,
133 TypeFeedbackId ast_id, Condition cond) {
134 DCHECK(RelocInfo::IsCodeTarget(rmode) && cond == al);
135
136#ifdef DEBUG
137 // Check the expected size before generating code to ensure we assume the same
138 // constant pool availability (e.g., whether constant pool is full or not).
139 int expected_size = CallSize(code, rmode, ast_id, cond);
140 Label start;
141 bind(&start);
142#endif
143 call(code, rmode, ast_id);
144 DCHECK_EQ(expected_size, SizeOfCodeGeneratedSince(&start));
145}
146
147void MacroAssembler::Drop(int count) {
148 if (count > 0) {
149 int total = count * kPointerSize;
150 if (is_uint12(total)) {
151 la(sp, MemOperand(sp, total));
152 } else if (is_int20(total)) {
153 lay(sp, MemOperand(sp, total));
154 } else {
155 AddP(sp, Operand(total));
156 }
157 }
158}
159
160void MacroAssembler::Drop(Register count, Register scratch) {
161 ShiftLeftP(scratch, count, Operand(kPointerSizeLog2));
162 AddP(sp, sp, scratch);
163}
164
165void MacroAssembler::Call(Label* target) { b(r14, target); }
166
167void MacroAssembler::Push(Handle<Object> handle) {
168 mov(r0, Operand(handle));
169 push(r0);
170}
171
172void MacroAssembler::Move(Register dst, Handle<Object> value) {
173 AllowDeferredHandleDereference smi_check;
174 if (value->IsSmi()) {
175 LoadSmiLiteral(dst, reinterpret_cast<Smi*>(*value));
176 } else {
177 DCHECK(value->IsHeapObject());
178 if (isolate()->heap()->InNewSpace(*value)) {
179 Handle<Cell> cell = isolate()->factory()->NewCell(value);
180 mov(dst, Operand(cell));
181 LoadP(dst, FieldMemOperand(dst, Cell::kValueOffset));
182 } else {
183 mov(dst, Operand(value));
184 }
185 }
186}
187
188void MacroAssembler::Move(Register dst, Register src, Condition cond) {
189 if (!dst.is(src)) {
190 LoadRR(dst, src);
191 }
192}
193
194void MacroAssembler::Move(DoubleRegister dst, DoubleRegister src) {
195 if (!dst.is(src)) {
196 ldr(dst, src);
197 }
198}
199
Ben Murdochda12d292016-06-02 14:46:10 +0100200void MacroAssembler::MultiPush(RegList regs, Register location) {
201 int16_t num_to_push = NumberOfBitsSet(regs);
202 int16_t stack_offset = num_to_push * kPointerSize;
203
204 SubP(location, location, Operand(stack_offset));
205 for (int16_t i = Register::kNumRegisters - 1; i >= 0; i--) {
206 if ((regs & (1 << i)) != 0) {
207 stack_offset -= kPointerSize;
208 StoreP(ToRegister(i), MemOperand(location, stack_offset));
209 }
210 }
211}
212
213void MacroAssembler::MultiPop(RegList regs, Register location) {
214 int16_t stack_offset = 0;
215
216 for (int16_t i = 0; i < Register::kNumRegisters; i++) {
217 if ((regs & (1 << i)) != 0) {
218 LoadP(ToRegister(i), MemOperand(location, stack_offset));
219 stack_offset += kPointerSize;
220 }
221 }
222 AddP(location, location, Operand(stack_offset));
223}
224
225void MacroAssembler::MultiPushDoubles(RegList dregs, Register location) {
226 int16_t num_to_push = NumberOfBitsSet(dregs);
227 int16_t stack_offset = num_to_push * kDoubleSize;
228
229 SubP(location, location, Operand(stack_offset));
230 for (int16_t i = DoubleRegister::kNumRegisters - 1; i >= 0; i--) {
231 if ((dregs & (1 << i)) != 0) {
232 DoubleRegister dreg = DoubleRegister::from_code(i);
233 stack_offset -= kDoubleSize;
234 StoreDouble(dreg, MemOperand(location, stack_offset));
235 }
236 }
237}
238
239void MacroAssembler::MultiPopDoubles(RegList dregs, Register location) {
240 int16_t stack_offset = 0;
241
242 for (int16_t i = 0; i < DoubleRegister::kNumRegisters; i++) {
243 if ((dregs & (1 << i)) != 0) {
244 DoubleRegister dreg = DoubleRegister::from_code(i);
245 LoadDouble(dreg, MemOperand(location, stack_offset));
246 stack_offset += kDoubleSize;
247 }
248 }
249 AddP(location, location, Operand(stack_offset));
250}
251
252void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index,
253 Condition) {
254 LoadP(destination, MemOperand(kRootRegister, index << kPointerSizeLog2), r0);
255}
256
257void MacroAssembler::StoreRoot(Register source, Heap::RootListIndex index,
258 Condition) {
259 DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
260 StoreP(source, MemOperand(kRootRegister, index << kPointerSizeLog2));
261}
262
263void MacroAssembler::InNewSpace(Register object, Register scratch,
264 Condition cond, Label* branch) {
265 DCHECK(cond == eq || cond == ne);
266 // TODO(joransiu): check if we can merge mov Operand into AndP.
267 const int mask =
268 (1 << MemoryChunk::IN_FROM_SPACE) | (1 << MemoryChunk::IN_TO_SPACE);
269 CheckPageFlag(object, scratch, mask, cond, branch);
270}
271
272void MacroAssembler::RecordWriteField(
273 Register object, int offset, Register value, Register dst,
274 LinkRegisterStatus lr_status, SaveFPRegsMode save_fp,
275 RememberedSetAction remembered_set_action, SmiCheck smi_check,
276 PointersToHereCheck pointers_to_here_check_for_value) {
277 // First, check if a write barrier is even needed. The tests below
278 // catch stores of Smis.
279 Label done;
280
281 // Skip barrier if writing a smi.
282 if (smi_check == INLINE_SMI_CHECK) {
283 JumpIfSmi(value, &done);
284 }
285
286 // Although the object register is tagged, the offset is relative to the start
287 // of the object, so so offset must be a multiple of kPointerSize.
288 DCHECK(IsAligned(offset, kPointerSize));
289
290 lay(dst, MemOperand(object, offset - kHeapObjectTag));
291 if (emit_debug_code()) {
292 Label ok;
293 AndP(r0, dst, Operand((1 << kPointerSizeLog2) - 1));
294 beq(&ok, Label::kNear);
295 stop("Unaligned cell in write barrier");
296 bind(&ok);
297 }
298
299 RecordWrite(object, dst, value, lr_status, save_fp, remembered_set_action,
300 OMIT_SMI_CHECK, pointers_to_here_check_for_value);
301
302 bind(&done);
303
304 // Clobber clobbered input registers when running with the debug-code flag
305 // turned on to provoke errors.
306 if (emit_debug_code()) {
307 mov(value, Operand(bit_cast<intptr_t>(kZapValue + 4)));
308 mov(dst, Operand(bit_cast<intptr_t>(kZapValue + 8)));
309 }
310}
311
312// Will clobber 4 registers: object, map, dst, ip. The
313// register 'object' contains a heap object pointer.
314void MacroAssembler::RecordWriteForMap(Register object, Register map,
315 Register dst,
316 LinkRegisterStatus lr_status,
317 SaveFPRegsMode fp_mode) {
318 if (emit_debug_code()) {
319 LoadP(dst, FieldMemOperand(map, HeapObject::kMapOffset));
320 CmpP(dst, Operand(isolate()->factory()->meta_map()));
321 Check(eq, kWrongAddressOrValuePassedToRecordWrite);
322 }
323
324 if (!FLAG_incremental_marking) {
325 return;
326 }
327
328 if (emit_debug_code()) {
329 CmpP(map, FieldMemOperand(object, HeapObject::kMapOffset));
330 Check(eq, kWrongAddressOrValuePassedToRecordWrite);
331 }
332
333 Label done;
334
335 // A single check of the map's pages interesting flag suffices, since it is
336 // only set during incremental collection, and then it's also guaranteed that
337 // the from object's page's interesting flag is also set. This optimization
338 // relies on the fact that maps can never be in new space.
339 CheckPageFlag(map,
340 map, // Used as scratch.
341 MemoryChunk::kPointersToHereAreInterestingMask, eq, &done);
342
343 lay(dst, MemOperand(object, HeapObject::kMapOffset - kHeapObjectTag));
344 if (emit_debug_code()) {
345 Label ok;
346 AndP(r0, dst, Operand((1 << kPointerSizeLog2) - 1));
347 beq(&ok, Label::kNear);
348 stop("Unaligned cell in write barrier");
349 bind(&ok);
350 }
351
352 // Record the actual write.
353 if (lr_status == kLRHasNotBeenSaved) {
354 push(r14);
355 }
356 RecordWriteStub stub(isolate(), object, map, dst, OMIT_REMEMBERED_SET,
357 fp_mode);
358 CallStub(&stub);
359 if (lr_status == kLRHasNotBeenSaved) {
360 pop(r14);
361 }
362
363 bind(&done);
364
365 // Count number of write barriers in generated code.
366 isolate()->counters()->write_barriers_static()->Increment();
367 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip, dst);
368
369 // Clobber clobbered registers when running with the debug-code flag
370 // turned on to provoke errors.
371 if (emit_debug_code()) {
372 mov(dst, Operand(bit_cast<intptr_t>(kZapValue + 12)));
373 mov(map, Operand(bit_cast<intptr_t>(kZapValue + 16)));
374 }
375}
376
377// Will clobber 4 registers: object, address, scratch, ip. The
378// register 'object' contains a heap object pointer. The heap object
379// tag is shifted away.
380void MacroAssembler::RecordWrite(
381 Register object, Register address, Register value,
382 LinkRegisterStatus lr_status, SaveFPRegsMode fp_mode,
383 RememberedSetAction remembered_set_action, SmiCheck smi_check,
384 PointersToHereCheck pointers_to_here_check_for_value) {
385 DCHECK(!object.is(value));
386 if (emit_debug_code()) {
387 CmpP(value, MemOperand(address));
388 Check(eq, kWrongAddressOrValuePassedToRecordWrite);
389 }
390
391 if (remembered_set_action == OMIT_REMEMBERED_SET &&
392 !FLAG_incremental_marking) {
393 return;
394 }
395 // First, check if a write barrier is even needed. The tests below
396 // catch stores of smis and stores into the young generation.
397 Label done;
398
399 if (smi_check == INLINE_SMI_CHECK) {
400 JumpIfSmi(value, &done);
401 }
402
403 if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) {
404 CheckPageFlag(value,
405 value, // Used as scratch.
406 MemoryChunk::kPointersToHereAreInterestingMask, eq, &done);
407 }
408 CheckPageFlag(object,
409 value, // Used as scratch.
410 MemoryChunk::kPointersFromHereAreInterestingMask, eq, &done);
411
412 // Record the actual write.
413 if (lr_status == kLRHasNotBeenSaved) {
414 push(r14);
415 }
416 RecordWriteStub stub(isolate(), object, value, address, remembered_set_action,
417 fp_mode);
418 CallStub(&stub);
419 if (lr_status == kLRHasNotBeenSaved) {
420 pop(r14);
421 }
422
423 bind(&done);
424
425 // Count number of write barriers in generated code.
426 isolate()->counters()->write_barriers_static()->Increment();
427 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip,
428 value);
429
430 // Clobber clobbered registers when running with the debug-code flag
431 // turned on to provoke errors.
432 if (emit_debug_code()) {
433 mov(address, Operand(bit_cast<intptr_t>(kZapValue + 12)));
434 mov(value, Operand(bit_cast<intptr_t>(kZapValue + 16)));
435 }
436}
437
438void MacroAssembler::RecordWriteCodeEntryField(Register js_function,
439 Register code_entry,
440 Register scratch) {
441 const int offset = JSFunction::kCodeEntryOffset;
442
443 // Since a code entry (value) is always in old space, we don't need to update
444 // remembered set. If incremental marking is off, there is nothing for us to
445 // do.
446 if (!FLAG_incremental_marking) return;
447
448 DCHECK(js_function.is(r3));
449 DCHECK(code_entry.is(r6));
450 DCHECK(scratch.is(r7));
451 AssertNotSmi(js_function);
452
453 if (emit_debug_code()) {
454 AddP(scratch, js_function, Operand(offset - kHeapObjectTag));
455 LoadP(ip, MemOperand(scratch));
456 CmpP(ip, code_entry);
457 Check(eq, kWrongAddressOrValuePassedToRecordWrite);
458 }
459
460 // First, check if a write barrier is even needed. The tests below
461 // catch stores of Smis and stores into young gen.
462 Label done;
463
464 CheckPageFlag(code_entry, scratch,
465 MemoryChunk::kPointersToHereAreInterestingMask, eq, &done);
466 CheckPageFlag(js_function, scratch,
467 MemoryChunk::kPointersFromHereAreInterestingMask, eq, &done);
468
469 const Register dst = scratch;
470 AddP(dst, js_function, Operand(offset - kHeapObjectTag));
471
472 // Save caller-saved registers. js_function and code_entry are in the
473 // caller-saved register list.
474 DCHECK(kJSCallerSaved & js_function.bit());
Ben Murdochc5610432016-08-08 18:44:38 +0100475 // DCHECK(kJSCallerSaved & code_entry.bit());
476 MultiPush(kJSCallerSaved | code_entry.bit() | r14.bit());
Ben Murdochda12d292016-06-02 14:46:10 +0100477
478 int argument_count = 3;
479 PrepareCallCFunction(argument_count, code_entry);
480
481 LoadRR(r2, js_function);
482 LoadRR(r3, dst);
483 mov(r4, Operand(ExternalReference::isolate_address(isolate())));
484
485 {
486 AllowExternalCallThatCantCauseGC scope(this);
487 CallCFunction(
488 ExternalReference::incremental_marking_record_write_code_entry_function(
489 isolate()),
490 argument_count);
491 }
492
493 // Restore caller-saved registers (including js_function and code_entry).
Ben Murdochc5610432016-08-08 18:44:38 +0100494 MultiPop(kJSCallerSaved | code_entry.bit() | r14.bit());
Ben Murdochda12d292016-06-02 14:46:10 +0100495
496 bind(&done);
497}
498
499void MacroAssembler::RememberedSetHelper(Register object, // For debug tests.
500 Register address, Register scratch,
501 SaveFPRegsMode fp_mode,
502 RememberedSetFinalAction and_then) {
503 Label done;
504 if (emit_debug_code()) {
505 Label ok;
506 JumpIfNotInNewSpace(object, scratch, &ok);
507 stop("Remembered set pointer is in new space");
508 bind(&ok);
509 }
510 // Load store buffer top.
511 ExternalReference store_buffer =
512 ExternalReference::store_buffer_top(isolate());
513 mov(ip, Operand(store_buffer));
514 LoadP(scratch, MemOperand(ip));
515 // Store pointer to buffer and increment buffer top.
516 StoreP(address, MemOperand(scratch));
517 AddP(scratch, Operand(kPointerSize));
518 // Write back new top of buffer.
519 StoreP(scratch, MemOperand(ip));
520 // Call stub on end of buffer.
521 // Check for end of buffer.
522 AndP(scratch, Operand(StoreBuffer::kStoreBufferMask));
523
524 if (and_then == kFallThroughAtEnd) {
525 bne(&done, Label::kNear);
526 } else {
527 DCHECK(and_then == kReturnAtEnd);
528 bne(&done, Label::kNear);
529 }
530 push(r14);
531 StoreBufferOverflowStub store_buffer_overflow(isolate(), fp_mode);
532 CallStub(&store_buffer_overflow);
533 pop(r14);
534 bind(&done);
535 if (and_then == kReturnAtEnd) {
536 Ret();
537 }
538}
539
540void MacroAssembler::PushCommonFrame(Register marker_reg) {
541 int fp_delta = 0;
542 CleanseP(r14);
543 if (marker_reg.is_valid()) {
544 Push(r14, fp, marker_reg);
545 fp_delta = 1;
546 } else {
547 Push(r14, fp);
548 fp_delta = 0;
549 }
550 la(fp, MemOperand(sp, fp_delta * kPointerSize));
551}
552
553void MacroAssembler::PopCommonFrame(Register marker_reg) {
554 if (marker_reg.is_valid()) {
555 Pop(r14, fp, marker_reg);
556 } else {
557 Pop(r14, fp);
558 }
559}
560
561void MacroAssembler::PushStandardFrame(Register function_reg) {
562 int fp_delta = 0;
563 CleanseP(r14);
564 if (function_reg.is_valid()) {
565 Push(r14, fp, cp, function_reg);
566 fp_delta = 2;
567 } else {
568 Push(r14, fp, cp);
569 fp_delta = 1;
570 }
571 la(fp, MemOperand(sp, fp_delta * kPointerSize));
572}
573
574void MacroAssembler::RestoreFrameStateForTailCall() {
575 // if (FLAG_enable_embedded_constant_pool) {
576 // LoadP(kConstantPoolRegister,
577 // MemOperand(fp, StandardFrameConstants::kConstantPoolOffset));
578 // set_constant_pool_available(false);
579 // }
580 DCHECK(!FLAG_enable_embedded_constant_pool);
581 LoadP(r14, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
582 LoadP(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
583}
584
585const RegList MacroAssembler::kSafepointSavedRegisters = Register::kAllocatable;
586const int MacroAssembler::kNumSafepointSavedRegisters =
587 Register::kNumAllocatable;
588
589// Push and pop all registers that can hold pointers.
590void MacroAssembler::PushSafepointRegisters() {
591 // Safepoints expect a block of kNumSafepointRegisters values on the
592 // stack, so adjust the stack for unsaved registers.
593 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
594 DCHECK(num_unsaved >= 0);
595 if (num_unsaved > 0) {
596 lay(sp, MemOperand(sp, -(num_unsaved * kPointerSize)));
597 }
598 MultiPush(kSafepointSavedRegisters);
599}
600
601void MacroAssembler::PopSafepointRegisters() {
602 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
603 MultiPop(kSafepointSavedRegisters);
604 if (num_unsaved > 0) {
605 la(sp, MemOperand(sp, num_unsaved * kPointerSize));
606 }
607}
608
609void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) {
610 StoreP(src, SafepointRegisterSlot(dst));
611}
612
613void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) {
614 LoadP(dst, SafepointRegisterSlot(src));
615}
616
617int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
618 // The registers are pushed starting with the highest encoding,
619 // which means that lowest encodings are closest to the stack pointer.
620 RegList regs = kSafepointSavedRegisters;
621 int index = 0;
622
623 DCHECK(reg_code >= 0 && reg_code < kNumRegisters);
624
625 for (int16_t i = 0; i < reg_code; i++) {
626 if ((regs & (1 << i)) != 0) {
627 index++;
628 }
629 }
630
631 return index;
632}
633
634MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) {
635 return MemOperand(sp, SafepointRegisterStackIndex(reg.code()) * kPointerSize);
636}
637
638MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) {
639 // General purpose registers are pushed last on the stack.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100640 const RegisterConfiguration* config = RegisterConfiguration::Crankshaft();
Ben Murdochda12d292016-06-02 14:46:10 +0100641 int doubles_size = config->num_allocatable_double_registers() * kDoubleSize;
642 int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize;
643 return MemOperand(sp, doubles_size + register_offset);
644}
645
646void MacroAssembler::CanonicalizeNaN(const DoubleRegister dst,
647 const DoubleRegister src) {
648 // Turn potential sNaN into qNaN
649 if (!dst.is(src)) ldr(dst, src);
650 lzdr(kDoubleRegZero);
651 sdbr(dst, kDoubleRegZero);
652}
653
654void MacroAssembler::ConvertIntToDouble(Register src, DoubleRegister dst) {
655 cdfbr(dst, src);
656}
657
658void MacroAssembler::ConvertUnsignedIntToDouble(Register src,
659 DoubleRegister dst) {
660 if (CpuFeatures::IsSupported(FLOATING_POINT_EXT)) {
661 cdlfbr(Condition(5), Condition(0), dst, src);
662 } else {
663 // zero-extend src
664 llgfr(src, src);
665 // convert to double
666 cdgbr(dst, src);
667 }
668}
669
670void MacroAssembler::ConvertIntToFloat(Register src, DoubleRegister dst) {
671 cefbr(dst, src);
672}
673
674void MacroAssembler::ConvertUnsignedIntToFloat(Register src,
675 DoubleRegister dst) {
676 celfbr(Condition(0), Condition(0), dst, src);
677}
678
679#if V8_TARGET_ARCH_S390X
680void MacroAssembler::ConvertInt64ToDouble(Register src,
681 DoubleRegister double_dst) {
682 cdgbr(double_dst, src);
683}
684
685void MacroAssembler::ConvertUnsignedInt64ToFloat(Register src,
686 DoubleRegister double_dst) {
687 celgbr(Condition(0), Condition(0), double_dst, src);
688}
689
690void MacroAssembler::ConvertUnsignedInt64ToDouble(Register src,
691 DoubleRegister double_dst) {
692 cdlgbr(Condition(0), Condition(0), double_dst, src);
693}
694
695void MacroAssembler::ConvertInt64ToFloat(Register src,
696 DoubleRegister double_dst) {
697 cegbr(double_dst, src);
698}
699#endif
700
701void MacroAssembler::ConvertFloat32ToInt64(const DoubleRegister double_input,
702#if !V8_TARGET_ARCH_S390X
703 const Register dst_hi,
704#endif
705 const Register dst,
706 const DoubleRegister double_dst,
707 FPRoundingMode rounding_mode) {
708 Condition m = Condition(0);
709 switch (rounding_mode) {
710 case kRoundToZero:
711 m = Condition(5);
712 break;
713 case kRoundToNearest:
714 UNIMPLEMENTED();
715 break;
716 case kRoundToPlusInf:
717 m = Condition(6);
718 break;
719 case kRoundToMinusInf:
720 m = Condition(7);
721 break;
722 default:
723 UNIMPLEMENTED();
724 break;
725 }
726 cgebr(m, dst, double_input);
727 ldgr(double_dst, dst);
728#if !V8_TARGET_ARCH_S390X
729 srlg(dst_hi, dst, Operand(32));
730#endif
731}
732
733void MacroAssembler::ConvertDoubleToInt64(const DoubleRegister double_input,
734#if !V8_TARGET_ARCH_S390X
735 const Register dst_hi,
736#endif
737 const Register dst,
738 const DoubleRegister double_dst,
739 FPRoundingMode rounding_mode) {
740 Condition m = Condition(0);
741 switch (rounding_mode) {
742 case kRoundToZero:
743 m = Condition(5);
744 break;
745 case kRoundToNearest:
746 UNIMPLEMENTED();
747 break;
748 case kRoundToPlusInf:
749 m = Condition(6);
750 break;
751 case kRoundToMinusInf:
752 m = Condition(7);
753 break;
754 default:
755 UNIMPLEMENTED();
756 break;
757 }
758 cgdbr(m, dst, double_input);
759 ldgr(double_dst, dst);
760#if !V8_TARGET_ARCH_S390X
761 srlg(dst_hi, dst, Operand(32));
762#endif
763}
764
765void MacroAssembler::ConvertFloat32ToInt32(const DoubleRegister double_input,
766 const Register dst,
767 const DoubleRegister double_dst,
768 FPRoundingMode rounding_mode) {
769 Condition m = Condition(0);
770 switch (rounding_mode) {
771 case kRoundToZero:
772 m = Condition(5);
773 break;
774 case kRoundToNearest:
775 UNIMPLEMENTED();
776 break;
777 case kRoundToPlusInf:
778 m = Condition(6);
779 break;
780 case kRoundToMinusInf:
781 m = Condition(7);
782 break;
783 default:
784 UNIMPLEMENTED();
785 break;
786 }
787 cfebr(m, dst, double_input);
788 ldgr(double_dst, dst);
789}
790
791void MacroAssembler::ConvertFloat32ToUnsignedInt32(
792 const DoubleRegister double_input, const Register dst,
793 const DoubleRegister double_dst, FPRoundingMode rounding_mode) {
794 Condition m = Condition(0);
795 switch (rounding_mode) {
796 case kRoundToZero:
797 m = Condition(5);
798 break;
799 case kRoundToNearest:
800 UNIMPLEMENTED();
801 break;
802 case kRoundToPlusInf:
803 m = Condition(6);
804 break;
805 case kRoundToMinusInf:
806 m = Condition(7);
807 break;
808 default:
809 UNIMPLEMENTED();
810 break;
811 }
812 clfebr(m, Condition(0), dst, double_input);
813 ldgr(double_dst, dst);
814}
815
816#if V8_TARGET_ARCH_S390X
817void MacroAssembler::ConvertFloat32ToUnsignedInt64(
818 const DoubleRegister double_input, const Register dst,
819 const DoubleRegister double_dst, FPRoundingMode rounding_mode) {
820 Condition m = Condition(0);
821 switch (rounding_mode) {
822 case kRoundToZero:
823 m = Condition(5);
824 break;
825 case kRoundToNearest:
826 UNIMPLEMENTED();
827 break;
828 case kRoundToPlusInf:
829 m = Condition(6);
830 break;
831 case kRoundToMinusInf:
832 m = Condition(7);
833 break;
834 default:
835 UNIMPLEMENTED();
836 break;
837 }
838 clgebr(m, Condition(0), dst, double_input);
839 ldgr(double_dst, dst);
840}
841
842void MacroAssembler::ConvertDoubleToUnsignedInt64(
843 const DoubleRegister double_input, const Register dst,
844 const DoubleRegister double_dst, FPRoundingMode rounding_mode) {
845 Condition m = Condition(0);
846 switch (rounding_mode) {
847 case kRoundToZero:
848 m = Condition(5);
849 break;
850 case kRoundToNearest:
851 UNIMPLEMENTED();
852 break;
853 case kRoundToPlusInf:
854 m = Condition(6);
855 break;
856 case kRoundToMinusInf:
857 m = Condition(7);
858 break;
859 default:
860 UNIMPLEMENTED();
861 break;
862 }
863 clgdbr(m, Condition(0), dst, double_input);
864 ldgr(double_dst, dst);
865}
866
867#endif
868
869#if !V8_TARGET_ARCH_S390X
870void MacroAssembler::ShiftLeftPair(Register dst_low, Register dst_high,
871 Register src_low, Register src_high,
872 Register scratch, Register shift) {
873 LoadRR(r0, src_high);
874 LoadRR(r1, src_low);
875 sldl(r0, shift, Operand::Zero());
876 LoadRR(dst_high, r0);
877 LoadRR(dst_low, r1);
878}
879
880void MacroAssembler::ShiftLeftPair(Register dst_low, Register dst_high,
881 Register src_low, Register src_high,
882 uint32_t shift) {
883 LoadRR(r0, src_high);
884 LoadRR(r1, src_low);
885 sldl(r0, r0, Operand(shift));
886 LoadRR(dst_high, r0);
887 LoadRR(dst_low, r1);
888}
889
890void MacroAssembler::ShiftRightPair(Register dst_low, Register dst_high,
891 Register src_low, Register src_high,
892 Register scratch, Register shift) {
893 LoadRR(r0, src_high);
894 LoadRR(r1, src_low);
895 srdl(r0, shift, Operand::Zero());
896 LoadRR(dst_high, r0);
897 LoadRR(dst_low, r1);
898}
899
900void MacroAssembler::ShiftRightPair(Register dst_low, Register dst_high,
901 Register src_low, Register src_high,
902 uint32_t shift) {
903 LoadRR(r0, src_high);
904 LoadRR(r1, src_low);
905 srdl(r0, r0, Operand(shift));
906 LoadRR(dst_high, r0);
907 LoadRR(dst_low, r1);
908}
909
910void MacroAssembler::ShiftRightArithPair(Register dst_low, Register dst_high,
911 Register src_low, Register src_high,
912 Register scratch, Register shift) {
913 LoadRR(r0, src_high);
914 LoadRR(r1, src_low);
915 srda(r0, shift, Operand::Zero());
916 LoadRR(dst_high, r0);
917 LoadRR(dst_low, r1);
918}
919
920void MacroAssembler::ShiftRightArithPair(Register dst_low, Register dst_high,
921 Register src_low, Register src_high,
922 uint32_t shift) {
923 LoadRR(r0, src_high);
924 LoadRR(r1, src_low);
925 srda(r0, r0, Operand(shift));
926 LoadRR(dst_high, r0);
927 LoadRR(dst_low, r1);
928}
929#endif
930
931void MacroAssembler::MovDoubleToInt64(Register dst, DoubleRegister src) {
932 lgdr(dst, src);
933}
934
935void MacroAssembler::MovInt64ToDouble(DoubleRegister dst, Register src) {
936 ldgr(dst, src);
937}
938
939void MacroAssembler::StubPrologue(StackFrame::Type type, Register base,
940 int prologue_offset) {
941 {
942 ConstantPoolUnavailableScope constant_pool_unavailable(this);
943 LoadSmiLiteral(r1, Smi::FromInt(type));
944 PushCommonFrame(r1);
945 }
946}
947
948void MacroAssembler::Prologue(bool code_pre_aging, Register base,
949 int prologue_offset) {
950 DCHECK(!base.is(no_reg));
951 {
952 PredictableCodeSizeScope predictible_code_size_scope(
953 this, kNoCodeAgeSequenceLength);
954 // The following instructions must remain together and unmodified
955 // for code aging to work properly.
956 if (code_pre_aging) {
957 // Pre-age the code.
958 // This matches the code found in PatchPlatformCodeAge()
959 Code* stub = Code::GetPreAgedCodeAgeStub(isolate());
960 intptr_t target = reinterpret_cast<intptr_t>(stub->instruction_start());
961 nop();
962 CleanseP(r14);
963 Push(r14);
964 mov(r2, Operand(target));
965 Call(r2);
966 for (int i = 0; i < kNoCodeAgeSequenceLength - kCodeAgingSequenceLength;
967 i += 2) {
968 // TODO(joransiu): Create nop function to pad
969 // (kNoCodeAgeSequenceLength - kCodeAgingSequenceLength) bytes.
970 nop(); // 2-byte nops().
971 }
972 } else {
973 // This matches the code found in GetNoCodeAgeSequence()
974 PushStandardFrame(r3);
975 }
976 }
977}
978
979void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) {
980 LoadP(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdoch61f157c2016-09-16 13:49:30 +0100981 LoadP(vector, FieldMemOperand(vector, JSFunction::kLiteralsOffset));
982 LoadP(vector, FieldMemOperand(vector, LiteralsArray::kFeedbackVectorOffset));
Ben Murdochda12d292016-06-02 14:46:10 +0100983}
984
985void MacroAssembler::EnterFrame(StackFrame::Type type,
986 bool load_constant_pool_pointer_reg) {
987 // We create a stack frame with:
988 // Return Addr <-- old sp
989 // Old FP <-- new fp
990 // CP
991 // type
992 // CodeObject <-- new sp
993
994 LoadSmiLiteral(ip, Smi::FromInt(type));
995 PushCommonFrame(ip);
996
997 if (type == StackFrame::INTERNAL) {
998 mov(r0, Operand(CodeObject()));
999 push(r0);
1000 }
1001}
1002
1003int MacroAssembler::LeaveFrame(StackFrame::Type type, int stack_adjustment) {
1004 // Drop the execution stack down to the frame pointer and restore
1005 // the caller frame pointer, return address and constant pool pointer.
1006 LoadP(r14, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
1007 lay(r1, MemOperand(
1008 fp, StandardFrameConstants::kCallerSPOffset + stack_adjustment));
1009 LoadP(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
1010 LoadRR(sp, r1);
1011 int frame_ends = pc_offset();
1012 return frame_ends;
1013}
1014
1015// ExitFrame layout (probably wrongish.. needs updating)
1016//
1017// SP -> previousSP
1018// LK reserved
1019// code
1020// sp_on_exit (for debug?)
1021// oldSP->prev SP
1022// LK
1023// <parameters on stack>
1024
1025// Prior to calling EnterExitFrame, we've got a bunch of parameters
1026// on the stack that we need to wrap a real frame around.. so first
1027// we reserve a slot for LK and push the previous SP which is captured
1028// in the fp register (r11)
1029// Then - we buy a new frame
1030
1031// r14
1032// oldFP <- newFP
1033// SP
1034// Code
1035// Floats
1036// gaps
1037// Args
1038// ABIRes <- newSP
1039void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) {
1040 // Set up the frame structure on the stack.
1041 DCHECK_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement);
1042 DCHECK_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset);
1043 DCHECK_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset);
1044 DCHECK(stack_space > 0);
1045
1046 // This is an opportunity to build a frame to wrap
1047 // all of the pushes that have happened inside of V8
1048 // since we were called from C code
1049 CleanseP(r14);
1050 LoadSmiLiteral(r1, Smi::FromInt(StackFrame::EXIT));
1051 PushCommonFrame(r1);
1052 // Reserve room for saved entry sp and code object.
1053 lay(sp, MemOperand(fp, -ExitFrameConstants::kFixedFrameSizeFromFp));
1054
1055 if (emit_debug_code()) {
1056 StoreP(MemOperand(fp, ExitFrameConstants::kSPOffset), Operand::Zero(), r1);
1057 }
1058 mov(r1, Operand(CodeObject()));
1059 StoreP(r1, MemOperand(fp, ExitFrameConstants::kCodeOffset));
1060
1061 // Save the frame pointer and the context in top.
1062 mov(r1, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
1063 StoreP(fp, MemOperand(r1));
1064 mov(r1, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
1065 StoreP(cp, MemOperand(r1));
1066
1067 // Optionally save all volatile double registers.
1068 if (save_doubles) {
1069 MultiPushDoubles(kCallerSavedDoubles);
1070 // Note that d0 will be accessible at
1071 // fp - ExitFrameConstants::kFrameSize -
1072 // kNumCallerSavedDoubles * kDoubleSize,
1073 // since the sp slot and code slot were pushed after the fp.
1074 }
1075
1076 lay(sp, MemOperand(sp, -stack_space * kPointerSize));
1077
1078 // Allocate and align the frame preparing for calling the runtime
1079 // function.
1080 const int frame_alignment = MacroAssembler::ActivationFrameAlignment();
1081 if (frame_alignment > 0) {
1082 DCHECK(frame_alignment == 8);
1083 ClearRightImm(sp, sp, Operand(3)); // equivalent to &= -8
1084 }
1085
Ben Murdochda12d292016-06-02 14:46:10 +01001086 lay(sp, MemOperand(sp, -kNumRequiredStackFrameSlots * kPointerSize));
Ben Murdoch6f5d0ea2016-06-15 14:45:46 +01001087 StoreP(MemOperand(sp), Operand::Zero(), r0);
Ben Murdochda12d292016-06-02 14:46:10 +01001088 // Set the exit frame sp value to point just before the return address
1089 // location.
1090 lay(r1, MemOperand(sp, kStackFrameSPSlot * kPointerSize));
1091 StoreP(r1, MemOperand(fp, ExitFrameConstants::kSPOffset));
1092}
1093
1094void MacroAssembler::InitializeNewString(Register string, Register length,
1095 Heap::RootListIndex map_index,
1096 Register scratch1, Register scratch2) {
1097 SmiTag(scratch1, length);
1098 LoadRoot(scratch2, map_index);
1099 StoreP(scratch1, FieldMemOperand(string, String::kLengthOffset));
1100 StoreP(FieldMemOperand(string, String::kHashFieldSlot),
1101 Operand(String::kEmptyHashField), scratch1);
1102 StoreP(scratch2, FieldMemOperand(string, HeapObject::kMapOffset));
1103}
1104
1105int MacroAssembler::ActivationFrameAlignment() {
1106#if !defined(USE_SIMULATOR)
1107 // Running on the real platform. Use the alignment as mandated by the local
1108 // environment.
1109 // Note: This will break if we ever start generating snapshots on one S390
1110 // platform for another S390 platform with a different alignment.
1111 return base::OS::ActivationFrameAlignment();
1112#else // Simulated
1113 // If we are using the simulator then we should always align to the expected
1114 // alignment. As the simulator is used to generate snapshots we do not know
1115 // if the target platform will need alignment, so this is controlled from a
1116 // flag.
1117 return FLAG_sim_stack_alignment;
1118#endif
1119}
1120
1121void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
1122 bool restore_context,
1123 bool argument_count_is_length) {
1124 // Optionally restore all double registers.
1125 if (save_doubles) {
1126 // Calculate the stack location of the saved doubles and restore them.
1127 const int kNumRegs = kNumCallerSavedDoubles;
1128 lay(r5, MemOperand(fp, -(ExitFrameConstants::kFixedFrameSizeFromFp +
1129 kNumRegs * kDoubleSize)));
1130 MultiPopDoubles(kCallerSavedDoubles, r5);
1131 }
1132
1133 // Clear top frame.
1134 mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
1135 StoreP(MemOperand(ip), Operand(0, kRelocInfo_NONEPTR), r0);
1136
1137 // Restore current context from top and clear it in debug mode.
1138 if (restore_context) {
1139 mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
1140 LoadP(cp, MemOperand(ip));
1141 }
1142#ifdef DEBUG
1143 mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
1144 StoreP(MemOperand(ip), Operand(0, kRelocInfo_NONEPTR), r0);
1145#endif
1146
1147 // Tear down the exit frame, pop the arguments, and return.
1148 LeaveFrame(StackFrame::EXIT);
1149
1150 if (argument_count.is_valid()) {
1151 if (!argument_count_is_length) {
1152 ShiftLeftP(argument_count, argument_count, Operand(kPointerSizeLog2));
1153 }
1154 la(sp, MemOperand(sp, argument_count));
1155 }
1156}
1157
1158void MacroAssembler::MovFromFloatResult(const DoubleRegister dst) {
1159 Move(dst, d0);
1160}
1161
1162void MacroAssembler::MovFromFloatParameter(const DoubleRegister dst) {
1163 Move(dst, d0);
1164}
1165
1166void MacroAssembler::PrepareForTailCall(const ParameterCount& callee_args_count,
1167 Register caller_args_count_reg,
1168 Register scratch0, Register scratch1) {
1169#if DEBUG
1170 if (callee_args_count.is_reg()) {
1171 DCHECK(!AreAliased(callee_args_count.reg(), caller_args_count_reg, scratch0,
1172 scratch1));
1173 } else {
1174 DCHECK(!AreAliased(caller_args_count_reg, scratch0, scratch1));
1175 }
1176#endif
1177
1178 // Calculate the end of destination area where we will put the arguments
1179 // after we drop current frame. We AddP kPointerSize to count the receiver
1180 // argument which is not included into formal parameters count.
1181 Register dst_reg = scratch0;
1182 ShiftLeftP(dst_reg, caller_args_count_reg, Operand(kPointerSizeLog2));
1183 AddP(dst_reg, fp, dst_reg);
1184 AddP(dst_reg, dst_reg,
1185 Operand(StandardFrameConstants::kCallerSPOffset + kPointerSize));
1186
1187 Register src_reg = caller_args_count_reg;
1188 // Calculate the end of source area. +kPointerSize is for the receiver.
1189 if (callee_args_count.is_reg()) {
1190 ShiftLeftP(src_reg, callee_args_count.reg(), Operand(kPointerSizeLog2));
1191 AddP(src_reg, sp, src_reg);
1192 AddP(src_reg, src_reg, Operand(kPointerSize));
1193 } else {
1194 mov(src_reg, Operand((callee_args_count.immediate() + 1) * kPointerSize));
1195 AddP(src_reg, src_reg, sp);
1196 }
1197
1198 if (FLAG_debug_code) {
1199 CmpLogicalP(src_reg, dst_reg);
1200 Check(lt, kStackAccessBelowStackPointer);
1201 }
1202
1203 // Restore caller's frame pointer and return address now as they will be
1204 // overwritten by the copying loop.
1205 RestoreFrameStateForTailCall();
1206
1207 // Now copy callee arguments to the caller frame going backwards to avoid
1208 // callee arguments corruption (source and destination areas could overlap).
1209
1210 // Both src_reg and dst_reg are pointing to the word after the one to copy,
1211 // so they must be pre-decremented in the loop.
1212 Register tmp_reg = scratch1;
1213 Label loop;
1214 if (callee_args_count.is_reg()) {
1215 AddP(tmp_reg, callee_args_count.reg(), Operand(1)); // +1 for receiver
1216 } else {
1217 mov(tmp_reg, Operand(callee_args_count.immediate() + 1));
1218 }
1219 LoadRR(r1, tmp_reg);
1220 bind(&loop);
1221 LoadP(tmp_reg, MemOperand(src_reg, -kPointerSize));
1222 StoreP(tmp_reg, MemOperand(dst_reg, -kPointerSize));
1223 lay(src_reg, MemOperand(src_reg, -kPointerSize));
1224 lay(dst_reg, MemOperand(dst_reg, -kPointerSize));
1225 BranchOnCount(r1, &loop);
1226
1227 // Leave current frame.
1228 LoadRR(sp, dst_reg);
1229}
1230
1231void MacroAssembler::InvokePrologue(const ParameterCount& expected,
1232 const ParameterCount& actual, Label* done,
1233 bool* definitely_mismatches,
1234 InvokeFlag flag,
1235 const CallWrapper& call_wrapper) {
1236 bool definitely_matches = false;
1237 *definitely_mismatches = false;
1238 Label regular_invoke;
1239
1240 // Check whether the expected and actual arguments count match. If not,
1241 // setup registers according to contract with ArgumentsAdaptorTrampoline:
1242 // r2: actual arguments count
1243 // r3: function (passed through to callee)
1244 // r4: expected arguments count
1245
1246 // The code below is made a lot easier because the calling code already sets
1247 // up actual and expected registers according to the contract if values are
1248 // passed in registers.
1249
1250 // ARM has some sanity checks as per below, considering add them for S390
1251 // DCHECK(actual.is_immediate() || actual.reg().is(r2));
1252 // DCHECK(expected.is_immediate() || expected.reg().is(r4));
1253
1254 if (expected.is_immediate()) {
1255 DCHECK(actual.is_immediate());
1256 mov(r2, Operand(actual.immediate()));
1257 if (expected.immediate() == actual.immediate()) {
1258 definitely_matches = true;
1259 } else {
1260 const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
1261 if (expected.immediate() == sentinel) {
1262 // Don't worry about adapting arguments for builtins that
1263 // don't want that done. Skip adaption code by making it look
1264 // like we have a match between expected and actual number of
1265 // arguments.
1266 definitely_matches = true;
1267 } else {
1268 *definitely_mismatches = true;
1269 mov(r4, Operand(expected.immediate()));
1270 }
1271 }
1272 } else {
1273 if (actual.is_immediate()) {
1274 mov(r2, Operand(actual.immediate()));
1275 CmpPH(expected.reg(), Operand(actual.immediate()));
1276 beq(&regular_invoke);
1277 } else {
1278 CmpP(expected.reg(), actual.reg());
1279 beq(&regular_invoke);
1280 }
1281 }
1282
1283 if (!definitely_matches) {
1284 Handle<Code> adaptor = isolate()->builtins()->ArgumentsAdaptorTrampoline();
1285 if (flag == CALL_FUNCTION) {
1286 call_wrapper.BeforeCall(CallSize(adaptor));
1287 Call(adaptor);
1288 call_wrapper.AfterCall();
1289 if (!*definitely_mismatches) {
1290 b(done);
1291 }
1292 } else {
1293 Jump(adaptor, RelocInfo::CODE_TARGET);
1294 }
1295 bind(&regular_invoke);
1296 }
1297}
1298
1299void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target,
1300 const ParameterCount& expected,
1301 const ParameterCount& actual) {
1302 Label skip_flooding;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001303 ExternalReference last_step_action =
1304 ExternalReference::debug_last_step_action_address(isolate());
1305 STATIC_ASSERT(StepFrame > StepIn);
1306 mov(r6, Operand(last_step_action));
1307 LoadB(r6, MemOperand(r6));
1308 CmpP(r6, Operand(StepIn));
1309 blt(&skip_flooding);
Ben Murdochda12d292016-06-02 14:46:10 +01001310 {
1311 FrameScope frame(this,
1312 has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
1313 if (expected.is_reg()) {
1314 SmiTag(expected.reg());
1315 Push(expected.reg());
1316 }
1317 if (actual.is_reg()) {
1318 SmiTag(actual.reg());
1319 Push(actual.reg());
1320 }
1321 if (new_target.is_valid()) {
1322 Push(new_target);
1323 }
1324 Push(fun, fun);
1325 CallRuntime(Runtime::kDebugPrepareStepInIfStepping);
1326 Pop(fun);
1327 if (new_target.is_valid()) {
1328 Pop(new_target);
1329 }
1330 if (actual.is_reg()) {
1331 Pop(actual.reg());
1332 SmiUntag(actual.reg());
1333 }
1334 if (expected.is_reg()) {
1335 Pop(expected.reg());
1336 SmiUntag(expected.reg());
1337 }
1338 }
1339 bind(&skip_flooding);
1340}
1341
1342void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
1343 const ParameterCount& expected,
1344 const ParameterCount& actual,
1345 InvokeFlag flag,
1346 const CallWrapper& call_wrapper) {
1347 // You can't call a function without a valid frame.
1348 DCHECK(flag == JUMP_FUNCTION || has_frame());
1349
1350 DCHECK(function.is(r3));
1351 DCHECK_IMPLIES(new_target.is_valid(), new_target.is(r5));
1352
1353 if (call_wrapper.NeedsDebugStepCheck()) {
1354 FloodFunctionIfStepping(function, new_target, expected, actual);
1355 }
1356
1357 // Clear the new.target register if not given.
1358 if (!new_target.is_valid()) {
1359 LoadRoot(r5, Heap::kUndefinedValueRootIndex);
1360 }
1361
1362 Label done;
1363 bool definitely_mismatches = false;
1364 InvokePrologue(expected, actual, &done, &definitely_mismatches, flag,
1365 call_wrapper);
1366 if (!definitely_mismatches) {
1367 // We call indirectly through the code field in the function to
1368 // allow recompilation to take effect without changing any of the
1369 // call sites.
1370 Register code = ip;
1371 LoadP(code, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
1372 if (flag == CALL_FUNCTION) {
1373 call_wrapper.BeforeCall(CallSize(code));
1374 CallJSEntry(code);
1375 call_wrapper.AfterCall();
1376 } else {
1377 DCHECK(flag == JUMP_FUNCTION);
1378 JumpToJSEntry(code);
1379 }
1380
1381 // Continue here if InvokePrologue does handle the invocation due to
1382 // mismatched parameter counts.
1383 bind(&done);
1384 }
1385}
1386
1387void MacroAssembler::InvokeFunction(Register fun, Register new_target,
1388 const ParameterCount& actual,
1389 InvokeFlag flag,
1390 const CallWrapper& call_wrapper) {
1391 // You can't call a function without a valid frame.
1392 DCHECK(flag == JUMP_FUNCTION || has_frame());
1393
1394 // Contract with called JS functions requires that function is passed in r3.
1395 DCHECK(fun.is(r3));
1396
1397 Register expected_reg = r4;
1398 Register temp_reg = r6;
1399 LoadP(temp_reg, FieldMemOperand(r3, JSFunction::kSharedFunctionInfoOffset));
1400 LoadP(cp, FieldMemOperand(r3, JSFunction::kContextOffset));
1401 LoadW(expected_reg,
1402 FieldMemOperand(temp_reg,
1403 SharedFunctionInfo::kFormalParameterCountOffset));
1404#if !defined(V8_TARGET_ARCH_S390X)
1405 SmiUntag(expected_reg);
1406#endif
1407
1408 ParameterCount expected(expected_reg);
1409 InvokeFunctionCode(fun, new_target, expected, actual, flag, call_wrapper);
1410}
1411
1412void MacroAssembler::InvokeFunction(Register function,
1413 const ParameterCount& expected,
1414 const ParameterCount& actual,
1415 InvokeFlag flag,
1416 const CallWrapper& call_wrapper) {
1417 // You can't call a function without a valid frame.
1418 DCHECK(flag == JUMP_FUNCTION || has_frame());
1419
1420 // Contract with called JS functions requires that function is passed in r3.
1421 DCHECK(function.is(r3));
1422
1423 // Get the function and setup the context.
1424 LoadP(cp, FieldMemOperand(r3, JSFunction::kContextOffset));
1425
1426 InvokeFunctionCode(r3, no_reg, expected, actual, flag, call_wrapper);
1427}
1428
1429void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
1430 const ParameterCount& expected,
1431 const ParameterCount& actual,
1432 InvokeFlag flag,
1433 const CallWrapper& call_wrapper) {
1434 Move(r3, function);
1435 InvokeFunction(r3, expected, actual, flag, call_wrapper);
1436}
1437
1438void MacroAssembler::IsObjectJSStringType(Register object, Register scratch,
1439 Label* fail) {
1440 DCHECK(kNotStringTag != 0);
1441
1442 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
1443 LoadlB(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
1444 mov(r0, Operand(kIsNotStringMask));
1445 AndP(r0, scratch);
1446 bne(fail);
1447}
1448
1449void MacroAssembler::IsObjectNameType(Register object, Register scratch,
1450 Label* fail) {
1451 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
1452 LoadlB(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
1453 CmpP(scratch, Operand(LAST_NAME_TYPE));
1454 bgt(fail);
1455}
1456
1457void MacroAssembler::DebugBreak() {
1458 LoadImmP(r2, Operand::Zero());
1459 mov(r3,
1460 Operand(ExternalReference(Runtime::kHandleDebuggerStatement, isolate())));
1461 CEntryStub ces(isolate(), 1);
1462 DCHECK(AllowThisStubCall(&ces));
1463 Call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT);
1464}
1465
1466void MacroAssembler::PushStackHandler() {
1467 // Adjust this code if not the case.
1468 STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize);
1469 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
1470
1471 // Link the current handler as the next handler.
1472 mov(r7, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
1473
1474 // Buy the full stack frame for 5 slots.
1475 lay(sp, MemOperand(sp, -StackHandlerConstants::kSize));
1476
1477 // Copy the old handler into the next handler slot.
1478 mvc(MemOperand(sp, StackHandlerConstants::kNextOffset), MemOperand(r7),
1479 kPointerSize);
1480 // Set this new handler as the current one.
1481 StoreP(sp, MemOperand(r7));
1482}
1483
1484void MacroAssembler::PopStackHandler() {
1485 STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize);
1486 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
1487
1488 // Pop the Next Handler into r3 and store it into Handler Address reference.
1489 Pop(r3);
1490 mov(ip, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
1491
1492 StoreP(r3, MemOperand(ip));
1493}
1494
1495void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
1496 Register scratch, Label* miss) {
1497 Label same_contexts;
1498
1499 DCHECK(!holder_reg.is(scratch));
1500 DCHECK(!holder_reg.is(ip));
1501 DCHECK(!scratch.is(ip));
1502
1503 // Load current lexical context from the active StandardFrame, which
1504 // may require crawling past STUB frames.
1505 Label load_context;
1506 Label has_context;
1507 DCHECK(!ip.is(scratch));
1508 LoadRR(ip, fp);
1509 bind(&load_context);
1510 LoadP(scratch,
1511 MemOperand(ip, CommonFrameConstants::kContextOrFrameTypeOffset));
1512 JumpIfNotSmi(scratch, &has_context);
1513 LoadP(ip, MemOperand(ip, CommonFrameConstants::kCallerFPOffset));
1514 b(&load_context);
1515 bind(&has_context);
1516
1517// In debug mode, make sure the lexical context is set.
1518#ifdef DEBUG
1519 CmpP(scratch, Operand::Zero());
1520 Check(ne, kWeShouldNotHaveAnEmptyLexicalContext);
1521#endif
1522
1523 // Load the native context of the current context.
1524 LoadP(scratch, ContextMemOperand(scratch, Context::NATIVE_CONTEXT_INDEX));
1525
1526 // Check the context is a native context.
1527 if (emit_debug_code()) {
1528 // Cannot use ip as a temporary in this verification code. Due to the fact
1529 // that ip is clobbered as part of cmp with an object Operand.
1530 push(holder_reg); // Temporarily save holder on the stack.
1531 // Read the first word and compare to the native_context_map.
1532 LoadP(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset));
1533 CompareRoot(holder_reg, Heap::kNativeContextMapRootIndex);
1534 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext);
1535 pop(holder_reg); // Restore holder.
1536 }
1537
1538 // Check if both contexts are the same.
1539 LoadP(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
1540 CmpP(scratch, ip);
1541 beq(&same_contexts, Label::kNear);
1542
1543 // Check the context is a native context.
1544 if (emit_debug_code()) {
1545 // TODO(119): avoid push(holder_reg)/pop(holder_reg)
1546 // Cannot use ip as a temporary in this verification code. Due to the fact
1547 // that ip is clobbered as part of cmp with an object Operand.
1548 push(holder_reg); // Temporarily save holder on the stack.
1549 LoadRR(holder_reg, ip); // Move ip to its holding place.
1550 CompareRoot(holder_reg, Heap::kNullValueRootIndex);
1551 Check(ne, kJSGlobalProxyContextShouldNotBeNull);
1552
1553 LoadP(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset));
1554 CompareRoot(holder_reg, Heap::kNativeContextMapRootIndex);
1555 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext);
1556 // Restore ip is not needed. ip is reloaded below.
1557 pop(holder_reg); // Restore holder.
1558 // Restore ip to holder's context.
1559 LoadP(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
1560 }
1561
1562 // Check that the security token in the calling global object is
1563 // compatible with the security token in the receiving global
1564 // object.
1565 int token_offset =
1566 Context::kHeaderSize + Context::SECURITY_TOKEN_INDEX * kPointerSize;
1567
1568 LoadP(scratch, FieldMemOperand(scratch, token_offset));
1569 LoadP(ip, FieldMemOperand(ip, token_offset));
1570 CmpP(scratch, ip);
1571 bne(miss);
1572
1573 bind(&same_contexts);
1574}
1575
1576// Compute the hash code from the untagged key. This must be kept in sync with
1577// ComputeIntegerHash in utils.h and KeyedLoadGenericStub in
1578// code-stub-hydrogen.cc
1579void MacroAssembler::GetNumberHash(Register t0, Register scratch) {
1580 // First of all we assign the hash seed to scratch.
1581 LoadRoot(scratch, Heap::kHashSeedRootIndex);
1582 SmiUntag(scratch);
1583
1584 // Xor original key with a seed.
1585 XorP(t0, scratch);
1586
1587 // Compute the hash code from the untagged key. This must be kept in sync
1588 // with ComputeIntegerHash in utils.h.
1589 //
1590 // hash = ~hash + (hash << 15);
1591 LoadRR(scratch, t0);
1592 NotP(scratch);
1593 sll(t0, Operand(15));
1594 AddP(t0, scratch, t0);
1595 // hash = hash ^ (hash >> 12);
1596 ShiftRight(scratch, t0, Operand(12));
1597 XorP(t0, scratch);
1598 // hash = hash + (hash << 2);
1599 ShiftLeft(scratch, t0, Operand(2));
1600 AddP(t0, t0, scratch);
1601 // hash = hash ^ (hash >> 4);
1602 ShiftRight(scratch, t0, Operand(4));
1603 XorP(t0, scratch);
1604 // hash = hash * 2057;
1605 LoadRR(r0, t0);
1606 ShiftLeft(scratch, t0, Operand(3));
1607 AddP(t0, t0, scratch);
1608 ShiftLeft(scratch, r0, Operand(11));
1609 AddP(t0, t0, scratch);
1610 // hash = hash ^ (hash >> 16);
1611 ShiftRight(scratch, t0, Operand(16));
1612 XorP(t0, scratch);
1613 // hash & 0x3fffffff
1614 ExtractBitRange(t0, t0, 29, 0);
1615}
1616
1617void MacroAssembler::LoadFromNumberDictionary(Label* miss, Register elements,
1618 Register key, Register result,
1619 Register t0, Register t1,
1620 Register t2) {
1621 // Register use:
1622 //
1623 // elements - holds the slow-case elements of the receiver on entry.
1624 // Unchanged unless 'result' is the same register.
1625 //
1626 // key - holds the smi key on entry.
1627 // Unchanged unless 'result' is the same register.
1628 //
1629 // result - holds the result on exit if the load succeeded.
1630 // Allowed to be the same as 'key' or 'result'.
1631 // Unchanged on bailout so 'key' or 'result' can be used
1632 // in further computation.
1633 //
1634 // Scratch registers:
1635 //
1636 // t0 - holds the untagged key on entry and holds the hash once computed.
1637 //
1638 // t1 - used to hold the capacity mask of the dictionary
1639 //
1640 // t2 - used for the index into the dictionary.
1641 Label done;
1642
1643 GetNumberHash(t0, t1);
1644
1645 // Compute the capacity mask.
1646 LoadP(t1, FieldMemOperand(elements, SeededNumberDictionary::kCapacityOffset));
1647 SmiUntag(t1);
1648 SubP(t1, Operand(1));
1649
1650 // Generate an unrolled loop that performs a few probes before giving up.
1651 for (int i = 0; i < kNumberDictionaryProbes; i++) {
1652 // Use t2 for index calculations and keep the hash intact in t0.
1653 LoadRR(t2, t0);
1654 // Compute the masked index: (hash + i + i * i) & mask.
1655 if (i > 0) {
1656 AddP(t2, Operand(SeededNumberDictionary::GetProbeOffset(i)));
1657 }
1658 AndP(t2, t1);
1659
1660 // Scale the index by multiplying by the element size.
1661 DCHECK(SeededNumberDictionary::kEntrySize == 3);
1662 LoadRR(ip, t2);
1663 sll(ip, Operand(1));
1664 AddP(t2, ip); // t2 = t2 * 3
1665
1666 // Check if the key is identical to the name.
1667 sll(t2, Operand(kPointerSizeLog2));
1668 AddP(t2, elements);
1669 LoadP(ip,
1670 FieldMemOperand(t2, SeededNumberDictionary::kElementsStartOffset));
1671 CmpP(key, ip);
1672 if (i != kNumberDictionaryProbes - 1) {
1673 beq(&done, Label::kNear);
1674 } else {
1675 bne(miss);
1676 }
1677 }
1678
1679 bind(&done);
1680 // Check that the value is a field property.
1681 // t2: elements + (index * kPointerSize)
1682 const int kDetailsOffset =
1683 SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
1684 LoadP(t1, FieldMemOperand(t2, kDetailsOffset));
1685 LoadSmiLiteral(ip, Smi::FromInt(PropertyDetails::TypeField::kMask));
1686 DCHECK_EQ(DATA, 0);
1687 AndP(r0, ip, t1);
1688 bne(miss);
1689
1690 // Get the value at the masked, scaled index and return.
1691 const int kValueOffset =
1692 SeededNumberDictionary::kElementsStartOffset + kPointerSize;
1693 LoadP(result, FieldMemOperand(t2, kValueOffset));
1694}
1695
1696void MacroAssembler::Allocate(int object_size, Register result,
1697 Register scratch1, Register scratch2,
1698 Label* gc_required, AllocationFlags flags) {
1699 DCHECK(object_size <= Page::kMaxRegularHeapObjectSize);
Ben Murdochc5610432016-08-08 18:44:38 +01001700 DCHECK((flags & ALLOCATION_FOLDED) == 0);
Ben Murdochda12d292016-06-02 14:46:10 +01001701 if (!FLAG_inline_new) {
1702 if (emit_debug_code()) {
1703 // Trash the registers to simulate an allocation failure.
1704 LoadImmP(result, Operand(0x7091));
1705 LoadImmP(scratch1, Operand(0x7191));
1706 LoadImmP(scratch2, Operand(0x7291));
1707 }
1708 b(gc_required);
1709 return;
1710 }
1711
1712 DCHECK(!AreAliased(result, scratch1, scratch2, ip));
1713
1714 // Make object size into bytes.
1715 if ((flags & SIZE_IN_WORDS) != 0) {
1716 object_size *= kPointerSize;
1717 }
1718 DCHECK_EQ(0, static_cast<int>(object_size & kObjectAlignmentMask));
1719
1720 // Check relative positions of allocation top and limit addresses.
1721 ExternalReference allocation_top =
1722 AllocationUtils::GetAllocationTopReference(isolate(), flags);
1723 ExternalReference allocation_limit =
1724 AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1725
1726 intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address());
1727 intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address());
1728 DCHECK((limit - top) == kPointerSize);
1729
1730 // Set up allocation top address register.
1731 Register top_address = scratch1;
1732 // This code stores a temporary value in ip. This is OK, as the code below
1733 // does not need ip for implicit literal generation.
1734 Register alloc_limit = ip;
1735 Register result_end = scratch2;
1736 mov(top_address, Operand(allocation_top));
1737
1738 if ((flags & RESULT_CONTAINS_TOP) == 0) {
1739 // Load allocation top into result and allocation limit into ip.
1740 LoadP(result, MemOperand(top_address));
1741 LoadP(alloc_limit, MemOperand(top_address, kPointerSize));
1742 } else {
1743 if (emit_debug_code()) {
1744 // Assert that result actually contains top on entry.
1745 LoadP(alloc_limit, MemOperand(top_address));
1746 CmpP(result, alloc_limit);
1747 Check(eq, kUnexpectedAllocationTop);
1748 }
1749 // Load allocation limit. Result already contains allocation top.
1750 LoadP(alloc_limit, MemOperand(top_address, limit - top));
1751 }
1752
1753 if ((flags & DOUBLE_ALIGNMENT) != 0) {
1754// Align the next allocation. Storing the filler map without checking top is
1755// safe in new-space because the limit of the heap is aligned there.
1756#if V8_TARGET_ARCH_S390X
1757 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
1758#else
1759 STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
1760 AndP(result_end, result, Operand(kDoubleAlignmentMask));
1761 Label aligned;
Ben Murdochc5610432016-08-08 18:44:38 +01001762 beq(&aligned, Label::kNear);
Ben Murdochda12d292016-06-02 14:46:10 +01001763 if ((flags & PRETENURE) != 0) {
1764 CmpLogicalP(result, alloc_limit);
1765 bge(gc_required);
1766 }
1767 mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
1768 StoreW(result_end, MemOperand(result));
1769 AddP(result, result, Operand(kDoubleSize / 2));
1770 bind(&aligned);
1771#endif
1772 }
1773
1774 // Calculate new top and bail out if new space is exhausted. Use result
1775 // to calculate the new top.
1776 SubP(r0, alloc_limit, result);
1777 if (is_int16(object_size)) {
1778 CmpP(r0, Operand(object_size));
1779 blt(gc_required);
1780 AddP(result_end, result, Operand(object_size));
1781 } else {
1782 mov(result_end, Operand(object_size));
1783 CmpP(r0, result_end);
1784 blt(gc_required);
1785 AddP(result_end, result, result_end);
1786 }
Ben Murdochda12d292016-06-02 14:46:10 +01001787
Ben Murdochc5610432016-08-08 18:44:38 +01001788 if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) {
1789 // The top pointer is not updated for allocation folding dominators.
1790 StoreP(result_end, MemOperand(top_address));
Ben Murdochda12d292016-06-02 14:46:10 +01001791 }
Ben Murdochc5610432016-08-08 18:44:38 +01001792
1793 // Tag object.
1794 AddP(result, result, Operand(kHeapObjectTag));
Ben Murdochda12d292016-06-02 14:46:10 +01001795}
1796
1797void MacroAssembler::Allocate(Register object_size, Register result,
1798 Register result_end, Register scratch,
1799 Label* gc_required, AllocationFlags flags) {
Ben Murdochc5610432016-08-08 18:44:38 +01001800 DCHECK((flags & ALLOCATION_FOLDED) == 0);
Ben Murdochda12d292016-06-02 14:46:10 +01001801 if (!FLAG_inline_new) {
1802 if (emit_debug_code()) {
1803 // Trash the registers to simulate an allocation failure.
1804 LoadImmP(result, Operand(0x7091));
1805 LoadImmP(scratch, Operand(0x7191));
1806 LoadImmP(result_end, Operand(0x7291));
1807 }
1808 b(gc_required);
1809 return;
1810 }
1811
1812 // |object_size| and |result_end| may overlap if the DOUBLE_ALIGNMENT flag
1813 // is not specified. Other registers must not overlap.
1814 DCHECK(!AreAliased(object_size, result, scratch, ip));
1815 DCHECK(!AreAliased(result_end, result, scratch, ip));
1816 DCHECK((flags & DOUBLE_ALIGNMENT) == 0 || !object_size.is(result_end));
1817
1818 // Check relative positions of allocation top and limit addresses.
1819 ExternalReference allocation_top =
1820 AllocationUtils::GetAllocationTopReference(isolate(), flags);
1821 ExternalReference allocation_limit =
1822 AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1823 intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address());
1824 intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address());
1825 DCHECK((limit - top) == kPointerSize);
1826
1827 // Set up allocation top address and allocation limit registers.
1828 Register top_address = scratch;
1829 // This code stores a temporary value in ip. This is OK, as the code below
1830 // does not need ip for implicit literal generation.
1831 Register alloc_limit = ip;
1832 mov(top_address, Operand(allocation_top));
1833
1834 if ((flags & RESULT_CONTAINS_TOP) == 0) {
1835 // Load allocation top into result and allocation limit into alloc_limit..
1836 LoadP(result, MemOperand(top_address));
1837 LoadP(alloc_limit, MemOperand(top_address, kPointerSize));
1838 } else {
1839 if (emit_debug_code()) {
1840 // Assert that result actually contains top on entry.
1841 LoadP(alloc_limit, MemOperand(top_address));
1842 CmpP(result, alloc_limit);
1843 Check(eq, kUnexpectedAllocationTop);
1844 }
1845 // Load allocation limit. Result already contains allocation top.
1846 LoadP(alloc_limit, MemOperand(top_address, limit - top));
1847 }
1848
1849 if ((flags & DOUBLE_ALIGNMENT) != 0) {
1850// Align the next allocation. Storing the filler map without checking top is
1851// safe in new-space because the limit of the heap is aligned there.
1852#if V8_TARGET_ARCH_S390X
1853 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
1854#else
1855 STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
1856 AndP(result_end, result, Operand(kDoubleAlignmentMask));
1857 Label aligned;
Ben Murdochc5610432016-08-08 18:44:38 +01001858 beq(&aligned, Label::kNear);
Ben Murdochda12d292016-06-02 14:46:10 +01001859 if ((flags & PRETENURE) != 0) {
1860 CmpLogicalP(result, alloc_limit);
1861 bge(gc_required);
1862 }
1863 mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
1864 StoreW(result_end, MemOperand(result));
1865 AddP(result, result, Operand(kDoubleSize / 2));
1866 bind(&aligned);
1867#endif
1868 }
1869
1870 // Calculate new top and bail out if new space is exhausted. Use result
1871 // to calculate the new top. Object size may be in words so a shift is
1872 // required to get the number of bytes.
1873 SubP(r0, alloc_limit, result);
1874 if ((flags & SIZE_IN_WORDS) != 0) {
1875 ShiftLeftP(result_end, object_size, Operand(kPointerSizeLog2));
1876 CmpP(r0, result_end);
1877 blt(gc_required);
1878 AddP(result_end, result, result_end);
1879 } else {
1880 CmpP(r0, object_size);
1881 blt(gc_required);
1882 AddP(result_end, result, object_size);
1883 }
1884
1885 // Update allocation top. result temporarily holds the new top.
1886 if (emit_debug_code()) {
1887 AndP(r0, result_end, Operand(kObjectAlignmentMask));
1888 Check(eq, kUnalignedAllocationInNewSpace, cr0);
1889 }
Ben Murdochc5610432016-08-08 18:44:38 +01001890 if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) {
1891 // The top pointer is not updated for allocation folding dominators.
1892 StoreP(result_end, MemOperand(top_address));
1893 }
1894
1895 // Tag object.
1896 AddP(result, result, Operand(kHeapObjectTag));
1897}
1898
1899void MacroAssembler::FastAllocate(Register object_size, Register result,
1900 Register result_end, Register scratch,
1901 AllocationFlags flags) {
1902 // |object_size| and |result_end| may overlap if the DOUBLE_ALIGNMENT flag
1903 // is not specified. Other registers must not overlap.
1904 DCHECK(!AreAliased(object_size, result, scratch, ip));
1905 DCHECK(!AreAliased(result_end, result, scratch, ip));
1906 DCHECK((flags & DOUBLE_ALIGNMENT) == 0 || !object_size.is(result_end));
1907
1908 ExternalReference allocation_top =
1909 AllocationUtils::GetAllocationTopReference(isolate(), flags);
1910
1911 Register top_address = scratch;
1912 mov(top_address, Operand(allocation_top));
1913 LoadP(result, MemOperand(top_address));
1914
1915 if ((flags & DOUBLE_ALIGNMENT) != 0) {
1916// Align the next allocation. Storing the filler map without checking top is
1917// safe in new-space because the limit of the heap is aligned there.
1918#if V8_TARGET_ARCH_S390X
1919 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
1920#else
1921 DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
1922 AndP(result_end, result, Operand(kDoubleAlignmentMask));
1923 Label aligned;
1924 beq(&aligned, Label::kNear);
1925 mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
1926 StoreW(result_end, MemOperand(result));
1927 AddP(result, result, Operand(kDoubleSize / 2));
1928 bind(&aligned);
1929#endif
1930 }
1931
1932 // Calculate new top using result. Object size may be in words so a shift is
1933 // required to get the number of bytes.
1934 if ((flags & SIZE_IN_WORDS) != 0) {
1935 ShiftLeftP(result_end, object_size, Operand(kPointerSizeLog2));
1936 AddP(result_end, result, result_end);
1937 } else {
1938 AddP(result_end, result, object_size);
1939 }
1940
1941 // Update allocation top. result temporarily holds the new top.
1942 if (emit_debug_code()) {
1943 AndP(r0, result_end, Operand(kObjectAlignmentMask));
1944 Check(eq, kUnalignedAllocationInNewSpace, cr0);
1945 }
Ben Murdochda12d292016-06-02 14:46:10 +01001946 StoreP(result_end, MemOperand(top_address));
1947
Ben Murdochc5610432016-08-08 18:44:38 +01001948 // Tag object.
1949 AddP(result, result, Operand(kHeapObjectTag));
1950}
1951
1952void MacroAssembler::FastAllocate(int object_size, Register result,
1953 Register scratch1, Register scratch2,
1954 AllocationFlags flags) {
1955 DCHECK(object_size <= Page::kMaxRegularHeapObjectSize);
1956 DCHECK(!AreAliased(result, scratch1, scratch2, ip));
1957
1958 // Make object size into bytes.
1959 if ((flags & SIZE_IN_WORDS) != 0) {
1960 object_size *= kPointerSize;
Ben Murdochda12d292016-06-02 14:46:10 +01001961 }
Ben Murdochc5610432016-08-08 18:44:38 +01001962 DCHECK_EQ(0, object_size & kObjectAlignmentMask);
1963
1964 ExternalReference allocation_top =
1965 AllocationUtils::GetAllocationTopReference(isolate(), flags);
1966
1967 // Set up allocation top address register.
1968 Register top_address = scratch1;
1969 Register result_end = scratch2;
1970 mov(top_address, Operand(allocation_top));
1971 LoadP(result, MemOperand(top_address));
1972
1973 if ((flags & DOUBLE_ALIGNMENT) != 0) {
1974// Align the next allocation. Storing the filler map without checking top is
1975// safe in new-space because the limit of the heap is aligned there.
1976#if V8_TARGET_ARCH_S390X
1977 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
1978#else
1979 DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
1980 AndP(result_end, result, Operand(kDoubleAlignmentMask));
1981 Label aligned;
1982 beq(&aligned, Label::kNear);
1983 mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
1984 StoreW(result_end, MemOperand(result));
1985 AddP(result, result, Operand(kDoubleSize / 2));
1986 bind(&aligned);
1987#endif
1988 }
1989
1990 // Calculate new top using result.
1991 AddP(result_end, result, Operand(object_size));
1992
1993 // The top pointer is not updated for allocation folding dominators.
1994 StoreP(result_end, MemOperand(top_address));
1995
1996 // Tag object.
1997 AddP(result, result, Operand(kHeapObjectTag));
Ben Murdochda12d292016-06-02 14:46:10 +01001998}
1999
2000void MacroAssembler::AllocateTwoByteString(Register result, Register length,
2001 Register scratch1, Register scratch2,
2002 Register scratch3,
2003 Label* gc_required) {
2004 // Calculate the number of bytes needed for the characters in the string while
2005 // observing object alignment.
2006 DCHECK((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
2007
2008 ShiftLeftP(scratch1, length, Operand(1)); // Length in bytes, not chars.
2009 AddP(scratch1, Operand(kObjectAlignmentMask + SeqTwoByteString::kHeaderSize));
2010
2011 AndP(scratch1, Operand(~kObjectAlignmentMask));
2012
2013 // Allocate two-byte string in new space.
Ben Murdochc5610432016-08-08 18:44:38 +01002014 Allocate(scratch1, result, scratch2, scratch3, gc_required,
2015 NO_ALLOCATION_FLAGS);
Ben Murdochda12d292016-06-02 14:46:10 +01002016
2017 // Set the map, length and hash field.
2018 InitializeNewString(result, length, Heap::kStringMapRootIndex, scratch1,
2019 scratch2);
2020}
2021
2022void MacroAssembler::AllocateOneByteString(Register result, Register length,
2023 Register scratch1, Register scratch2,
2024 Register scratch3,
2025 Label* gc_required) {
2026 // Calculate the number of bytes needed for the characters in the string while
2027 // observing object alignment.
2028 DCHECK((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
2029 DCHECK(kCharSize == 1);
2030 AddP(scratch1, length,
2031 Operand(kObjectAlignmentMask + SeqOneByteString::kHeaderSize));
2032 AndP(scratch1, Operand(~kObjectAlignmentMask));
2033
2034 // Allocate one-byte string in new space.
Ben Murdochc5610432016-08-08 18:44:38 +01002035 Allocate(scratch1, result, scratch2, scratch3, gc_required,
2036 NO_ALLOCATION_FLAGS);
Ben Murdochda12d292016-06-02 14:46:10 +01002037
2038 // Set the map, length and hash field.
2039 InitializeNewString(result, length, Heap::kOneByteStringMapRootIndex,
2040 scratch1, scratch2);
2041}
2042
2043void MacroAssembler::AllocateTwoByteConsString(Register result, Register length,
2044 Register scratch1,
2045 Register scratch2,
2046 Label* gc_required) {
2047 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
Ben Murdochc5610432016-08-08 18:44:38 +01002048 NO_ALLOCATION_FLAGS);
Ben Murdochda12d292016-06-02 14:46:10 +01002049
2050 InitializeNewString(result, length, Heap::kConsStringMapRootIndex, scratch1,
2051 scratch2);
2052}
2053
2054void MacroAssembler::AllocateOneByteConsString(Register result, Register length,
2055 Register scratch1,
2056 Register scratch2,
2057 Label* gc_required) {
2058 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
Ben Murdochc5610432016-08-08 18:44:38 +01002059 NO_ALLOCATION_FLAGS);
Ben Murdochda12d292016-06-02 14:46:10 +01002060
2061 InitializeNewString(result, length, Heap::kConsOneByteStringMapRootIndex,
2062 scratch1, scratch2);
2063}
2064
2065void MacroAssembler::AllocateTwoByteSlicedString(Register result,
2066 Register length,
2067 Register scratch1,
2068 Register scratch2,
2069 Label* gc_required) {
2070 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
Ben Murdochc5610432016-08-08 18:44:38 +01002071 NO_ALLOCATION_FLAGS);
Ben Murdochda12d292016-06-02 14:46:10 +01002072
2073 InitializeNewString(result, length, Heap::kSlicedStringMapRootIndex, scratch1,
2074 scratch2);
2075}
2076
2077void MacroAssembler::AllocateOneByteSlicedString(Register result,
2078 Register length,
2079 Register scratch1,
2080 Register scratch2,
2081 Label* gc_required) {
2082 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
Ben Murdochc5610432016-08-08 18:44:38 +01002083 NO_ALLOCATION_FLAGS);
Ben Murdochda12d292016-06-02 14:46:10 +01002084
2085 InitializeNewString(result, length, Heap::kSlicedOneByteStringMapRootIndex,
2086 scratch1, scratch2);
2087}
2088
2089void MacroAssembler::CompareObjectType(Register object, Register map,
2090 Register type_reg, InstanceType type) {
2091 const Register temp = type_reg.is(no_reg) ? r0 : type_reg;
2092
2093 LoadP(map, FieldMemOperand(object, HeapObject::kMapOffset));
2094 CompareInstanceType(map, temp, type);
2095}
2096
2097void MacroAssembler::CompareInstanceType(Register map, Register type_reg,
2098 InstanceType type) {
2099 STATIC_ASSERT(Map::kInstanceTypeOffset < 4096);
2100 STATIC_ASSERT(LAST_TYPE < 256);
2101 LoadlB(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
2102 CmpP(type_reg, Operand(type));
2103}
2104
2105void MacroAssembler::CompareRoot(Register obj, Heap::RootListIndex index) {
2106 CmpP(obj, MemOperand(kRootRegister, index << kPointerSizeLog2));
2107}
2108
2109void MacroAssembler::CheckFastElements(Register map, Register scratch,
2110 Label* fail) {
2111 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
2112 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
2113 STATIC_ASSERT(FAST_ELEMENTS == 2);
2114 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
2115 STATIC_ASSERT(Map::kMaximumBitField2FastHoleyElementValue < 0x8000);
2116 CmpLogicalByte(FieldMemOperand(map, Map::kBitField2Offset),
2117 Operand(Map::kMaximumBitField2FastHoleyElementValue));
2118 bgt(fail);
2119}
2120
2121void MacroAssembler::CheckFastObjectElements(Register map, Register scratch,
2122 Label* fail) {
2123 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
2124 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
2125 STATIC_ASSERT(FAST_ELEMENTS == 2);
2126 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
2127 CmpLogicalByte(FieldMemOperand(map, Map::kBitField2Offset),
2128 Operand(Map::kMaximumBitField2FastHoleySmiElementValue));
2129 ble(fail);
2130 CmpLogicalByte(FieldMemOperand(map, Map::kBitField2Offset),
2131 Operand(Map::kMaximumBitField2FastHoleyElementValue));
2132 bgt(fail);
2133}
2134
2135void MacroAssembler::CheckFastSmiElements(Register map, Register scratch,
2136 Label* fail) {
2137 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
2138 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
2139 CmpLogicalByte(FieldMemOperand(map, Map::kBitField2Offset),
2140 Operand(Map::kMaximumBitField2FastHoleySmiElementValue));
2141 bgt(fail);
2142}
2143
2144void MacroAssembler::SmiToDouble(DoubleRegister value, Register smi) {
2145 SmiUntag(ip, smi);
2146 ConvertIntToDouble(ip, value);
2147}
2148void MacroAssembler::StoreNumberToDoubleElements(
2149 Register value_reg, Register key_reg, Register elements_reg,
2150 Register scratch1, DoubleRegister double_scratch, Label* fail,
2151 int elements_offset) {
2152 DCHECK(!AreAliased(value_reg, key_reg, elements_reg, scratch1));
2153 Label smi_value, store;
2154
2155 // Handle smi values specially.
2156 JumpIfSmi(value_reg, &smi_value);
2157
2158 // Ensure that the object is a heap number
2159 CheckMap(value_reg, scratch1, isolate()->factory()->heap_number_map(), fail,
2160 DONT_DO_SMI_CHECK);
2161
2162 LoadDouble(double_scratch,
2163 FieldMemOperand(value_reg, HeapNumber::kValueOffset));
2164 // Force a canonical NaN.
2165 CanonicalizeNaN(double_scratch);
2166 b(&store);
2167
2168 bind(&smi_value);
2169 SmiToDouble(double_scratch, value_reg);
2170
2171 bind(&store);
2172 SmiToDoubleArrayOffset(scratch1, key_reg);
2173 StoreDouble(double_scratch,
2174 FieldMemOperand(elements_reg, scratch1,
2175 FixedDoubleArray::kHeaderSize - elements_offset));
2176}
2177
2178void MacroAssembler::AddAndCheckForOverflow(Register dst, Register left,
2179 Register right,
2180 Register overflow_dst,
2181 Register scratch) {
2182 DCHECK(!dst.is(overflow_dst));
2183 DCHECK(!dst.is(scratch));
2184 DCHECK(!overflow_dst.is(scratch));
2185 DCHECK(!overflow_dst.is(left));
2186 DCHECK(!overflow_dst.is(right));
2187
2188 // TODO(joransiu): Optimize paths for left == right.
2189 bool left_is_right = left.is(right);
2190
2191 // C = A+B; C overflows if A/B have same sign and C has diff sign than A
2192 if (dst.is(left)) {
2193 LoadRR(scratch, left); // Preserve left.
2194 AddP(dst, left, right); // Left is overwritten.
2195 XorP(overflow_dst, scratch, dst); // Original left.
2196 if (!left_is_right) XorP(scratch, dst, right);
2197 } else if (dst.is(right)) {
2198 LoadRR(scratch, right); // Preserve right.
2199 AddP(dst, left, right); // Right is overwritten.
2200 XorP(overflow_dst, dst, left);
2201 if (!left_is_right) XorP(scratch, dst, scratch);
2202 } else {
2203 AddP(dst, left, right);
2204 XorP(overflow_dst, dst, left);
2205 if (!left_is_right) XorP(scratch, dst, right);
2206 }
2207 if (!left_is_right) AndP(overflow_dst, scratch, overflow_dst);
2208 LoadAndTestRR(overflow_dst, overflow_dst);
2209}
2210
2211void MacroAssembler::AddAndCheckForOverflow(Register dst, Register left,
2212 intptr_t right,
2213 Register overflow_dst,
2214 Register scratch) {
2215 DCHECK(!dst.is(overflow_dst));
2216 DCHECK(!dst.is(scratch));
2217 DCHECK(!overflow_dst.is(scratch));
2218 DCHECK(!overflow_dst.is(left));
2219
2220 mov(r1, Operand(right));
2221 AddAndCheckForOverflow(dst, left, r1, overflow_dst, scratch);
2222}
2223
2224void MacroAssembler::SubAndCheckForOverflow(Register dst, Register left,
2225 Register right,
2226 Register overflow_dst,
2227 Register scratch) {
2228 DCHECK(!dst.is(overflow_dst));
2229 DCHECK(!dst.is(scratch));
2230 DCHECK(!overflow_dst.is(scratch));
2231 DCHECK(!overflow_dst.is(left));
2232 DCHECK(!overflow_dst.is(right));
2233
2234 // C = A-B; C overflows if A/B have diff signs and C has diff sign than A
2235 if (dst.is(left)) {
2236 LoadRR(scratch, left); // Preserve left.
2237 SubP(dst, left, right); // Left is overwritten.
2238 XorP(overflow_dst, dst, scratch);
2239 XorP(scratch, right);
2240 AndP(overflow_dst, scratch /*, SetRC*/);
2241 LoadAndTestRR(overflow_dst, overflow_dst);
2242 // Should be okay to remove rc
2243 } else if (dst.is(right)) {
2244 LoadRR(scratch, right); // Preserve right.
2245 SubP(dst, left, right); // Right is overwritten.
2246 XorP(overflow_dst, dst, left);
2247 XorP(scratch, left);
2248 AndP(overflow_dst, scratch /*, SetRC*/);
2249 LoadAndTestRR(overflow_dst, overflow_dst);
2250 // Should be okay to remove rc
2251 } else {
2252 SubP(dst, left, right);
2253 XorP(overflow_dst, dst, left);
2254 XorP(scratch, left, right);
2255 AndP(overflow_dst, scratch /*, SetRC*/);
2256 LoadAndTestRR(overflow_dst, overflow_dst);
2257 // Should be okay to remove rc
2258 }
2259}
2260
2261void MacroAssembler::CompareMap(Register obj, Register scratch, Handle<Map> map,
2262 Label* early_success) {
2263 LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
2264 CompareMap(obj, map, early_success);
2265}
2266
2267void MacroAssembler::CompareMap(Register obj_map, Handle<Map> map,
2268 Label* early_success) {
2269 mov(r0, Operand(map));
2270 CmpP(r0, FieldMemOperand(obj_map, HeapObject::kMapOffset));
2271}
2272
2273void MacroAssembler::CheckMap(Register obj, Register scratch, Handle<Map> map,
2274 Label* fail, SmiCheckType smi_check_type) {
2275 if (smi_check_type == DO_SMI_CHECK) {
2276 JumpIfSmi(obj, fail);
2277 }
2278
2279 Label success;
2280 CompareMap(obj, scratch, map, &success);
2281 bne(fail);
2282 bind(&success);
2283}
2284
2285void MacroAssembler::CheckMap(Register obj, Register scratch,
2286 Heap::RootListIndex index, Label* fail,
2287 SmiCheckType smi_check_type) {
2288 if (smi_check_type == DO_SMI_CHECK) {
2289 JumpIfSmi(obj, fail);
2290 }
2291 LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
2292 CompareRoot(scratch, index);
2293 bne(fail);
2294}
2295
2296void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1,
2297 Register scratch2, Handle<WeakCell> cell,
2298 Handle<Code> success,
2299 SmiCheckType smi_check_type) {
2300 Label fail;
2301 if (smi_check_type == DO_SMI_CHECK) {
2302 JumpIfSmi(obj, &fail);
2303 }
2304 LoadP(scratch1, FieldMemOperand(obj, HeapObject::kMapOffset));
2305 CmpWeakValue(scratch1, cell, scratch2);
2306 Jump(success, RelocInfo::CODE_TARGET, eq);
2307 bind(&fail);
2308}
2309
2310void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell,
2311 Register scratch, CRegister) {
2312 mov(scratch, Operand(cell));
2313 CmpP(value, FieldMemOperand(scratch, WeakCell::kValueOffset));
2314}
2315
2316void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) {
2317 mov(value, Operand(cell));
2318 LoadP(value, FieldMemOperand(value, WeakCell::kValueOffset));
2319}
2320
2321void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
2322 Label* miss) {
2323 GetWeakValue(value, cell);
2324 JumpIfSmi(value, miss);
2325}
2326
2327void MacroAssembler::GetMapConstructor(Register result, Register map,
2328 Register temp, Register temp2) {
2329 Label done, loop;
2330 LoadP(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset));
2331 bind(&loop);
2332 JumpIfSmi(result, &done);
2333 CompareObjectType(result, temp, temp2, MAP_TYPE);
2334 bne(&done);
2335 LoadP(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset));
2336 b(&loop);
2337 bind(&done);
2338}
2339
2340void MacroAssembler::TryGetFunctionPrototype(Register function, Register result,
2341 Register scratch, Label* miss) {
2342 // Get the prototype or initial map from the function.
2343 LoadP(result,
2344 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2345
2346 // If the prototype or initial map is the hole, don't return it and
2347 // simply miss the cache instead. This will allow us to allocate a
2348 // prototype object on-demand in the runtime system.
2349 CompareRoot(result, Heap::kTheHoleValueRootIndex);
2350 beq(miss);
2351
2352 // If the function does not have an initial map, we're done.
2353 Label done;
2354 CompareObjectType(result, scratch, scratch, MAP_TYPE);
2355 bne(&done, Label::kNear);
2356
2357 // Get the prototype from the initial map.
2358 LoadP(result, FieldMemOperand(result, Map::kPrototypeOffset));
2359
2360 // All done.
2361 bind(&done);
2362}
2363
2364void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id,
2365 Condition cond) {
2366 DCHECK(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs.
2367 Call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id, cond);
2368}
2369
2370void MacroAssembler::TailCallStub(CodeStub* stub, Condition cond) {
2371 Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond);
2372}
2373
2374bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
2375 return has_frame_ || !stub->SometimesSetsUpAFrame();
2376}
2377
2378void MacroAssembler::IndexFromHash(Register hash, Register index) {
2379 // If the hash field contains an array index pick it out. The assert checks
2380 // that the constants for the maximum number of digits for an array index
2381 // cached in the hash field and the number of bits reserved for it does not
2382 // conflict.
2383 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
2384 (1 << String::kArrayIndexValueBits));
2385 DecodeFieldToSmi<String::ArrayIndexValueBits>(index, hash);
2386}
2387
2388void MacroAssembler::TestDoubleIsInt32(DoubleRegister double_input,
2389 Register scratch1, Register scratch2,
2390 DoubleRegister double_scratch) {
2391 TryDoubleToInt32Exact(scratch1, double_input, scratch2, double_scratch);
2392}
2393
2394void MacroAssembler::TestDoubleIsMinusZero(DoubleRegister input,
2395 Register scratch1,
2396 Register scratch2) {
2397 lgdr(scratch1, input);
2398#if V8_TARGET_ARCH_S390X
2399 llihf(scratch2, Operand(0x80000000)); // scratch2 = 0x80000000_00000000
2400 CmpP(scratch1, scratch2);
2401#else
2402 Label done;
2403 CmpP(scratch1, Operand::Zero());
2404 bne(&done, Label::kNear);
2405
2406 srlg(scratch1, scratch1, Operand(32));
2407 CmpP(scratch1, Operand(HeapNumber::kSignMask));
2408 bind(&done);
2409#endif
2410}
2411
2412void MacroAssembler::TestDoubleSign(DoubleRegister input, Register scratch) {
Ben Murdoch6f5d0ea2016-06-15 14:45:46 +01002413 lgdr(scratch, input);
2414 cgfi(scratch, Operand::Zero());
Ben Murdochda12d292016-06-02 14:46:10 +01002415}
2416
2417void MacroAssembler::TestHeapNumberSign(Register input, Register scratch) {
2418 LoadlW(scratch, FieldMemOperand(input, HeapNumber::kValueOffset +
2419 Register::kExponentOffset));
2420 Cmp32(scratch, Operand::Zero());
2421}
2422
2423void MacroAssembler::TryDoubleToInt32Exact(Register result,
2424 DoubleRegister double_input,
2425 Register scratch,
2426 DoubleRegister double_scratch) {
2427 Label done;
2428 DCHECK(!double_input.is(double_scratch));
2429
2430 ConvertDoubleToInt64(double_input,
2431#if !V8_TARGET_ARCH_S390X
2432 scratch,
2433#endif
2434 result, double_scratch);
2435
2436#if V8_TARGET_ARCH_S390X
2437 TestIfInt32(result, r0);
2438#else
2439 TestIfInt32(scratch, result, r0);
2440#endif
2441 bne(&done);
2442
2443 // convert back and compare
2444 lgdr(scratch, double_scratch);
2445 cdfbr(double_scratch, scratch);
2446 cdbr(double_scratch, double_input);
2447 bind(&done);
2448}
2449
2450void MacroAssembler::TryInt32Floor(Register result, DoubleRegister double_input,
2451 Register input_high, Register scratch,
2452 DoubleRegister double_scratch, Label* done,
2453 Label* exact) {
2454 DCHECK(!result.is(input_high));
2455 DCHECK(!double_input.is(double_scratch));
2456 Label exception;
2457
2458 // Move high word into input_high
Ben Murdochda12d292016-06-02 14:46:10 +01002459 lay(sp, MemOperand(sp, -kDoubleSize));
Ben Murdoch6f5d0ea2016-06-15 14:45:46 +01002460 StoreDouble(double_input, MemOperand(sp));
Ben Murdochda12d292016-06-02 14:46:10 +01002461 LoadlW(input_high, MemOperand(sp, Register::kExponentOffset));
2462 la(sp, MemOperand(sp, kDoubleSize));
2463
2464 // Test for NaN/Inf
2465 ExtractBitMask(result, input_high, HeapNumber::kExponentMask);
2466 CmpLogicalP(result, Operand(0x7ff));
2467 beq(&exception);
2468
2469 // Convert (rounding to -Inf)
2470 ConvertDoubleToInt64(double_input,
2471#if !V8_TARGET_ARCH_S390X
2472 scratch,
2473#endif
2474 result, double_scratch, kRoundToMinusInf);
2475
2476// Test for overflow
2477#if V8_TARGET_ARCH_S390X
2478 TestIfInt32(result, r0);
2479#else
2480 TestIfInt32(scratch, result, r0);
2481#endif
2482 bne(&exception);
2483
2484 // Test for exactness
2485 lgdr(scratch, double_scratch);
2486 cdfbr(double_scratch, scratch);
2487 cdbr(double_scratch, double_input);
2488 beq(exact);
2489 b(done);
2490
2491 bind(&exception);
2492}
2493
2494void MacroAssembler::TryInlineTruncateDoubleToI(Register result,
2495 DoubleRegister double_input,
2496 Label* done) {
2497 DoubleRegister double_scratch = kScratchDoubleReg;
2498#if !V8_TARGET_ARCH_S390X
2499 Register scratch = ip;
2500#endif
2501
2502 ConvertDoubleToInt64(double_input,
2503#if !V8_TARGET_ARCH_S390X
2504 scratch,
2505#endif
2506 result, double_scratch);
2507
2508// Test for overflow
2509#if V8_TARGET_ARCH_S390X
2510 TestIfInt32(result, r0);
2511#else
2512 TestIfInt32(scratch, result, r0);
2513#endif
2514 beq(done);
2515}
2516
2517void MacroAssembler::TruncateDoubleToI(Register result,
2518 DoubleRegister double_input) {
2519 Label done;
2520
2521 TryInlineTruncateDoubleToI(result, double_input, &done);
2522
2523 // If we fell through then inline version didn't succeed - call stub instead.
2524 push(r14);
2525 // Put input on stack.
Ben Murdochda12d292016-06-02 14:46:10 +01002526 lay(sp, MemOperand(sp, -kDoubleSize));
Ben Murdoch6f5d0ea2016-06-15 14:45:46 +01002527 StoreDouble(double_input, MemOperand(sp));
Ben Murdochda12d292016-06-02 14:46:10 +01002528
2529 DoubleToIStub stub(isolate(), sp, result, 0, true, true);
2530 CallStub(&stub);
2531
2532 la(sp, MemOperand(sp, kDoubleSize));
2533 pop(r14);
2534
2535 bind(&done);
2536}
2537
2538void MacroAssembler::TruncateHeapNumberToI(Register result, Register object) {
2539 Label done;
2540 DoubleRegister double_scratch = kScratchDoubleReg;
2541 DCHECK(!result.is(object));
2542
2543 LoadDouble(double_scratch, FieldMemOperand(object, HeapNumber::kValueOffset));
2544 TryInlineTruncateDoubleToI(result, double_scratch, &done);
2545
2546 // If we fell through then inline version didn't succeed - call stub instead.
2547 push(r14);
2548 DoubleToIStub stub(isolate(), object, result,
2549 HeapNumber::kValueOffset - kHeapObjectTag, true, true);
2550 CallStub(&stub);
2551 pop(r14);
2552
2553 bind(&done);
2554}
2555
2556void MacroAssembler::TruncateNumberToI(Register object, Register result,
2557 Register heap_number_map,
2558 Register scratch1, Label* not_number) {
2559 Label done;
2560 DCHECK(!result.is(object));
2561
2562 UntagAndJumpIfSmi(result, object, &done);
2563 JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number);
2564 TruncateHeapNumberToI(result, object);
2565
2566 bind(&done);
2567}
2568
2569void MacroAssembler::GetLeastBitsFromSmi(Register dst, Register src,
2570 int num_least_bits) {
2571 if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) {
2572 // We rotate by kSmiShift amount, and extract the num_least_bits
2573 risbg(dst, src, Operand(64 - num_least_bits), Operand(63),
2574 Operand(64 - kSmiShift), true);
2575 } else {
2576 SmiUntag(dst, src);
2577 AndP(dst, Operand((1 << num_least_bits) - 1));
2578 }
2579}
2580
2581void MacroAssembler::GetLeastBitsFromInt32(Register dst, Register src,
2582 int num_least_bits) {
2583 AndP(dst, src, Operand((1 << num_least_bits) - 1));
2584}
2585
2586void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments,
2587 SaveFPRegsMode save_doubles) {
2588 // All parameters are on the stack. r2 has the return value after call.
2589
2590 // If the expected number of arguments of the runtime function is
2591 // constant, we check that the actual number of arguments match the
2592 // expectation.
2593 CHECK(f->nargs < 0 || f->nargs == num_arguments);
2594
2595 // TODO(1236192): Most runtime routines don't need the number of
2596 // arguments passed in because it is constant. At some point we
2597 // should remove this need and make the runtime routine entry code
2598 // smarter.
2599 mov(r2, Operand(num_arguments));
2600 mov(r3, Operand(ExternalReference(f, isolate())));
2601 CEntryStub stub(isolate(),
2602#if V8_TARGET_ARCH_S390X
2603 f->result_size,
2604#else
2605 1,
2606#endif
2607 save_doubles);
2608 CallStub(&stub);
2609}
2610
2611void MacroAssembler::CallExternalReference(const ExternalReference& ext,
2612 int num_arguments) {
2613 mov(r2, Operand(num_arguments));
2614 mov(r3, Operand(ext));
2615
2616 CEntryStub stub(isolate(), 1);
2617 CallStub(&stub);
2618}
2619
2620void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
2621 const Runtime::Function* function = Runtime::FunctionForId(fid);
2622 DCHECK_EQ(1, function->result_size);
2623 if (function->nargs >= 0) {
2624 mov(r2, Operand(function->nargs));
2625 }
2626 JumpToExternalReference(ExternalReference(fid, isolate()));
2627}
2628
2629void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin) {
2630 mov(r3, Operand(builtin));
2631 CEntryStub stub(isolate(), 1);
2632 Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
2633}
2634
2635void MacroAssembler::SetCounter(StatsCounter* counter, int value,
2636 Register scratch1, Register scratch2) {
2637 if (FLAG_native_code_counters && counter->Enabled()) {
2638 mov(scratch1, Operand(value));
2639 mov(scratch2, Operand(ExternalReference(counter)));
2640 StoreW(scratch1, MemOperand(scratch2));
2641 }
2642}
2643
2644void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
2645 Register scratch1, Register scratch2) {
2646 DCHECK(value > 0 && is_int8(value));
2647 if (FLAG_native_code_counters && counter->Enabled()) {
2648 mov(scratch1, Operand(ExternalReference(counter)));
2649 // @TODO(john.yan): can be optimized by asi()
2650 LoadW(scratch2, MemOperand(scratch1));
2651 AddP(scratch2, Operand(value));
2652 StoreW(scratch2, MemOperand(scratch1));
2653 }
2654}
2655
2656void MacroAssembler::DecrementCounter(StatsCounter* counter, int value,
2657 Register scratch1, Register scratch2) {
2658 DCHECK(value > 0 && is_int8(value));
2659 if (FLAG_native_code_counters && counter->Enabled()) {
2660 mov(scratch1, Operand(ExternalReference(counter)));
2661 // @TODO(john.yan): can be optimized by asi()
2662 LoadW(scratch2, MemOperand(scratch1));
2663 AddP(scratch2, Operand(-value));
2664 StoreW(scratch2, MemOperand(scratch1));
2665 }
2666}
2667
2668void MacroAssembler::Assert(Condition cond, BailoutReason reason,
2669 CRegister cr) {
2670 if (emit_debug_code()) Check(cond, reason, cr);
2671}
2672
2673void MacroAssembler::AssertFastElements(Register elements) {
2674 if (emit_debug_code()) {
2675 DCHECK(!elements.is(r0));
2676 Label ok;
2677 push(elements);
2678 LoadP(elements, FieldMemOperand(elements, HeapObject::kMapOffset));
2679 CompareRoot(elements, Heap::kFixedArrayMapRootIndex);
2680 beq(&ok, Label::kNear);
2681 CompareRoot(elements, Heap::kFixedDoubleArrayMapRootIndex);
2682 beq(&ok, Label::kNear);
2683 CompareRoot(elements, Heap::kFixedCOWArrayMapRootIndex);
2684 beq(&ok, Label::kNear);
2685 Abort(kJSObjectWithFastElementsMapHasSlowElements);
2686 bind(&ok);
2687 pop(elements);
2688 }
2689}
2690
2691void MacroAssembler::Check(Condition cond, BailoutReason reason, CRegister cr) {
2692 Label L;
2693 b(cond, &L);
2694 Abort(reason);
2695 // will not return here
2696 bind(&L);
2697}
2698
2699void MacroAssembler::Abort(BailoutReason reason) {
2700 Label abort_start;
2701 bind(&abort_start);
2702#ifdef DEBUG
2703 const char* msg = GetBailoutReason(reason);
2704 if (msg != NULL) {
2705 RecordComment("Abort message: ");
2706 RecordComment(msg);
2707 }
2708
2709 if (FLAG_trap_on_abort) {
2710 stop(msg);
2711 return;
2712 }
2713#endif
2714
2715 LoadSmiLiteral(r0, Smi::FromInt(reason));
2716 push(r0);
2717 // Disable stub call restrictions to always allow calls to abort.
2718 if (!has_frame_) {
2719 // We don't actually want to generate a pile of code for this, so just
2720 // claim there is a stack frame, without generating one.
2721 FrameScope scope(this, StackFrame::NONE);
2722 CallRuntime(Runtime::kAbort);
2723 } else {
2724 CallRuntime(Runtime::kAbort);
2725 }
2726 // will not return here
2727}
2728
2729void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
2730 if (context_chain_length > 0) {
2731 // Move up the chain of contexts to the context containing the slot.
2732 LoadP(dst, MemOperand(cp, Context::SlotOffset(Context::PREVIOUS_INDEX)));
2733 for (int i = 1; i < context_chain_length; i++) {
2734 LoadP(dst, MemOperand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX)));
2735 }
2736 } else {
2737 // Slot is in the current function context. Move it into the
2738 // destination register in case we store into it (the write barrier
2739 // cannot be allowed to destroy the context in esi).
2740 LoadRR(dst, cp);
2741 }
2742}
2743
2744void MacroAssembler::LoadTransitionedArrayMapConditional(
2745 ElementsKind expected_kind, ElementsKind transitioned_kind,
2746 Register map_in_out, Register scratch, Label* no_map_match) {
2747 DCHECK(IsFastElementsKind(expected_kind));
2748 DCHECK(IsFastElementsKind(transitioned_kind));
2749
2750 // Check that the function's map is the same as the expected cached map.
2751 LoadP(scratch, NativeContextMemOperand());
2752 LoadP(ip, ContextMemOperand(scratch, Context::ArrayMapIndex(expected_kind)));
2753 CmpP(map_in_out, ip);
2754 bne(no_map_match);
2755
2756 // Use the transitioned cached map.
2757 LoadP(map_in_out,
2758 ContextMemOperand(scratch, Context::ArrayMapIndex(transitioned_kind)));
2759}
2760
2761void MacroAssembler::LoadNativeContextSlot(int index, Register dst) {
2762 LoadP(dst, NativeContextMemOperand());
2763 LoadP(dst, ContextMemOperand(dst, index));
2764}
2765
2766void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
2767 Register map,
2768 Register scratch) {
2769 // Load the initial map. The global functions all have initial maps.
2770 LoadP(map,
2771 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2772 if (emit_debug_code()) {
2773 Label ok, fail;
2774 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK);
2775 b(&ok);
2776 bind(&fail);
2777 Abort(kGlobalFunctionsMustHaveInitialMap);
2778 bind(&ok);
2779 }
2780}
2781
2782void MacroAssembler::JumpIfNotPowerOfTwoOrZero(
2783 Register reg, Register scratch, Label* not_power_of_two_or_zero) {
2784 SubP(scratch, reg, Operand(1));
2785 CmpP(scratch, Operand::Zero());
2786 blt(not_power_of_two_or_zero);
2787 AndP(r0, reg, scratch /*, SetRC*/); // Should be okay to remove rc
2788 bne(not_power_of_two_or_zero /*, cr0*/);
2789}
2790
2791void MacroAssembler::JumpIfNotPowerOfTwoOrZeroAndNeg(Register reg,
2792 Register scratch,
2793 Label* zero_and_neg,
2794 Label* not_power_of_two) {
2795 SubP(scratch, reg, Operand(1));
2796 CmpP(scratch, Operand::Zero());
2797 blt(zero_and_neg);
2798 AndP(r0, reg, scratch /*, SetRC*/); // Should be okay to remove rc
2799 bne(not_power_of_two /*, cr0*/);
2800}
2801
2802#if !V8_TARGET_ARCH_S390X
2803void MacroAssembler::SmiTagCheckOverflow(Register reg, Register overflow) {
2804 DCHECK(!reg.is(overflow));
2805 LoadRR(overflow, reg); // Save original value.
2806 SmiTag(reg);
2807 XorP(overflow, overflow, reg); // Overflow if (value ^ 2 * value) < 0.
2808 LoadAndTestRR(overflow, overflow);
2809}
2810
2811void MacroAssembler::SmiTagCheckOverflow(Register dst, Register src,
2812 Register overflow) {
2813 if (dst.is(src)) {
2814 // Fall back to slower case.
2815 SmiTagCheckOverflow(dst, overflow);
2816 } else {
2817 DCHECK(!dst.is(src));
2818 DCHECK(!dst.is(overflow));
2819 DCHECK(!src.is(overflow));
2820 SmiTag(dst, src);
2821 XorP(overflow, dst, src); // Overflow if (value ^ 2 * value) < 0.
2822 LoadAndTestRR(overflow, overflow);
2823 }
2824}
2825#endif
2826
2827void MacroAssembler::JumpIfNotBothSmi(Register reg1, Register reg2,
2828 Label* on_not_both_smi) {
2829 STATIC_ASSERT(kSmiTag == 0);
2830 OrP(r0, reg1, reg2 /*, LeaveRC*/); // should be okay to remove LeaveRC
2831 JumpIfNotSmi(r0, on_not_both_smi);
2832}
2833
2834void MacroAssembler::UntagAndJumpIfSmi(Register dst, Register src,
2835 Label* smi_case) {
2836 STATIC_ASSERT(kSmiTag == 0);
2837 STATIC_ASSERT(kSmiTagSize == 1);
2838 // this won't work if src == dst
2839 DCHECK(src.code() != dst.code());
2840 SmiUntag(dst, src);
2841 TestIfSmi(src);
2842 beq(smi_case);
2843}
2844
2845void MacroAssembler::UntagAndJumpIfNotSmi(Register dst, Register src,
2846 Label* non_smi_case) {
2847 STATIC_ASSERT(kSmiTag == 0);
2848 STATIC_ASSERT(kSmiTagSize == 1);
2849
2850 // We can more optimally use TestIfSmi if dst != src
2851 // otherwise, the UnTag operation will kill the CC and we cannot
2852 // test the Tag bit.
2853 if (src.code() != dst.code()) {
2854 SmiUntag(dst, src);
2855 TestIfSmi(src);
2856 } else {
2857 TestBit(src, 0, r0);
2858 SmiUntag(dst, src);
2859 LoadAndTestRR(r0, r0);
2860 }
2861 bne(non_smi_case);
2862}
2863
2864void MacroAssembler::JumpIfEitherSmi(Register reg1, Register reg2,
2865 Label* on_either_smi) {
2866 STATIC_ASSERT(kSmiTag == 0);
2867 JumpIfSmi(reg1, on_either_smi);
2868 JumpIfSmi(reg2, on_either_smi);
2869}
2870
2871void MacroAssembler::AssertNotNumber(Register object) {
2872 if (emit_debug_code()) {
2873 STATIC_ASSERT(kSmiTag == 0);
2874 TestIfSmi(object);
2875 Check(ne, kOperandIsANumber, cr0);
2876 push(object);
2877 CompareObjectType(object, object, object, HEAP_NUMBER_TYPE);
2878 pop(object);
2879 Check(ne, kOperandIsANumber);
2880 }
2881}
2882
2883void MacroAssembler::AssertNotSmi(Register object) {
2884 if (emit_debug_code()) {
2885 STATIC_ASSERT(kSmiTag == 0);
2886 TestIfSmi(object);
2887 Check(ne, kOperandIsASmi, cr0);
2888 }
2889}
2890
2891void MacroAssembler::AssertSmi(Register object) {
2892 if (emit_debug_code()) {
2893 STATIC_ASSERT(kSmiTag == 0);
2894 TestIfSmi(object);
2895 Check(eq, kOperandIsNotSmi, cr0);
2896 }
2897}
2898
2899void MacroAssembler::AssertString(Register object) {
2900 if (emit_debug_code()) {
2901 STATIC_ASSERT(kSmiTag == 0);
2902 TestIfSmi(object);
2903 Check(ne, kOperandIsASmiAndNotAString, cr0);
2904 push(object);
2905 LoadP(object, FieldMemOperand(object, HeapObject::kMapOffset));
2906 CompareInstanceType(object, object, FIRST_NONSTRING_TYPE);
2907 pop(object);
2908 Check(lt, kOperandIsNotAString);
2909 }
2910}
2911
2912void MacroAssembler::AssertName(Register object) {
2913 if (emit_debug_code()) {
2914 STATIC_ASSERT(kSmiTag == 0);
2915 TestIfSmi(object);
2916 Check(ne, kOperandIsASmiAndNotAName, cr0);
2917 push(object);
2918 LoadP(object, FieldMemOperand(object, HeapObject::kMapOffset));
2919 CompareInstanceType(object, object, LAST_NAME_TYPE);
2920 pop(object);
2921 Check(le, kOperandIsNotAName);
2922 }
2923}
2924
2925void MacroAssembler::AssertFunction(Register object) {
2926 if (emit_debug_code()) {
2927 STATIC_ASSERT(kSmiTag == 0);
2928 TestIfSmi(object);
2929 Check(ne, kOperandIsASmiAndNotAFunction, cr0);
2930 push(object);
2931 CompareObjectType(object, object, object, JS_FUNCTION_TYPE);
2932 pop(object);
2933 Check(eq, kOperandIsNotAFunction);
2934 }
2935}
2936
2937void MacroAssembler::AssertBoundFunction(Register object) {
2938 if (emit_debug_code()) {
2939 STATIC_ASSERT(kSmiTag == 0);
2940 TestIfSmi(object);
2941 Check(ne, kOperandIsASmiAndNotABoundFunction, cr0);
2942 push(object);
2943 CompareObjectType(object, object, object, JS_BOUND_FUNCTION_TYPE);
2944 pop(object);
2945 Check(eq, kOperandIsNotABoundFunction);
2946 }
2947}
2948
Ben Murdochc5610432016-08-08 18:44:38 +01002949void MacroAssembler::AssertGeneratorObject(Register object) {
2950 if (emit_debug_code()) {
2951 STATIC_ASSERT(kSmiTag == 0);
2952 TestIfSmi(object);
2953 Check(ne, kOperandIsASmiAndNotAGeneratorObject, cr0);
2954 push(object);
2955 CompareObjectType(object, object, object, JS_GENERATOR_OBJECT_TYPE);
2956 pop(object);
2957 Check(eq, kOperandIsNotAGeneratorObject);
2958 }
2959}
2960
Ben Murdochda12d292016-06-02 14:46:10 +01002961void MacroAssembler::AssertReceiver(Register object) {
2962 if (emit_debug_code()) {
2963 STATIC_ASSERT(kSmiTag == 0);
2964 TestIfSmi(object);
2965 Check(ne, kOperandIsASmiAndNotAReceiver, cr0);
2966 push(object);
2967 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
2968 CompareObjectType(object, object, object, FIRST_JS_RECEIVER_TYPE);
2969 pop(object);
2970 Check(ge, kOperandIsNotAReceiver);
2971 }
2972}
2973
2974void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
2975 Register scratch) {
2976 if (emit_debug_code()) {
2977 Label done_checking;
2978 AssertNotSmi(object);
2979 CompareRoot(object, Heap::kUndefinedValueRootIndex);
2980 beq(&done_checking, Label::kNear);
2981 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
2982 CompareRoot(scratch, Heap::kAllocationSiteMapRootIndex);
2983 Assert(eq, kExpectedUndefinedOrCell);
2984 bind(&done_checking);
2985 }
2986}
2987
2988void MacroAssembler::AssertIsRoot(Register reg, Heap::RootListIndex index) {
2989 if (emit_debug_code()) {
2990 CompareRoot(reg, index);
2991 Check(eq, kHeapNumberMapRegisterClobbered);
2992 }
2993}
2994
2995void MacroAssembler::JumpIfNotHeapNumber(Register object,
2996 Register heap_number_map,
2997 Register scratch,
2998 Label* on_not_heap_number) {
2999 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
3000 AssertIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
3001 CmpP(scratch, heap_number_map);
3002 bne(on_not_heap_number);
3003}
3004
3005void MacroAssembler::JumpIfNonSmisNotBothSequentialOneByteStrings(
3006 Register first, Register second, Register scratch1, Register scratch2,
3007 Label* failure) {
3008 // Test that both first and second are sequential one-byte strings.
3009 // Assume that they are non-smis.
3010 LoadP(scratch1, FieldMemOperand(first, HeapObject::kMapOffset));
3011 LoadP(scratch2, FieldMemOperand(second, HeapObject::kMapOffset));
3012 LoadlB(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
3013 LoadlB(scratch2, FieldMemOperand(scratch2, Map::kInstanceTypeOffset));
3014
3015 JumpIfBothInstanceTypesAreNotSequentialOneByte(scratch1, scratch2, scratch1,
3016 scratch2, failure);
3017}
3018
3019void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register first,
3020 Register second,
3021 Register scratch1,
3022 Register scratch2,
3023 Label* failure) {
3024 // Check that neither is a smi.
3025 AndP(scratch1, first, second);
3026 JumpIfSmi(scratch1, failure);
3027 JumpIfNonSmisNotBothSequentialOneByteStrings(first, second, scratch1,
3028 scratch2, failure);
3029}
3030
3031void MacroAssembler::JumpIfNotUniqueNameInstanceType(Register reg,
3032 Label* not_unique_name) {
3033 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
3034 Label succeed;
3035 AndP(r0, reg, Operand(kIsNotStringMask | kIsNotInternalizedMask));
3036 beq(&succeed, Label::kNear);
3037 CmpP(reg, Operand(SYMBOL_TYPE));
3038 bne(not_unique_name);
3039
3040 bind(&succeed);
3041}
3042
3043// Allocates a heap number or jumps to the need_gc label if the young space
3044// is full and a scavenge is needed.
3045void MacroAssembler::AllocateHeapNumber(Register result, Register scratch1,
3046 Register scratch2,
3047 Register heap_number_map,
3048 Label* gc_required,
Ben Murdochda12d292016-06-02 14:46:10 +01003049 MutableMode mode) {
3050 // Allocate an object in the heap for the heap number and tag it as a heap
3051 // object.
3052 Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required,
Ben Murdochc5610432016-08-08 18:44:38 +01003053 NO_ALLOCATION_FLAGS);
Ben Murdochda12d292016-06-02 14:46:10 +01003054
3055 Heap::RootListIndex map_index = mode == MUTABLE
3056 ? Heap::kMutableHeapNumberMapRootIndex
3057 : Heap::kHeapNumberMapRootIndex;
3058 AssertIsRoot(heap_number_map, map_index);
3059
3060 // Store heap number map in the allocated object.
Ben Murdochda12d292016-06-02 14:46:10 +01003061 StoreP(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01003062}
3063
3064void MacroAssembler::AllocateHeapNumberWithValue(
3065 Register result, DoubleRegister value, Register scratch1, Register scratch2,
3066 Register heap_number_map, Label* gc_required) {
3067 AllocateHeapNumber(result, scratch1, scratch2, heap_number_map, gc_required);
3068 StoreDouble(value, FieldMemOperand(result, HeapNumber::kValueOffset));
3069}
3070
3071void MacroAssembler::AllocateJSValue(Register result, Register constructor,
3072 Register value, Register scratch1,
3073 Register scratch2, Label* gc_required) {
3074 DCHECK(!result.is(constructor));
3075 DCHECK(!result.is(scratch1));
3076 DCHECK(!result.is(scratch2));
3077 DCHECK(!result.is(value));
3078
3079 // Allocate JSValue in new space.
Ben Murdochc5610432016-08-08 18:44:38 +01003080 Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required,
3081 NO_ALLOCATION_FLAGS);
Ben Murdochda12d292016-06-02 14:46:10 +01003082
3083 // Initialize the JSValue.
3084 LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2);
3085 StoreP(scratch1, FieldMemOperand(result, HeapObject::kMapOffset), r0);
3086 LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex);
3087 StoreP(scratch1, FieldMemOperand(result, JSObject::kPropertiesOffset), r0);
3088 StoreP(scratch1, FieldMemOperand(result, JSObject::kElementsOffset), r0);
3089 StoreP(value, FieldMemOperand(result, JSValue::kValueOffset), r0);
3090 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
3091}
3092
3093void MacroAssembler::CopyBytes(Register src, Register dst, Register length,
3094 Register scratch) {
3095 Label big_loop, left_bytes, done, fake_call;
3096
3097 DCHECK(!scratch.is(r0));
3098
3099 // big loop moves 256 bytes at a time
3100 bind(&big_loop);
3101 CmpP(length, Operand(static_cast<intptr_t>(0x100)));
3102 blt(&left_bytes);
3103
3104 mvc(MemOperand(dst), MemOperand(src), 0x100);
3105
3106 AddP(src, Operand(static_cast<intptr_t>(0x100)));
3107 AddP(dst, Operand(static_cast<intptr_t>(0x100)));
3108 SubP(length, Operand(static_cast<intptr_t>(0x100)));
3109 b(&big_loop);
3110
3111 bind(&left_bytes);
3112 CmpP(length, Operand::Zero());
3113 beq(&done);
3114
3115 // TODO(john.yan): More optimal version is to use MVC
3116 // Sequence below has some undiagnosed issue.
3117 /*
3118 b(scratch, &fake_call); // use brasl to Save mvc addr to scratch
3119 mvc(MemOperand(dst), MemOperand(src), 1);
3120 bind(&fake_call);
3121 SubP(length, Operand(static_cast<intptr_t>(-1)));
3122 ex(length, MemOperand(scratch)); // execute mvc instr above
3123 AddP(src, length);
3124 AddP(dst, length);
3125 AddP(src, Operand(static_cast<intptr_t>(0x1)));
3126 AddP(dst, Operand(static_cast<intptr_t>(0x1)));
3127 */
3128
3129 mvc(MemOperand(dst), MemOperand(src), 1);
3130 AddP(src, Operand(static_cast<intptr_t>(0x1)));
3131 AddP(dst, Operand(static_cast<intptr_t>(0x1)));
3132 SubP(length, Operand(static_cast<intptr_t>(0x1)));
3133
3134 b(&left_bytes);
3135 bind(&done);
3136}
3137
3138void MacroAssembler::InitializeNFieldsWithFiller(Register current_address,
3139 Register count,
3140 Register filler) {
3141 Label loop;
3142 bind(&loop);
3143 StoreP(filler, MemOperand(current_address));
3144 AddP(current_address, current_address, Operand(kPointerSize));
3145 BranchOnCount(r1, &loop);
3146}
3147
3148void MacroAssembler::InitializeFieldsWithFiller(Register current_address,
3149 Register end_address,
3150 Register filler) {
3151 Label done;
3152 DCHECK(!filler.is(r1));
3153 DCHECK(!current_address.is(r1));
3154 DCHECK(!end_address.is(r1));
3155 SubP(r1, end_address, current_address /*, LeaveOE, SetRC*/);
3156 beq(&done, Label::kNear);
3157 ShiftRightP(r1, r1, Operand(kPointerSizeLog2));
3158 InitializeNFieldsWithFiller(current_address, r1, filler);
3159 bind(&done);
3160}
3161
3162void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialOneByte(
3163 Register first, Register second, Register scratch1, Register scratch2,
3164 Label* failure) {
3165 const int kFlatOneByteStringMask =
3166 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
3167 const int kFlatOneByteStringTag =
3168 kStringTag | kOneByteStringTag | kSeqStringTag;
3169 if (!scratch1.is(first)) LoadRR(scratch1, first);
3170 if (!scratch2.is(second)) LoadRR(scratch2, second);
3171 nilf(scratch1, Operand(kFlatOneByteStringMask));
3172 CmpP(scratch1, Operand(kFlatOneByteStringTag));
3173 bne(failure);
3174 nilf(scratch2, Operand(kFlatOneByteStringMask));
3175 CmpP(scratch2, Operand(kFlatOneByteStringTag));
3176 bne(failure);
3177}
3178
3179void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte(Register type,
3180 Register scratch,
3181 Label* failure) {
3182 const int kFlatOneByteStringMask =
3183 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
3184 const int kFlatOneByteStringTag =
3185 kStringTag | kOneByteStringTag | kSeqStringTag;
3186
3187 if (!scratch.is(type)) LoadRR(scratch, type);
3188 nilf(scratch, Operand(kFlatOneByteStringMask));
3189 CmpP(scratch, Operand(kFlatOneByteStringTag));
3190 bne(failure);
3191}
3192
3193static const int kRegisterPassedArguments = 5;
3194
3195int MacroAssembler::CalculateStackPassedWords(int num_reg_arguments,
3196 int num_double_arguments) {
3197 int stack_passed_words = 0;
3198 if (num_double_arguments > DoubleRegister::kNumRegisters) {
3199 stack_passed_words +=
3200 2 * (num_double_arguments - DoubleRegister::kNumRegisters);
3201 }
3202 // Up to five simple arguments are passed in registers r2..r6
3203 if (num_reg_arguments > kRegisterPassedArguments) {
3204 stack_passed_words += num_reg_arguments - kRegisterPassedArguments;
3205 }
3206 return stack_passed_words;
3207}
3208
3209void MacroAssembler::EmitSeqStringSetCharCheck(Register string, Register index,
3210 Register value,
3211 uint32_t encoding_mask) {
3212 Label is_object;
3213 TestIfSmi(string);
3214 Check(ne, kNonObject, cr0);
3215
3216 LoadP(ip, FieldMemOperand(string, HeapObject::kMapOffset));
3217 LoadlB(ip, FieldMemOperand(ip, Map::kInstanceTypeOffset));
3218
3219 AndP(ip, Operand(kStringRepresentationMask | kStringEncodingMask));
3220 CmpP(ip, Operand(encoding_mask));
3221 Check(eq, kUnexpectedStringType);
3222
3223// The index is assumed to be untagged coming in, tag it to compare with the
3224// string length without using a temp register, it is restored at the end of
3225// this function.
3226#if !V8_TARGET_ARCH_S390X
3227 Label index_tag_ok, index_tag_bad;
3228 JumpIfNotSmiCandidate(index, r0, &index_tag_bad);
3229#endif
3230 SmiTag(index, index);
3231#if !V8_TARGET_ARCH_S390X
3232 b(&index_tag_ok);
3233 bind(&index_tag_bad);
3234 Abort(kIndexIsTooLarge);
3235 bind(&index_tag_ok);
3236#endif
3237
3238 LoadP(ip, FieldMemOperand(string, String::kLengthOffset));
3239 CmpP(index, ip);
3240 Check(lt, kIndexIsTooLarge);
3241
3242 DCHECK(Smi::FromInt(0) == 0);
3243 CmpP(index, Operand::Zero());
3244 Check(ge, kIndexIsNegative);
3245
3246 SmiUntag(index, index);
3247}
3248
3249void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
3250 int num_double_arguments,
3251 Register scratch) {
3252 int frame_alignment = ActivationFrameAlignment();
3253 int stack_passed_arguments =
3254 CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
3255 int stack_space = kNumRequiredStackFrameSlots;
3256 if (frame_alignment > kPointerSize) {
3257 // Make stack end at alignment and make room for stack arguments
3258 // -- preserving original value of sp.
3259 LoadRR(scratch, sp);
3260 lay(sp, MemOperand(sp, -(stack_passed_arguments + 1) * kPointerSize));
3261 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
3262 ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
3263 StoreP(scratch, MemOperand(sp, (stack_passed_arguments)*kPointerSize));
3264 } else {
3265 stack_space += stack_passed_arguments;
3266 }
3267 lay(sp, MemOperand(sp, -(stack_space)*kPointerSize));
3268}
3269
3270void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
3271 Register scratch) {
3272 PrepareCallCFunction(num_reg_arguments, 0, scratch);
3273}
3274
3275void MacroAssembler::MovToFloatParameter(DoubleRegister src) { Move(d0, src); }
3276
3277void MacroAssembler::MovToFloatResult(DoubleRegister src) { Move(d0, src); }
3278
3279void MacroAssembler::MovToFloatParameters(DoubleRegister src1,
3280 DoubleRegister src2) {
3281 if (src2.is(d0)) {
3282 DCHECK(!src1.is(d2));
3283 Move(d2, src2);
3284 Move(d0, src1);
3285 } else {
3286 Move(d0, src1);
3287 Move(d2, src2);
3288 }
3289}
3290
3291void MacroAssembler::CallCFunction(ExternalReference function,
3292 int num_reg_arguments,
3293 int num_double_arguments) {
3294 mov(ip, Operand(function));
3295 CallCFunctionHelper(ip, num_reg_arguments, num_double_arguments);
3296}
3297
3298void MacroAssembler::CallCFunction(Register function, int num_reg_arguments,
3299 int num_double_arguments) {
3300 CallCFunctionHelper(function, num_reg_arguments, num_double_arguments);
3301}
3302
3303void MacroAssembler::CallCFunction(ExternalReference function,
3304 int num_arguments) {
3305 CallCFunction(function, num_arguments, 0);
3306}
3307
3308void MacroAssembler::CallCFunction(Register function, int num_arguments) {
3309 CallCFunction(function, num_arguments, 0);
3310}
3311
3312void MacroAssembler::CallCFunctionHelper(Register function,
3313 int num_reg_arguments,
3314 int num_double_arguments) {
3315 DCHECK(has_frame());
3316
3317 // Just call directly. The function called cannot cause a GC, or
3318 // allow preemption, so the return address in the link register
3319 // stays correct.
3320 Register dest = function;
3321 if (ABI_CALL_VIA_IP) {
3322 Move(ip, function);
3323 dest = ip;
3324 }
3325
3326 Call(dest);
3327
3328 int stack_passed_arguments =
3329 CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
3330 int stack_space = kNumRequiredStackFrameSlots + stack_passed_arguments;
3331 if (ActivationFrameAlignment() > kPointerSize) {
3332 // Load the original stack pointer (pre-alignment) from the stack
3333 LoadP(sp, MemOperand(sp, stack_space * kPointerSize));
3334 } else {
3335 la(sp, MemOperand(sp, stack_space * kPointerSize));
3336 }
3337}
3338
3339void MacroAssembler::CheckPageFlag(
3340 Register object,
3341 Register scratch, // scratch may be same register as object
3342 int mask, Condition cc, Label* condition_met) {
3343 DCHECK(cc == ne || cc == eq);
3344 ClearRightImm(scratch, object, Operand(kPageSizeBits));
3345
3346 if (base::bits::IsPowerOfTwo32(mask)) {
3347 // If it's a power of two, we can use Test-Under-Mask Memory-Imm form
3348 // which allows testing of a single byte in memory.
3349 int32_t byte_offset = 4;
3350 uint32_t shifted_mask = mask;
3351 // Determine the byte offset to be tested
3352 if (mask <= 0x80) {
3353 byte_offset = kPointerSize - 1;
3354 } else if (mask < 0x8000) {
3355 byte_offset = kPointerSize - 2;
3356 shifted_mask = mask >> 8;
3357 } else if (mask < 0x800000) {
3358 byte_offset = kPointerSize - 3;
3359 shifted_mask = mask >> 16;
3360 } else {
3361 byte_offset = kPointerSize - 4;
3362 shifted_mask = mask >> 24;
3363 }
3364#if V8_TARGET_LITTLE_ENDIAN
3365 // Reverse the byte_offset if emulating on little endian platform
3366 byte_offset = kPointerSize - byte_offset - 1;
3367#endif
3368 tm(MemOperand(scratch, MemoryChunk::kFlagsOffset + byte_offset),
3369 Operand(shifted_mask));
3370 } else {
3371 LoadP(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset));
3372 AndP(r0, scratch, Operand(mask));
3373 }
3374 // Should be okay to remove rc
3375
3376 if (cc == ne) {
3377 bne(condition_met);
3378 }
3379 if (cc == eq) {
3380 beq(condition_met);
3381 }
3382}
3383
3384void MacroAssembler::JumpIfBlack(Register object, Register scratch0,
3385 Register scratch1, Label* on_black) {
3386 HasColor(object, scratch0, scratch1, on_black, 1, 1); // kBlackBitPattern.
3387 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
3388}
3389
3390void MacroAssembler::HasColor(Register object, Register bitmap_scratch,
3391 Register mask_scratch, Label* has_color,
3392 int first_bit, int second_bit) {
3393 DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, no_reg));
3394
3395 GetMarkBits(object, bitmap_scratch, mask_scratch);
3396
3397 Label other_color, word_boundary;
3398 LoadlW(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
3399 // Test the first bit
3400 AndP(r0, ip, mask_scratch /*, SetRC*/); // Should be okay to remove rc
3401 b(first_bit == 1 ? eq : ne, &other_color, Label::kNear);
3402 // Shift left 1
3403 // May need to load the next cell
3404 sll(mask_scratch, Operand(1) /*, SetRC*/);
3405 LoadAndTest32(mask_scratch, mask_scratch);
3406 beq(&word_boundary, Label::kNear);
3407 // Test the second bit
3408 AndP(r0, ip, mask_scratch /*, SetRC*/); // Should be okay to remove rc
3409 b(second_bit == 1 ? ne : eq, has_color);
3410 b(&other_color, Label::kNear);
3411
3412 bind(&word_boundary);
3413 LoadlW(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize + kIntSize));
3414 AndP(r0, ip, Operand(1));
3415 b(second_bit == 1 ? ne : eq, has_color);
3416 bind(&other_color);
3417}
3418
3419void MacroAssembler::GetMarkBits(Register addr_reg, Register bitmap_reg,
3420 Register mask_reg) {
3421 DCHECK(!AreAliased(addr_reg, bitmap_reg, mask_reg, no_reg));
3422 LoadRR(bitmap_reg, addr_reg);
3423 nilf(bitmap_reg, Operand(~Page::kPageAlignmentMask));
3424 const int kLowBits = kPointerSizeLog2 + Bitmap::kBitsPerCellLog2;
3425 ExtractBitRange(mask_reg, addr_reg, kLowBits - 1, kPointerSizeLog2);
3426 ExtractBitRange(ip, addr_reg, kPageSizeBits - 1, kLowBits);
3427 ShiftLeftP(ip, ip, Operand(Bitmap::kBytesPerCellLog2));
3428 AddP(bitmap_reg, ip);
3429 LoadRR(ip, mask_reg); // Have to do some funky reg shuffling as
3430 // 31-bit shift left clobbers on s390.
3431 LoadImmP(mask_reg, Operand(1));
3432 ShiftLeftP(mask_reg, mask_reg, ip);
3433}
3434
3435void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch,
3436 Register mask_scratch, Register load_scratch,
3437 Label* value_is_white) {
3438 DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, ip));
3439 GetMarkBits(value, bitmap_scratch, mask_scratch);
3440
3441 // If the value is black or grey we don't need to do anything.
3442 DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0);
3443 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
3444 DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0);
3445 DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
3446
3447 // Since both black and grey have a 1 in the first position and white does
3448 // not have a 1 there we only need to check one bit.
3449 LoadlW(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
3450 LoadRR(r0, load_scratch);
3451 AndP(r0, mask_scratch);
3452 beq(value_is_white);
3453}
3454
3455// Saturate a value into 8-bit unsigned integer
3456// if input_value < 0, output_value is 0
3457// if input_value > 255, output_value is 255
3458// otherwise output_value is the input_value
3459void MacroAssembler::ClampUint8(Register output_reg, Register input_reg) {
3460 int satval = (1 << 8) - 1;
3461
3462 Label done, negative_label, overflow_label;
3463 CmpP(input_reg, Operand::Zero());
3464 blt(&negative_label);
3465
3466 CmpP(input_reg, Operand(satval));
3467 bgt(&overflow_label);
3468 if (!output_reg.is(input_reg)) {
3469 LoadRR(output_reg, input_reg);
3470 }
3471 b(&done);
3472
3473 bind(&negative_label);
3474 LoadImmP(output_reg, Operand::Zero()); // set to 0 if negative
3475 b(&done);
3476
3477 bind(&overflow_label); // set to satval if > satval
3478 LoadImmP(output_reg, Operand(satval));
3479
3480 bind(&done);
3481}
3482
3483void MacroAssembler::ClampDoubleToUint8(Register result_reg,
3484 DoubleRegister input_reg,
3485 DoubleRegister double_scratch) {
3486 Label above_zero;
3487 Label done;
3488 Label in_bounds;
3489
3490 LoadDoubleLiteral(double_scratch, 0.0, result_reg);
3491 cdbr(input_reg, double_scratch);
3492 bgt(&above_zero, Label::kNear);
3493
3494 // Double value is less than zero, NaN or Inf, return 0.
3495 LoadIntLiteral(result_reg, 0);
3496 b(&done, Label::kNear);
3497
3498 // Double value is >= 255, return 255.
3499 bind(&above_zero);
3500 LoadDoubleLiteral(double_scratch, 255.0, result_reg);
3501 cdbr(input_reg, double_scratch);
3502 ble(&in_bounds, Label::kNear);
3503 LoadIntLiteral(result_reg, 255);
3504 b(&done, Label::kNear);
3505
3506 // In 0-255 range, round and truncate.
3507 bind(&in_bounds);
3508
3509 // round to nearest (default rounding mode)
3510 cfdbr(ROUND_TO_NEAREST_WITH_TIES_TO_EVEN, result_reg, input_reg);
3511 bind(&done);
3512}
3513
3514void MacroAssembler::LoadInstanceDescriptors(Register map,
3515 Register descriptors) {
3516 LoadP(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset));
3517}
3518
3519void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) {
3520 LoadlW(dst, FieldMemOperand(map, Map::kBitField3Offset));
3521 DecodeField<Map::NumberOfOwnDescriptorsBits>(dst);
3522}
3523
3524void MacroAssembler::EnumLength(Register dst, Register map) {
3525 STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
3526 LoadW(dst, FieldMemOperand(map, Map::kBitField3Offset));
3527 And(dst, Operand(Map::EnumLengthBits::kMask));
3528 SmiTag(dst);
3529}
3530
3531void MacroAssembler::LoadAccessor(Register dst, Register holder,
3532 int accessor_index,
3533 AccessorComponent accessor) {
3534 LoadP(dst, FieldMemOperand(holder, HeapObject::kMapOffset));
3535 LoadInstanceDescriptors(dst, dst);
3536 LoadP(dst,
3537 FieldMemOperand(dst, DescriptorArray::GetValueOffset(accessor_index)));
3538 const int getterOffset = AccessorPair::kGetterOffset;
3539 const int setterOffset = AccessorPair::kSetterOffset;
3540 int offset = ((accessor == ACCESSOR_GETTER) ? getterOffset : setterOffset);
3541 LoadP(dst, FieldMemOperand(dst, offset));
3542}
3543
3544void MacroAssembler::CheckEnumCache(Label* call_runtime) {
3545 Register null_value = r7;
3546 Register empty_fixed_array_value = r8;
3547 LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
3548 Label next, start;
3549 LoadRR(r4, r2);
3550
3551 // Check if the enum length field is properly initialized, indicating that
3552 // there is an enum cache.
3553 LoadP(r3, FieldMemOperand(r4, HeapObject::kMapOffset));
3554
3555 EnumLength(r5, r3);
3556 CmpSmiLiteral(r5, Smi::FromInt(kInvalidEnumCacheSentinel), r0);
3557 beq(call_runtime);
3558
3559 LoadRoot(null_value, Heap::kNullValueRootIndex);
3560 b(&start, Label::kNear);
3561
3562 bind(&next);
3563 LoadP(r3, FieldMemOperand(r4, HeapObject::kMapOffset));
3564
3565 // For all objects but the receiver, check that the cache is empty.
3566 EnumLength(r5, r3);
3567 CmpSmiLiteral(r5, Smi::FromInt(0), r0);
3568 bne(call_runtime);
3569
3570 bind(&start);
3571
3572 // Check that there are no elements. Register r4 contains the current JS
3573 // object we've reached through the prototype chain.
3574 Label no_elements;
3575 LoadP(r4, FieldMemOperand(r4, JSObject::kElementsOffset));
3576 CmpP(r4, empty_fixed_array_value);
3577 beq(&no_elements, Label::kNear);
3578
3579 // Second chance, the object may be using the empty slow element dictionary.
3580 CompareRoot(r5, Heap::kEmptySlowElementDictionaryRootIndex);
3581 bne(call_runtime);
3582
3583 bind(&no_elements);
3584 LoadP(r4, FieldMemOperand(r3, Map::kPrototypeOffset));
3585 CmpP(r4, null_value);
3586 bne(&next);
3587}
3588
3589////////////////////////////////////////////////////////////////////////////////
3590//
3591// New MacroAssembler Interfaces added for S390
3592//
3593////////////////////////////////////////////////////////////////////////////////
3594// Primarily used for loading constants
3595// This should really move to be in macro-assembler as it
3596// is really a pseudo instruction
3597// Some usages of this intend for a FIXED_SEQUENCE to be used
3598// @TODO - break this dependency so we can optimize mov() in general
3599// and only use the generic version when we require a fixed sequence
3600void MacroAssembler::LoadRepresentation(Register dst, const MemOperand& mem,
3601 Representation r, Register scratch) {
3602 DCHECK(!r.IsDouble());
3603 if (r.IsInteger8()) {
3604 LoadB(dst, mem);
3605 lgbr(dst, dst);
3606 } else if (r.IsUInteger8()) {
3607 LoadlB(dst, mem);
3608 } else if (r.IsInteger16()) {
3609 LoadHalfWordP(dst, mem, scratch);
3610 lghr(dst, dst);
3611 } else if (r.IsUInteger16()) {
3612 LoadHalfWordP(dst, mem, scratch);
3613#if V8_TARGET_ARCH_S390X
3614 } else if (r.IsInteger32()) {
3615 LoadW(dst, mem, scratch);
3616#endif
3617 } else {
3618 LoadP(dst, mem, scratch);
3619 }
3620}
3621
3622void MacroAssembler::StoreRepresentation(Register src, const MemOperand& mem,
3623 Representation r, Register scratch) {
3624 DCHECK(!r.IsDouble());
3625 if (r.IsInteger8() || r.IsUInteger8()) {
3626 StoreByte(src, mem, scratch);
3627 } else if (r.IsInteger16() || r.IsUInteger16()) {
3628 StoreHalfWord(src, mem, scratch);
3629#if V8_TARGET_ARCH_S390X
3630 } else if (r.IsInteger32()) {
3631 StoreW(src, mem, scratch);
3632#endif
3633 } else {
3634 if (r.IsHeapObject()) {
3635 AssertNotSmi(src);
3636 } else if (r.IsSmi()) {
3637 AssertSmi(src);
3638 }
3639 StoreP(src, mem, scratch);
3640 }
3641}
3642
3643void MacroAssembler::TestJSArrayForAllocationMemento(Register receiver_reg,
3644 Register scratch_reg,
3645 Register scratch2_reg,
3646 Label* no_memento_found) {
3647 Label map_check;
3648 Label top_check;
Ben Murdochc5610432016-08-08 18:44:38 +01003649 ExternalReference new_space_allocation_top_adr =
Ben Murdochda12d292016-06-02 14:46:10 +01003650 ExternalReference::new_space_allocation_top_address(isolate());
3651 const int kMementoMapOffset = JSArray::kSize - kHeapObjectTag;
3652 const int kMementoEndOffset = kMementoMapOffset + AllocationMemento::kSize;
3653
3654 DCHECK(!AreAliased(receiver_reg, scratch_reg));
3655
3656 // Bail out if the object is not in new space.
3657 JumpIfNotInNewSpace(receiver_reg, scratch_reg, no_memento_found);
3658
3659 DCHECK((~Page::kPageAlignmentMask & 0xffff) == 0);
Ben Murdochda12d292016-06-02 14:46:10 +01003660
3661 // If the object is in new space, we need to check whether it is on the same
3662 // page as the current top.
Ben Murdochc5610432016-08-08 18:44:38 +01003663 AddP(scratch_reg, receiver_reg, Operand(kMementoEndOffset));
3664 mov(ip, Operand(new_space_allocation_top_adr));
3665 LoadP(ip, MemOperand(ip));
3666 XorP(r0, scratch_reg, ip);
Ben Murdochda12d292016-06-02 14:46:10 +01003667 AndP(r0, r0, Operand(~Page::kPageAlignmentMask));
3668 beq(&top_check, Label::kNear);
3669 // The object is on a different page than allocation top. Bail out if the
3670 // object sits on the page boundary as no memento can follow and we cannot
3671 // touch the memory following it.
3672 XorP(r0, scratch_reg, receiver_reg);
3673 AndP(r0, r0, Operand(~Page::kPageAlignmentMask));
3674 bne(no_memento_found);
3675 // Continue with the actual map check.
3676 b(&map_check, Label::kNear);
3677 // If top is on the same page as the current object, we need to check whether
3678 // we are below top.
3679 bind(&top_check);
Ben Murdochc5610432016-08-08 18:44:38 +01003680 CmpP(scratch_reg, ip);
Ben Murdochda12d292016-06-02 14:46:10 +01003681 bgt(no_memento_found);
3682 // Memento map check.
3683 bind(&map_check);
3684 LoadP(scratch_reg, MemOperand(receiver_reg, kMementoMapOffset));
3685 CmpP(scratch_reg, Operand(isolate()->factory()->allocation_memento_map()));
3686}
3687
3688Register GetRegisterThatIsNotOneOf(Register reg1, Register reg2, Register reg3,
3689 Register reg4, Register reg5,
3690 Register reg6) {
3691 RegList regs = 0;
3692 if (reg1.is_valid()) regs |= reg1.bit();
3693 if (reg2.is_valid()) regs |= reg2.bit();
3694 if (reg3.is_valid()) regs |= reg3.bit();
3695 if (reg4.is_valid()) regs |= reg4.bit();
3696 if (reg5.is_valid()) regs |= reg5.bit();
3697 if (reg6.is_valid()) regs |= reg6.bit();
3698
Ben Murdoch61f157c2016-09-16 13:49:30 +01003699 const RegisterConfiguration* config = RegisterConfiguration::Crankshaft();
Ben Murdochda12d292016-06-02 14:46:10 +01003700 for (int i = 0; i < config->num_allocatable_general_registers(); ++i) {
3701 int code = config->GetAllocatableGeneralCode(i);
3702 Register candidate = Register::from_code(code);
3703 if (regs & candidate.bit()) continue;
3704 return candidate;
3705 }
3706 UNREACHABLE();
3707 return no_reg;
3708}
3709
3710void MacroAssembler::JumpIfDictionaryInPrototypeChain(Register object,
3711 Register scratch0,
3712 Register scratch1,
3713 Label* found) {
3714 DCHECK(!scratch1.is(scratch0));
3715 Register current = scratch0;
3716 Label loop_again, end;
3717
3718 // scratch contained elements pointer.
3719 LoadRR(current, object);
3720 LoadP(current, FieldMemOperand(current, HeapObject::kMapOffset));
3721 LoadP(current, FieldMemOperand(current, Map::kPrototypeOffset));
3722 CompareRoot(current, Heap::kNullValueRootIndex);
3723 beq(&end);
3724
3725 // Loop based on the map going up the prototype chain.
3726 bind(&loop_again);
3727 LoadP(current, FieldMemOperand(current, HeapObject::kMapOffset));
3728
3729 STATIC_ASSERT(JS_PROXY_TYPE < JS_OBJECT_TYPE);
3730 STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE);
3731 LoadlB(scratch1, FieldMemOperand(current, Map::kInstanceTypeOffset));
3732 CmpP(scratch1, Operand(JS_OBJECT_TYPE));
3733 blt(found);
3734
3735 LoadlB(scratch1, FieldMemOperand(current, Map::kBitField2Offset));
3736 DecodeField<Map::ElementsKindBits>(scratch1);
3737 CmpP(scratch1, Operand(DICTIONARY_ELEMENTS));
3738 beq(found);
3739 LoadP(current, FieldMemOperand(current, Map::kPrototypeOffset));
3740 CompareRoot(current, Heap::kNullValueRootIndex);
3741 bne(&loop_again);
3742
3743 bind(&end);
3744}
3745
3746void MacroAssembler::mov(Register dst, const Operand& src) {
3747 if (src.rmode_ != kRelocInfo_NONEPTR) {
3748 // some form of relocation needed
3749 RecordRelocInfo(src.rmode_, src.imm_);
3750 }
3751
3752#if V8_TARGET_ARCH_S390X
3753 int64_t value = src.immediate();
3754 int32_t hi_32 = static_cast<int64_t>(value) >> 32;
3755 int32_t lo_32 = static_cast<int32_t>(value);
3756
3757 iihf(dst, Operand(hi_32));
3758 iilf(dst, Operand(lo_32));
3759#else
3760 int value = src.immediate();
3761 iilf(dst, Operand(value));
3762#endif
3763}
3764
3765void MacroAssembler::Mul(Register dst, Register src1, Register src2) {
3766 if (dst.is(src2)) {
3767 MulP(dst, src1);
3768 } else if (dst.is(src1)) {
3769 MulP(dst, src2);
3770 } else {
3771 Move(dst, src1);
3772 MulP(dst, src2);
3773 }
3774}
3775
3776void MacroAssembler::DivP(Register dividend, Register divider) {
3777 // have to make sure the src and dst are reg pairs
3778 DCHECK(dividend.code() % 2 == 0);
3779#if V8_TARGET_ARCH_S390X
3780 dsgr(dividend, divider);
3781#else
3782 dr(dividend, divider);
3783#endif
3784}
3785
3786void MacroAssembler::MulP(Register dst, const Operand& opnd) {
3787#if V8_TARGET_ARCH_S390X
3788 msgfi(dst, opnd);
3789#else
3790 msfi(dst, opnd);
3791#endif
3792}
3793
3794void MacroAssembler::MulP(Register dst, Register src) {
3795#if V8_TARGET_ARCH_S390X
3796 msgr(dst, src);
3797#else
3798 msr(dst, src);
3799#endif
3800}
3801
3802void MacroAssembler::MulP(Register dst, const MemOperand& opnd) {
3803#if V8_TARGET_ARCH_S390X
3804 if (is_uint16(opnd.offset())) {
3805 ms(dst, opnd);
3806 } else if (is_int20(opnd.offset())) {
3807 msy(dst, opnd);
3808 } else {
3809 UNIMPLEMENTED();
3810 }
3811#else
3812 if (is_int20(opnd.offset())) {
3813 msg(dst, opnd);
3814 } else {
3815 UNIMPLEMENTED();
3816 }
3817#endif
3818}
3819
3820//----------------------------------------------------------------------------
3821// Add Instructions
3822//----------------------------------------------------------------------------
3823
3824// Add 32-bit (Register dst = Register dst + Immediate opnd)
3825void MacroAssembler::Add32(Register dst, const Operand& opnd) {
3826 if (is_int16(opnd.immediate()))
3827 ahi(dst, opnd);
3828 else
3829 afi(dst, opnd);
3830}
3831
3832// Add Pointer Size (Register dst = Register dst + Immediate opnd)
3833void MacroAssembler::AddP(Register dst, const Operand& opnd) {
3834#if V8_TARGET_ARCH_S390X
3835 if (is_int16(opnd.immediate()))
3836 aghi(dst, opnd);
3837 else
3838 agfi(dst, opnd);
3839#else
3840 Add32(dst, opnd);
3841#endif
3842}
3843
3844// Add 32-bit (Register dst = Register src + Immediate opnd)
3845void MacroAssembler::Add32(Register dst, Register src, const Operand& opnd) {
3846 if (!dst.is(src)) {
3847 if (CpuFeatures::IsSupported(DISTINCT_OPS) && is_int16(opnd.immediate())) {
3848 ahik(dst, src, opnd);
3849 return;
3850 }
3851 lr(dst, src);
3852 }
3853 Add32(dst, opnd);
3854}
3855
3856// Add Pointer Size (Register dst = Register src + Immediate opnd)
3857void MacroAssembler::AddP(Register dst, Register src, const Operand& opnd) {
3858 if (!dst.is(src)) {
3859 if (CpuFeatures::IsSupported(DISTINCT_OPS) && is_int16(opnd.immediate())) {
3860 AddPImm_RRI(dst, src, opnd);
3861 return;
3862 }
3863 LoadRR(dst, src);
3864 }
3865 AddP(dst, opnd);
3866}
3867
3868// Add 32-bit (Register dst = Register dst + Register src)
3869void MacroAssembler::Add32(Register dst, Register src) { ar(dst, src); }
3870
3871// Add Pointer Size (Register dst = Register dst + Register src)
3872void MacroAssembler::AddP(Register dst, Register src) { AddRR(dst, src); }
3873
3874// Add Pointer Size with src extension
3875// (Register dst(ptr) = Register dst (ptr) + Register src (32 | 32->64))
3876// src is treated as a 32-bit signed integer, which is sign extended to
3877// 64-bit if necessary.
3878void MacroAssembler::AddP_ExtendSrc(Register dst, Register src) {
3879#if V8_TARGET_ARCH_S390X
3880 agfr(dst, src);
3881#else
3882 ar(dst, src);
3883#endif
3884}
3885
3886// Add 32-bit (Register dst = Register src1 + Register src2)
3887void MacroAssembler::Add32(Register dst, Register src1, Register src2) {
3888 if (!dst.is(src1) && !dst.is(src2)) {
3889 // We prefer to generate AR/AGR, over the non clobbering ARK/AGRK
3890 // as AR is a smaller instruction
3891 if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
3892 ark(dst, src1, src2);
3893 return;
3894 } else {
3895 lr(dst, src1);
3896 }
3897 } else if (dst.is(src2)) {
3898 src2 = src1;
3899 }
3900 ar(dst, src2);
3901}
3902
3903// Add Pointer Size (Register dst = Register src1 + Register src2)
3904void MacroAssembler::AddP(Register dst, Register src1, Register src2) {
3905 if (!dst.is(src1) && !dst.is(src2)) {
3906 // We prefer to generate AR/AGR, over the non clobbering ARK/AGRK
3907 // as AR is a smaller instruction
3908 if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
3909 AddP_RRR(dst, src1, src2);
3910 return;
3911 } else {
3912 LoadRR(dst, src1);
3913 }
3914 } else if (dst.is(src2)) {
3915 src2 = src1;
3916 }
3917 AddRR(dst, src2);
3918}
3919
3920// Add Pointer Size with src extension
3921// (Register dst (ptr) = Register dst (ptr) + Register src1 (ptr) +
3922// Register src2 (32 | 32->64))
3923// src is treated as a 32-bit signed integer, which is sign extended to
3924// 64-bit if necessary.
3925void MacroAssembler::AddP_ExtendSrc(Register dst, Register src1,
3926 Register src2) {
3927#if V8_TARGET_ARCH_S390X
3928 if (dst.is(src2)) {
3929 // The source we need to sign extend is the same as result.
3930 lgfr(dst, src2);
3931 agr(dst, src1);
3932 } else {
3933 if (!dst.is(src1)) LoadRR(dst, src1);
3934 agfr(dst, src2);
3935 }
3936#else
3937 AddP(dst, src1, src2);
3938#endif
3939}
3940
3941// Add 32-bit (Register-Memory)
3942void MacroAssembler::Add32(Register dst, const MemOperand& opnd) {
3943 DCHECK(is_int20(opnd.offset()));
3944 if (is_uint12(opnd.offset()))
3945 a(dst, opnd);
3946 else
3947 ay(dst, opnd);
3948}
3949
3950// Add Pointer Size (Register-Memory)
3951void MacroAssembler::AddP(Register dst, const MemOperand& opnd) {
3952#if V8_TARGET_ARCH_S390X
3953 DCHECK(is_int20(opnd.offset()));
3954 ag(dst, opnd);
3955#else
3956 Add32(dst, opnd);
3957#endif
3958}
3959
3960// Add Pointer Size with src extension
3961// (Register dst (ptr) = Register dst (ptr) + Mem opnd (32 | 32->64))
3962// src is treated as a 32-bit signed integer, which is sign extended to
3963// 64-bit if necessary.
3964void MacroAssembler::AddP_ExtendSrc(Register dst, const MemOperand& opnd) {
3965#if V8_TARGET_ARCH_S390X
3966 DCHECK(is_int20(opnd.offset()));
3967 agf(dst, opnd);
3968#else
3969 Add32(dst, opnd);
3970#endif
3971}
3972
3973// Add 32-bit (Memory - Immediate)
3974void MacroAssembler::Add32(const MemOperand& opnd, const Operand& imm) {
3975 DCHECK(is_int8(imm.immediate()));
3976 DCHECK(is_int20(opnd.offset()));
3977 DCHECK(CpuFeatures::IsSupported(GENERAL_INSTR_EXT));
3978 asi(opnd, imm);
3979}
3980
3981// Add Pointer-sized (Memory - Immediate)
3982void MacroAssembler::AddP(const MemOperand& opnd, const Operand& imm) {
3983 DCHECK(is_int8(imm.immediate()));
3984 DCHECK(is_int20(opnd.offset()));
3985 DCHECK(CpuFeatures::IsSupported(GENERAL_INSTR_EXT));
3986#if V8_TARGET_ARCH_S390X
3987 agsi(opnd, imm);
3988#else
3989 asi(opnd, imm);
3990#endif
3991}
3992
3993//----------------------------------------------------------------------------
3994// Add Logical Instructions
3995//----------------------------------------------------------------------------
3996
3997// Add Logical With Carry 32-bit (Register dst = Register src1 + Register src2)
3998void MacroAssembler::AddLogicalWithCarry32(Register dst, Register src1,
3999 Register src2) {
4000 if (!dst.is(src2) && !dst.is(src1)) {
4001 lr(dst, src1);
4002 alcr(dst, src2);
4003 } else if (!dst.is(src2)) {
4004 // dst == src1
4005 DCHECK(dst.is(src1));
4006 alcr(dst, src2);
4007 } else {
4008 // dst == src2
4009 DCHECK(dst.is(src2));
4010 alcr(dst, src1);
4011 }
4012}
4013
4014// Add Logical 32-bit (Register dst = Register src1 + Register src2)
4015void MacroAssembler::AddLogical32(Register dst, Register src1, Register src2) {
4016 if (!dst.is(src2) && !dst.is(src1)) {
4017 lr(dst, src1);
4018 alr(dst, src2);
4019 } else if (!dst.is(src2)) {
4020 // dst == src1
4021 DCHECK(dst.is(src1));
4022 alr(dst, src2);
4023 } else {
4024 // dst == src2
4025 DCHECK(dst.is(src2));
4026 alr(dst, src1);
4027 }
4028}
4029
4030// Add Logical 32-bit (Register dst = Register dst + Immediate opnd)
4031void MacroAssembler::AddLogical(Register dst, const Operand& imm) {
4032 alfi(dst, imm);
4033}
4034
4035// Add Logical Pointer Size (Register dst = Register dst + Immediate opnd)
4036void MacroAssembler::AddLogicalP(Register dst, const Operand& imm) {
4037#ifdef V8_TARGET_ARCH_S390X
4038 algfi(dst, imm);
4039#else
4040 AddLogical(dst, imm);
4041#endif
4042}
4043
4044// Add Logical 32-bit (Register-Memory)
4045void MacroAssembler::AddLogical(Register dst, const MemOperand& opnd) {
4046 DCHECK(is_int20(opnd.offset()));
4047 if (is_uint12(opnd.offset()))
4048 al_z(dst, opnd);
4049 else
4050 aly(dst, opnd);
4051}
4052
4053// Add Logical Pointer Size (Register-Memory)
4054void MacroAssembler::AddLogicalP(Register dst, const MemOperand& opnd) {
4055#if V8_TARGET_ARCH_S390X
4056 DCHECK(is_int20(opnd.offset()));
4057 alg(dst, opnd);
4058#else
4059 AddLogical(dst, opnd);
4060#endif
4061}
4062
4063//----------------------------------------------------------------------------
4064// Subtract Instructions
4065//----------------------------------------------------------------------------
4066
4067// Subtract Logical With Carry 32-bit (Register dst = Register src1 - Register
4068// src2)
4069void MacroAssembler::SubLogicalWithBorrow32(Register dst, Register src1,
4070 Register src2) {
4071 if (!dst.is(src2) && !dst.is(src1)) {
4072 lr(dst, src1);
4073 slbr(dst, src2);
4074 } else if (!dst.is(src2)) {
4075 // dst == src1
4076 DCHECK(dst.is(src1));
4077 slbr(dst, src2);
4078 } else {
4079 // dst == src2
4080 DCHECK(dst.is(src2));
4081 lr(r0, dst);
4082 SubLogicalWithBorrow32(dst, src1, r0);
4083 }
4084}
4085
4086// Subtract Logical 32-bit (Register dst = Register src1 - Register src2)
4087void MacroAssembler::SubLogical32(Register dst, Register src1, Register src2) {
4088 if (!dst.is(src2) && !dst.is(src1)) {
4089 lr(dst, src1);
4090 slr(dst, src2);
4091 } else if (!dst.is(src2)) {
4092 // dst == src1
4093 DCHECK(dst.is(src1));
4094 slr(dst, src2);
4095 } else {
4096 // dst == src2
4097 DCHECK(dst.is(src2));
4098 lr(r0, dst);
4099 SubLogical32(dst, src1, r0);
4100 }
4101}
4102
4103// Subtract 32-bit (Register dst = Register dst - Immediate opnd)
4104void MacroAssembler::Sub32(Register dst, const Operand& imm) {
4105 Add32(dst, Operand(-(imm.imm_)));
4106}
4107
4108// Subtract Pointer Size (Register dst = Register dst - Immediate opnd)
4109void MacroAssembler::SubP(Register dst, const Operand& imm) {
4110 AddP(dst, Operand(-(imm.imm_)));
4111}
4112
4113// Subtract 32-bit (Register dst = Register src - Immediate opnd)
4114void MacroAssembler::Sub32(Register dst, Register src, const Operand& imm) {
4115 Add32(dst, src, Operand(-(imm.imm_)));
4116}
4117
4118// Subtract Pointer Sized (Register dst = Register src - Immediate opnd)
4119void MacroAssembler::SubP(Register dst, Register src, const Operand& imm) {
4120 AddP(dst, src, Operand(-(imm.imm_)));
4121}
4122
4123// Subtract 32-bit (Register dst = Register dst - Register src)
4124void MacroAssembler::Sub32(Register dst, Register src) { sr(dst, src); }
4125
4126// Subtract Pointer Size (Register dst = Register dst - Register src)
4127void MacroAssembler::SubP(Register dst, Register src) { SubRR(dst, src); }
4128
4129// Subtract Pointer Size with src extension
4130// (Register dst(ptr) = Register dst (ptr) - Register src (32 | 32->64))
4131// src is treated as a 32-bit signed integer, which is sign extended to
4132// 64-bit if necessary.
4133void MacroAssembler::SubP_ExtendSrc(Register dst, Register src) {
4134#if V8_TARGET_ARCH_S390X
4135 sgfr(dst, src);
4136#else
4137 sr(dst, src);
4138#endif
4139}
4140
4141// Subtract 32-bit (Register = Register - Register)
4142void MacroAssembler::Sub32(Register dst, Register src1, Register src2) {
4143 // Use non-clobbering version if possible
4144 if (CpuFeatures::IsSupported(DISTINCT_OPS) && !dst.is(src1)) {
4145 srk(dst, src1, src2);
4146 return;
4147 }
4148 if (!dst.is(src1) && !dst.is(src2)) lr(dst, src1);
4149 // In scenario where we have dst = src - dst, we need to swap and negate
4150 if (!dst.is(src1) && dst.is(src2)) {
4151 sr(dst, src1); // dst = (dst - src)
4152 lcr(dst, dst); // dst = -dst
4153 } else {
4154 sr(dst, src2);
4155 }
4156}
4157
4158// Subtract Pointer Sized (Register = Register - Register)
4159void MacroAssembler::SubP(Register dst, Register src1, Register src2) {
4160 // Use non-clobbering version if possible
4161 if (CpuFeatures::IsSupported(DISTINCT_OPS) && !dst.is(src1)) {
4162 SubP_RRR(dst, src1, src2);
4163 return;
4164 }
4165 if (!dst.is(src1) && !dst.is(src2)) LoadRR(dst, src1);
4166 // In scenario where we have dst = src - dst, we need to swap and negate
4167 if (!dst.is(src1) && dst.is(src2)) {
4168 SubP(dst, src1); // dst = (dst - src)
4169 LoadComplementRR(dst, dst); // dst = -dst
4170 } else {
4171 SubP(dst, src2);
4172 }
4173}
4174
4175// Subtract Pointer Size with src extension
4176// (Register dst(ptr) = Register dst (ptr) - Register src (32 | 32->64))
4177// src is treated as a 32-bit signed integer, which is sign extended to
4178// 64-bit if necessary.
4179void MacroAssembler::SubP_ExtendSrc(Register dst, Register src1,
4180 Register src2) {
4181#if V8_TARGET_ARCH_S390X
4182 if (!dst.is(src1) && !dst.is(src2)) LoadRR(dst, src1);
4183
4184 // In scenario where we have dst = src - dst, we need to swap and negate
4185 if (!dst.is(src1) && dst.is(src2)) {
4186 lgfr(dst, dst); // Sign extend this operand first.
4187 SubP(dst, src1); // dst = (dst - src)
4188 LoadComplementRR(dst, dst); // dst = -dst
4189 } else {
4190 sgfr(dst, src2);
4191 }
4192#else
4193 SubP(dst, src1, src2);
4194#endif
4195}
4196
4197// Subtract 32-bit (Register-Memory)
4198void MacroAssembler::Sub32(Register dst, const MemOperand& opnd) {
4199 DCHECK(is_int20(opnd.offset()));
4200 if (is_uint12(opnd.offset()))
4201 s(dst, opnd);
4202 else
4203 sy(dst, opnd);
4204}
4205
4206// Subtract Pointer Sized (Register - Memory)
4207void MacroAssembler::SubP(Register dst, const MemOperand& opnd) {
4208#if V8_TARGET_ARCH_S390X
4209 sg(dst, opnd);
4210#else
4211 Sub32(dst, opnd);
4212#endif
4213}
4214
4215void MacroAssembler::MovIntToFloat(DoubleRegister dst, Register src) {
4216 sllg(src, src, Operand(32));
4217 ldgr(dst, src);
4218}
4219
4220void MacroAssembler::MovFloatToInt(Register dst, DoubleRegister src) {
4221 lgdr(dst, src);
4222 srlg(dst, dst, Operand(32));
4223}
4224
4225void MacroAssembler::SubP_ExtendSrc(Register dst, const MemOperand& opnd) {
4226#if V8_TARGET_ARCH_S390X
4227 DCHECK(is_int20(opnd.offset()));
4228 sgf(dst, opnd);
4229#else
4230 Sub32(dst, opnd);
4231#endif
4232}
4233
4234//----------------------------------------------------------------------------
4235// Subtract Logical Instructions
4236//----------------------------------------------------------------------------
4237
4238// Subtract Logical 32-bit (Register - Memory)
4239void MacroAssembler::SubLogical(Register dst, const MemOperand& opnd) {
4240 DCHECK(is_int20(opnd.offset()));
4241 if (is_uint12(opnd.offset()))
4242 sl(dst, opnd);
4243 else
4244 sly(dst, opnd);
4245}
4246
4247// Subtract Logical Pointer Sized (Register - Memory)
4248void MacroAssembler::SubLogicalP(Register dst, const MemOperand& opnd) {
4249 DCHECK(is_int20(opnd.offset()));
4250#if V8_TARGET_ARCH_S390X
4251 slgf(dst, opnd);
4252#else
4253 SubLogical(dst, opnd);
4254#endif
4255}
4256
4257// Subtract Logical Pointer Size with src extension
4258// (Register dst (ptr) = Register dst (ptr) - Mem opnd (32 | 32->64))
4259// src is treated as a 32-bit signed integer, which is sign extended to
4260// 64-bit if necessary.
4261void MacroAssembler::SubLogicalP_ExtendSrc(Register dst,
4262 const MemOperand& opnd) {
4263#if V8_TARGET_ARCH_S390X
4264 DCHECK(is_int20(opnd.offset()));
4265 slgf(dst, opnd);
4266#else
4267 SubLogical(dst, opnd);
4268#endif
4269}
4270
4271//----------------------------------------------------------------------------
4272// Bitwise Operations
4273//----------------------------------------------------------------------------
4274
4275// AND 32-bit - dst = dst & src
4276void MacroAssembler::And(Register dst, Register src) { nr(dst, src); }
4277
4278// AND Pointer Size - dst = dst & src
4279void MacroAssembler::AndP(Register dst, Register src) { AndRR(dst, src); }
4280
4281// Non-clobbering AND 32-bit - dst = src1 & src1
4282void MacroAssembler::And(Register dst, Register src1, Register src2) {
4283 if (!dst.is(src1) && !dst.is(src2)) {
4284 // We prefer to generate XR/XGR, over the non clobbering XRK/XRK
4285 // as XR is a smaller instruction
4286 if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4287 nrk(dst, src1, src2);
4288 return;
4289 } else {
4290 lr(dst, src1);
4291 }
4292 } else if (dst.is(src2)) {
4293 src2 = src1;
4294 }
4295 And(dst, src2);
4296}
4297
4298// Non-clobbering AND pointer size - dst = src1 & src1
4299void MacroAssembler::AndP(Register dst, Register src1, Register src2) {
4300 if (!dst.is(src1) && !dst.is(src2)) {
4301 // We prefer to generate XR/XGR, over the non clobbering XRK/XRK
4302 // as XR is a smaller instruction
4303 if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4304 AndP_RRR(dst, src1, src2);
4305 return;
4306 } else {
4307 LoadRR(dst, src1);
4308 }
4309 } else if (dst.is(src2)) {
4310 src2 = src1;
4311 }
4312 AndP(dst, src2);
4313}
4314
4315// AND 32-bit (Reg - Mem)
4316void MacroAssembler::And(Register dst, const MemOperand& opnd) {
4317 DCHECK(is_int20(opnd.offset()));
4318 if (is_uint12(opnd.offset()))
4319 n(dst, opnd);
4320 else
4321 ny(dst, opnd);
4322}
4323
4324// AND Pointer Size (Reg - Mem)
4325void MacroAssembler::AndP(Register dst, const MemOperand& opnd) {
4326 DCHECK(is_int20(opnd.offset()));
4327#if V8_TARGET_ARCH_S390X
4328 ng(dst, opnd);
4329#else
4330 And(dst, opnd);
4331#endif
4332}
4333
4334// AND 32-bit - dst = dst & imm
4335void MacroAssembler::And(Register dst, const Operand& opnd) { nilf(dst, opnd); }
4336
4337// AND Pointer Size - dst = dst & imm
4338void MacroAssembler::AndP(Register dst, const Operand& opnd) {
4339#if V8_TARGET_ARCH_S390X
4340 intptr_t value = opnd.imm_;
4341 if (value >> 32 != -1) {
4342 // this may not work b/c condition code won't be set correctly
4343 nihf(dst, Operand(value >> 32));
4344 }
4345 nilf(dst, Operand(value & 0xFFFFFFFF));
4346#else
4347 And(dst, opnd);
4348#endif
4349}
4350
4351// AND 32-bit - dst = src & imm
4352void MacroAssembler::And(Register dst, Register src, const Operand& opnd) {
4353 if (!dst.is(src)) lr(dst, src);
4354 nilf(dst, opnd);
4355}
4356
4357// AND Pointer Size - dst = src & imm
4358void MacroAssembler::AndP(Register dst, Register src, const Operand& opnd) {
4359 // Try to exploit RISBG first
4360 intptr_t value = opnd.imm_;
4361 if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) {
4362 intptr_t shifted_value = value;
4363 int trailing_zeros = 0;
4364
4365 // We start checking how many trailing zeros are left at the end.
4366 while ((0 != shifted_value) && (0 == (shifted_value & 1))) {
4367 trailing_zeros++;
4368 shifted_value >>= 1;
4369 }
4370
4371 // If temp (value with right-most set of zeros shifted out) is 1 less
4372 // than power of 2, we have consecutive bits of 1.
4373 // Special case: If shift_value is zero, we cannot use RISBG, as it requires
4374 // selection of at least 1 bit.
4375 if ((0 != shifted_value) && base::bits::IsPowerOfTwo64(shifted_value + 1)) {
4376 int startBit =
4377 base::bits::CountLeadingZeros64(shifted_value) - trailing_zeros;
4378 int endBit = 63 - trailing_zeros;
4379 // Start: startBit, End: endBit, Shift = 0, true = zero unselected bits.
4380 risbg(dst, src, Operand(startBit), Operand(endBit), Operand::Zero(),
4381 true);
4382 return;
4383 } else if (-1 == shifted_value) {
4384 // A Special case in which all top bits up to MSB are 1's. In this case,
4385 // we can set startBit to be 0.
4386 int endBit = 63 - trailing_zeros;
4387 risbg(dst, src, Operand::Zero(), Operand(endBit), Operand::Zero(), true);
4388 return;
4389 }
4390 }
4391
4392 // If we are &'ing zero, we can just whack the dst register and skip copy
4393 if (!dst.is(src) && (0 != value)) LoadRR(dst, src);
4394 AndP(dst, opnd);
4395}
4396
4397// OR 32-bit - dst = dst & src
4398void MacroAssembler::Or(Register dst, Register src) { or_z(dst, src); }
4399
4400// OR Pointer Size - dst = dst & src
4401void MacroAssembler::OrP(Register dst, Register src) { OrRR(dst, src); }
4402
4403// Non-clobbering OR 32-bit - dst = src1 & src1
4404void MacroAssembler::Or(Register dst, Register src1, Register src2) {
4405 if (!dst.is(src1) && !dst.is(src2)) {
4406 // We prefer to generate XR/XGR, over the non clobbering XRK/XRK
4407 // as XR is a smaller instruction
4408 if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4409 ork(dst, src1, src2);
4410 return;
4411 } else {
4412 lr(dst, src1);
4413 }
4414 } else if (dst.is(src2)) {
4415 src2 = src1;
4416 }
4417 Or(dst, src2);
4418}
4419
4420// Non-clobbering OR pointer size - dst = src1 & src1
4421void MacroAssembler::OrP(Register dst, Register src1, Register src2) {
4422 if (!dst.is(src1) && !dst.is(src2)) {
4423 // We prefer to generate XR/XGR, over the non clobbering XRK/XRK
4424 // as XR is a smaller instruction
4425 if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4426 OrP_RRR(dst, src1, src2);
4427 return;
4428 } else {
4429 LoadRR(dst, src1);
4430 }
4431 } else if (dst.is(src2)) {
4432 src2 = src1;
4433 }
4434 OrP(dst, src2);
4435}
4436
4437// OR 32-bit (Reg - Mem)
4438void MacroAssembler::Or(Register dst, const MemOperand& opnd) {
4439 DCHECK(is_int20(opnd.offset()));
4440 if (is_uint12(opnd.offset()))
4441 o(dst, opnd);
4442 else
4443 oy(dst, opnd);
4444}
4445
4446// OR Pointer Size (Reg - Mem)
4447void MacroAssembler::OrP(Register dst, const MemOperand& opnd) {
4448 DCHECK(is_int20(opnd.offset()));
4449#if V8_TARGET_ARCH_S390X
4450 og(dst, opnd);
4451#else
4452 Or(dst, opnd);
4453#endif
4454}
4455
4456// OR 32-bit - dst = dst & imm
4457void MacroAssembler::Or(Register dst, const Operand& opnd) { oilf(dst, opnd); }
4458
4459// OR Pointer Size - dst = dst & imm
4460void MacroAssembler::OrP(Register dst, const Operand& opnd) {
4461#if V8_TARGET_ARCH_S390X
4462 intptr_t value = opnd.imm_;
4463 if (value >> 32 != 0) {
4464 // this may not work b/c condition code won't be set correctly
4465 oihf(dst, Operand(value >> 32));
4466 }
4467 oilf(dst, Operand(value & 0xFFFFFFFF));
4468#else
4469 Or(dst, opnd);
4470#endif
4471}
4472
4473// OR 32-bit - dst = src & imm
4474void MacroAssembler::Or(Register dst, Register src, const Operand& opnd) {
4475 if (!dst.is(src)) lr(dst, src);
4476 oilf(dst, opnd);
4477}
4478
4479// OR Pointer Size - dst = src & imm
4480void MacroAssembler::OrP(Register dst, Register src, const Operand& opnd) {
4481 if (!dst.is(src)) LoadRR(dst, src);
4482 OrP(dst, opnd);
4483}
4484
4485// XOR 32-bit - dst = dst & src
4486void MacroAssembler::Xor(Register dst, Register src) { xr(dst, src); }
4487
4488// XOR Pointer Size - dst = dst & src
4489void MacroAssembler::XorP(Register dst, Register src) { XorRR(dst, src); }
4490
4491// Non-clobbering XOR 32-bit - dst = src1 & src1
4492void MacroAssembler::Xor(Register dst, Register src1, Register src2) {
4493 if (!dst.is(src1) && !dst.is(src2)) {
4494 // We prefer to generate XR/XGR, over the non clobbering XRK/XRK
4495 // as XR is a smaller instruction
4496 if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4497 xrk(dst, src1, src2);
4498 return;
4499 } else {
4500 lr(dst, src1);
4501 }
4502 } else if (dst.is(src2)) {
4503 src2 = src1;
4504 }
4505 Xor(dst, src2);
4506}
4507
4508// Non-clobbering XOR pointer size - dst = src1 & src1
4509void MacroAssembler::XorP(Register dst, Register src1, Register src2) {
4510 if (!dst.is(src1) && !dst.is(src2)) {
4511 // We prefer to generate XR/XGR, over the non clobbering XRK/XRK
4512 // as XR is a smaller instruction
4513 if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4514 XorP_RRR(dst, src1, src2);
4515 return;
4516 } else {
4517 LoadRR(dst, src1);
4518 }
4519 } else if (dst.is(src2)) {
4520 src2 = src1;
4521 }
4522 XorP(dst, src2);
4523}
4524
4525// XOR 32-bit (Reg - Mem)
4526void MacroAssembler::Xor(Register dst, const MemOperand& opnd) {
4527 DCHECK(is_int20(opnd.offset()));
4528 if (is_uint12(opnd.offset()))
4529 x(dst, opnd);
4530 else
4531 xy(dst, opnd);
4532}
4533
4534// XOR Pointer Size (Reg - Mem)
4535void MacroAssembler::XorP(Register dst, const MemOperand& opnd) {
4536 DCHECK(is_int20(opnd.offset()));
4537#if V8_TARGET_ARCH_S390X
4538 xg(dst, opnd);
4539#else
4540 Xor(dst, opnd);
4541#endif
4542}
4543
4544// XOR 32-bit - dst = dst & imm
4545void MacroAssembler::Xor(Register dst, const Operand& opnd) { xilf(dst, opnd); }
4546
4547// XOR Pointer Size - dst = dst & imm
4548void MacroAssembler::XorP(Register dst, const Operand& opnd) {
4549#if V8_TARGET_ARCH_S390X
4550 intptr_t value = opnd.imm_;
4551 xihf(dst, Operand(value >> 32));
4552 xilf(dst, Operand(value & 0xFFFFFFFF));
4553#else
4554 Xor(dst, opnd);
4555#endif
4556}
4557
4558// XOR 32-bit - dst = src & imm
4559void MacroAssembler::Xor(Register dst, Register src, const Operand& opnd) {
4560 if (!dst.is(src)) lr(dst, src);
4561 xilf(dst, opnd);
4562}
4563
4564// XOR Pointer Size - dst = src & imm
4565void MacroAssembler::XorP(Register dst, Register src, const Operand& opnd) {
4566 if (!dst.is(src)) LoadRR(dst, src);
4567 XorP(dst, opnd);
4568}
4569
4570void MacroAssembler::NotP(Register dst) {
4571#if V8_TARGET_ARCH_S390X
4572 xihf(dst, Operand(0xFFFFFFFF));
4573 xilf(dst, Operand(0xFFFFFFFF));
4574#else
4575 XorP(dst, Operand(0xFFFFFFFF));
4576#endif
4577}
4578
4579// works the same as mov
4580void MacroAssembler::Load(Register dst, const Operand& opnd) {
4581 intptr_t value = opnd.immediate();
4582 if (is_int16(value)) {
4583#if V8_TARGET_ARCH_S390X
4584 lghi(dst, opnd);
4585#else
4586 lhi(dst, opnd);
4587#endif
4588 } else {
4589#if V8_TARGET_ARCH_S390X
4590 llilf(dst, opnd);
4591#else
4592 iilf(dst, opnd);
4593#endif
4594 }
4595}
4596
4597void MacroAssembler::Load(Register dst, const MemOperand& opnd) {
4598 DCHECK(is_int20(opnd.offset()));
4599#if V8_TARGET_ARCH_S390X
4600 lgf(dst, opnd); // 64<-32
4601#else
4602 if (is_uint12(opnd.offset())) {
4603 l(dst, opnd);
4604 } else {
4605 ly(dst, opnd);
4606 }
4607#endif
4608}
4609
4610//-----------------------------------------------------------------------------
4611// Compare Helpers
4612//-----------------------------------------------------------------------------
4613
4614// Compare 32-bit Register vs Register
4615void MacroAssembler::Cmp32(Register src1, Register src2) { cr_z(src1, src2); }
4616
4617// Compare Pointer Sized Register vs Register
4618void MacroAssembler::CmpP(Register src1, Register src2) {
4619#if V8_TARGET_ARCH_S390X
4620 cgr(src1, src2);
4621#else
4622 Cmp32(src1, src2);
4623#endif
4624}
4625
4626// Compare 32-bit Register vs Immediate
4627// This helper will set up proper relocation entries if required.
4628void MacroAssembler::Cmp32(Register dst, const Operand& opnd) {
4629 if (opnd.rmode_ == kRelocInfo_NONEPTR) {
4630 intptr_t value = opnd.immediate();
4631 if (is_int16(value))
4632 chi(dst, opnd);
4633 else
4634 cfi(dst, opnd);
4635 } else {
4636 // Need to generate relocation record here
4637 RecordRelocInfo(opnd.rmode_, opnd.imm_);
4638 cfi(dst, opnd);
4639 }
4640}
4641
4642// Compare Pointer Sized Register vs Immediate
4643// This helper will set up proper relocation entries if required.
4644void MacroAssembler::CmpP(Register dst, const Operand& opnd) {
4645#if V8_TARGET_ARCH_S390X
4646 if (opnd.rmode_ == kRelocInfo_NONEPTR) {
4647 cgfi(dst, opnd);
4648 } else {
4649 mov(r0, opnd); // Need to generate 64-bit relocation
4650 cgr(dst, r0);
4651 }
4652#else
4653 Cmp32(dst, opnd);
4654#endif
4655}
4656
4657// Compare 32-bit Register vs Memory
4658void MacroAssembler::Cmp32(Register dst, const MemOperand& opnd) {
4659 // make sure offset is within 20 bit range
4660 DCHECK(is_int20(opnd.offset()));
4661 if (is_uint12(opnd.offset()))
4662 c(dst, opnd);
4663 else
4664 cy(dst, opnd);
4665}
4666
4667// Compare Pointer Size Register vs Memory
4668void MacroAssembler::CmpP(Register dst, const MemOperand& opnd) {
4669 // make sure offset is within 20 bit range
4670 DCHECK(is_int20(opnd.offset()));
4671#if V8_TARGET_ARCH_S390X
4672 cg(dst, opnd);
4673#else
4674 Cmp32(dst, opnd);
4675#endif
4676}
4677
4678//-----------------------------------------------------------------------------
4679// Compare Logical Helpers
4680//-----------------------------------------------------------------------------
4681
4682// Compare Logical 32-bit Register vs Register
4683void MacroAssembler::CmpLogical32(Register dst, Register src) { clr(dst, src); }
4684
4685// Compare Logical Pointer Sized Register vs Register
4686void MacroAssembler::CmpLogicalP(Register dst, Register src) {
4687#ifdef V8_TARGET_ARCH_S390X
4688 clgr(dst, src);
4689#else
4690 CmpLogical32(dst, src);
4691#endif
4692}
4693
4694// Compare Logical 32-bit Register vs Immediate
4695void MacroAssembler::CmpLogical32(Register dst, const Operand& opnd) {
4696 clfi(dst, opnd);
4697}
4698
4699// Compare Logical Pointer Sized Register vs Immediate
4700void MacroAssembler::CmpLogicalP(Register dst, const Operand& opnd) {
4701#if V8_TARGET_ARCH_S390X
4702 DCHECK(static_cast<uint32_t>(opnd.immediate() >> 32) == 0);
4703 clgfi(dst, opnd);
4704#else
4705 CmpLogical32(dst, opnd);
4706#endif
4707}
4708
4709// Compare Logical 32-bit Register vs Memory
4710void MacroAssembler::CmpLogical32(Register dst, const MemOperand& opnd) {
4711 // make sure offset is within 20 bit range
4712 DCHECK(is_int20(opnd.offset()));
4713 if (is_uint12(opnd.offset()))
4714 cl(dst, opnd);
4715 else
4716 cly(dst, opnd);
4717}
4718
4719// Compare Logical Pointer Sized Register vs Memory
4720void MacroAssembler::CmpLogicalP(Register dst, const MemOperand& opnd) {
4721 // make sure offset is within 20 bit range
4722 DCHECK(is_int20(opnd.offset()));
4723#if V8_TARGET_ARCH_S390X
4724 clg(dst, opnd);
4725#else
4726 CmpLogical32(dst, opnd);
4727#endif
4728}
4729
4730// Compare Logical Byte (Mem - Imm)
4731void MacroAssembler::CmpLogicalByte(const MemOperand& mem, const Operand& imm) {
4732 DCHECK(is_uint8(imm.immediate()));
4733 if (is_uint12(mem.offset()))
4734 cli(mem, imm);
4735 else
4736 cliy(mem, imm);
4737}
4738
4739void MacroAssembler::Branch(Condition c, const Operand& opnd) {
4740 intptr_t value = opnd.immediate();
4741 if (is_int16(value))
4742 brc(c, opnd);
4743 else
4744 brcl(c, opnd);
4745}
4746
4747// Branch On Count. Decrement R1, and branch if R1 != 0.
4748void MacroAssembler::BranchOnCount(Register r1, Label* l) {
4749 int32_t offset = branch_offset(l);
Ben Murdochda12d292016-06-02 14:46:10 +01004750 if (is_int16(offset)) {
4751#if V8_TARGET_ARCH_S390X
4752 brctg(r1, Operand(offset));
4753#else
4754 brct(r1, Operand(offset));
4755#endif
4756 } else {
4757 AddP(r1, Operand(-1));
4758 Branch(ne, Operand(offset));
4759 }
4760}
4761
4762void MacroAssembler::LoadIntLiteral(Register dst, int value) {
4763 Load(dst, Operand(value));
4764}
4765
4766void MacroAssembler::LoadSmiLiteral(Register dst, Smi* smi) {
4767 intptr_t value = reinterpret_cast<intptr_t>(smi);
4768#if V8_TARGET_ARCH_S390X
4769 DCHECK((value & 0xffffffff) == 0);
4770 // The smi value is loaded in upper 32-bits. Lower 32-bit are zeros.
4771 llihf(dst, Operand(value >> 32));
4772#else
4773 llilf(dst, Operand(value));
4774#endif
4775}
4776
4777void MacroAssembler::LoadDoubleLiteral(DoubleRegister result, uint64_t value,
4778 Register scratch) {
4779 uint32_t hi_32 = value >> 32;
4780 uint32_t lo_32 = static_cast<uint32_t>(value);
4781
4782 // Load the 64-bit value into a GPR, then transfer it to FPR via LDGR
4783 iihf(scratch, Operand(hi_32));
4784 iilf(scratch, Operand(lo_32));
4785 ldgr(result, scratch);
4786}
4787
4788void MacroAssembler::LoadDoubleLiteral(DoubleRegister result, double value,
4789 Register scratch) {
4790 uint64_t int_val = bit_cast<uint64_t, double>(value);
4791 LoadDoubleLiteral(result, int_val, scratch);
4792}
4793
4794void MacroAssembler::LoadFloat32Literal(DoubleRegister result, float value,
4795 Register scratch) {
4796 uint32_t hi_32 = bit_cast<uint32_t>(value);
4797 uint32_t lo_32 = 0;
4798
4799 // Load the 64-bit value into a GPR, then transfer it to FPR via LDGR
4800 iihf(scratch, Operand(hi_32));
4801 iilf(scratch, Operand(lo_32));
4802 ldgr(result, scratch);
4803}
4804
4805void MacroAssembler::CmpSmiLiteral(Register src1, Smi* smi, Register scratch) {
4806#if V8_TARGET_ARCH_S390X
4807 LoadSmiLiteral(scratch, smi);
4808 cgr(src1, scratch);
4809#else
4810 // CFI takes 32-bit immediate.
4811 cfi(src1, Operand(smi));
4812#endif
4813}
4814
4815void MacroAssembler::CmpLogicalSmiLiteral(Register src1, Smi* smi,
4816 Register scratch) {
4817#if V8_TARGET_ARCH_S390X
4818 LoadSmiLiteral(scratch, smi);
4819 clgr(src1, scratch);
4820#else
4821 // CLFI takes 32-bit immediate
4822 clfi(src1, Operand(smi));
4823#endif
4824}
4825
4826void MacroAssembler::AddSmiLiteral(Register dst, Register src, Smi* smi,
4827 Register scratch) {
4828#if V8_TARGET_ARCH_S390X
4829 LoadSmiLiteral(scratch, smi);
4830 AddP(dst, src, scratch);
4831#else
4832 AddP(dst, src, Operand(reinterpret_cast<intptr_t>(smi)));
4833#endif
4834}
4835
4836void MacroAssembler::SubSmiLiteral(Register dst, Register src, Smi* smi,
4837 Register scratch) {
4838#if V8_TARGET_ARCH_S390X
4839 LoadSmiLiteral(scratch, smi);
4840 SubP(dst, src, scratch);
4841#else
4842 AddP(dst, src, Operand(-(reinterpret_cast<intptr_t>(smi))));
4843#endif
4844}
4845
4846void MacroAssembler::AndSmiLiteral(Register dst, Register src, Smi* smi) {
4847 if (!dst.is(src)) LoadRR(dst, src);
4848#if V8_TARGET_ARCH_S390X
4849 DCHECK((reinterpret_cast<intptr_t>(smi) & 0xffffffff) == 0);
4850 int value = static_cast<int>(reinterpret_cast<intptr_t>(smi) >> 32);
4851 nihf(dst, Operand(value));
4852#else
4853 nilf(dst, Operand(reinterpret_cast<int>(smi)));
4854#endif
4855}
4856
4857// Load a "pointer" sized value from the memory location
4858void MacroAssembler::LoadP(Register dst, const MemOperand& mem,
4859 Register scratch) {
4860 int offset = mem.offset();
4861
4862 if (!scratch.is(no_reg) && !is_int20(offset)) {
4863 /* cannot use d-form */
4864 LoadIntLiteral(scratch, offset);
4865#if V8_TARGET_ARCH_S390X
4866 lg(dst, MemOperand(mem.rb(), scratch));
4867#else
4868 l(dst, MemOperand(mem.rb(), scratch));
4869#endif
4870 } else {
4871#if V8_TARGET_ARCH_S390X
4872 lg(dst, mem);
4873#else
4874 if (is_uint12(offset)) {
4875 l(dst, mem);
4876 } else {
4877 ly(dst, mem);
4878 }
4879#endif
4880 }
4881}
4882
4883// Store a "pointer" sized value to the memory location
4884void MacroAssembler::StoreP(Register src, const MemOperand& mem,
4885 Register scratch) {
4886 if (!is_int20(mem.offset())) {
4887 DCHECK(!scratch.is(no_reg));
4888 DCHECK(!scratch.is(r0));
4889 LoadIntLiteral(scratch, mem.offset());
4890#if V8_TARGET_ARCH_S390X
4891 stg(src, MemOperand(mem.rb(), scratch));
4892#else
4893 st(src, MemOperand(mem.rb(), scratch));
4894#endif
4895 } else {
4896#if V8_TARGET_ARCH_S390X
4897 stg(src, mem);
4898#else
4899 // StoreW will try to generate ST if offset fits, otherwise
4900 // it'll generate STY.
4901 StoreW(src, mem);
4902#endif
4903 }
4904}
4905
4906// Store a "pointer" sized constant to the memory location
4907void MacroAssembler::StoreP(const MemOperand& mem, const Operand& opnd,
4908 Register scratch) {
4909 // Relocations not supported
4910 DCHECK(opnd.rmode_ == kRelocInfo_NONEPTR);
4911
4912 // Try to use MVGHI/MVHI
4913 if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT) && is_uint12(mem.offset()) &&
4914 mem.getIndexRegister().is(r0) && is_int16(opnd.imm_)) {
4915#if V8_TARGET_ARCH_S390X
4916 mvghi(mem, opnd);
4917#else
4918 mvhi(mem, opnd);
4919#endif
4920 } else {
4921 LoadImmP(scratch, opnd);
4922 StoreP(scratch, mem);
4923 }
4924}
4925
4926void MacroAssembler::LoadMultipleP(Register dst1, Register dst2,
4927 const MemOperand& mem) {
4928#if V8_TARGET_ARCH_S390X
4929 DCHECK(is_int20(mem.offset()));
4930 lmg(dst1, dst2, mem);
4931#else
4932 if (is_uint12(mem.offset())) {
4933 lm(dst1, dst2, mem);
4934 } else {
4935 DCHECK(is_int20(mem.offset()));
4936 lmy(dst1, dst2, mem);
4937 }
4938#endif
4939}
4940
4941void MacroAssembler::StoreMultipleP(Register src1, Register src2,
4942 const MemOperand& mem) {
4943#if V8_TARGET_ARCH_S390X
4944 DCHECK(is_int20(mem.offset()));
4945 stmg(src1, src2, mem);
4946#else
4947 if (is_uint12(mem.offset())) {
4948 stm(src1, src2, mem);
4949 } else {
4950 DCHECK(is_int20(mem.offset()));
4951 stmy(src1, src2, mem);
4952 }
4953#endif
4954}
4955
4956void MacroAssembler::LoadMultipleW(Register dst1, Register dst2,
4957 const MemOperand& mem) {
4958 if (is_uint12(mem.offset())) {
4959 lm(dst1, dst2, mem);
4960 } else {
4961 DCHECK(is_int20(mem.offset()));
4962 lmy(dst1, dst2, mem);
4963 }
4964}
4965
4966void MacroAssembler::StoreMultipleW(Register src1, Register src2,
4967 const MemOperand& mem) {
4968 if (is_uint12(mem.offset())) {
4969 stm(src1, src2, mem);
4970 } else {
4971 DCHECK(is_int20(mem.offset()));
4972 stmy(src1, src2, mem);
4973 }
4974}
4975
4976// Load 32-bits and sign extend if necessary.
4977void MacroAssembler::LoadW(Register dst, Register src) {
4978#if V8_TARGET_ARCH_S390X
4979 lgfr(dst, src);
4980#else
4981 if (!dst.is(src)) lr(dst, src);
4982#endif
4983}
4984
4985// Load 32-bits and sign extend if necessary.
4986void MacroAssembler::LoadW(Register dst, const MemOperand& mem,
4987 Register scratch) {
4988 int offset = mem.offset();
4989
4990 if (!is_int20(offset)) {
4991 DCHECK(!scratch.is(no_reg));
4992 LoadIntLiteral(scratch, offset);
4993#if V8_TARGET_ARCH_S390X
4994 lgf(dst, MemOperand(mem.rb(), scratch));
4995#else
4996 l(dst, MemOperand(mem.rb(), scratch));
4997#endif
4998 } else {
4999#if V8_TARGET_ARCH_S390X
5000 lgf(dst, mem);
5001#else
5002 if (is_uint12(offset)) {
5003 l(dst, mem);
5004 } else {
5005 ly(dst, mem);
5006 }
5007#endif
5008 }
5009}
5010
5011// Load 32-bits and zero extend if necessary.
5012void MacroAssembler::LoadlW(Register dst, Register src) {
5013#if V8_TARGET_ARCH_S390X
5014 llgfr(dst, src);
5015#else
5016 if (!dst.is(src)) lr(dst, src);
5017#endif
5018}
5019
5020// Variable length depending on whether offset fits into immediate field
5021// MemOperand of RX or RXY format
5022void MacroAssembler::LoadlW(Register dst, const MemOperand& mem,
5023 Register scratch) {
5024 Register base = mem.rb();
5025 int offset = mem.offset();
5026
5027#if V8_TARGET_ARCH_S390X
5028 if (is_int20(offset)) {
5029 llgf(dst, mem);
5030 } else if (!scratch.is(no_reg)) {
5031 // Materialize offset into scratch register.
5032 LoadIntLiteral(scratch, offset);
5033 llgf(dst, MemOperand(base, scratch));
5034 } else {
5035 DCHECK(false);
5036 }
5037#else
5038 bool use_RXform = false;
5039 bool use_RXYform = false;
5040 if (is_uint12(offset)) {
5041 // RX-format supports unsigned 12-bits offset.
5042 use_RXform = true;
5043 } else if (is_int20(offset)) {
5044 // RXY-format supports signed 20-bits offset.
5045 use_RXYform = true;
5046 } else if (!scratch.is(no_reg)) {
5047 // Materialize offset into scratch register.
5048 LoadIntLiteral(scratch, offset);
5049 } else {
5050 DCHECK(false);
5051 }
5052
5053 if (use_RXform) {
5054 l(dst, mem);
5055 } else if (use_RXYform) {
5056 ly(dst, mem);
5057 } else {
5058 ly(dst, MemOperand(base, scratch));
5059 }
5060#endif
5061}
5062
5063void MacroAssembler::LoadB(Register dst, const MemOperand& mem) {
5064#if V8_TARGET_ARCH_S390X
5065 lgb(dst, mem);
5066#else
5067 lb(dst, mem);
5068#endif
5069}
5070
Ben Murdochc5610432016-08-08 18:44:38 +01005071void MacroAssembler::LoadB(Register dst, Register src) {
5072#if V8_TARGET_ARCH_S390X
5073 lgbr(dst, src);
5074#else
5075 lbr(dst, src);
5076#endif
5077}
5078
Ben Murdochda12d292016-06-02 14:46:10 +01005079void MacroAssembler::LoadlB(Register dst, const MemOperand& mem) {
5080#if V8_TARGET_ARCH_S390X
5081 llgc(dst, mem);
5082#else
5083 llc(dst, mem);
5084#endif
5085}
5086
5087// Load And Test (Reg <- Reg)
5088void MacroAssembler::LoadAndTest32(Register dst, Register src) {
5089 ltr(dst, src);
5090}
5091
5092// Load And Test
5093// (Register dst(ptr) = Register src (32 | 32->64))
5094// src is treated as a 32-bit signed integer, which is sign extended to
5095// 64-bit if necessary.
5096void MacroAssembler::LoadAndTestP_ExtendSrc(Register dst, Register src) {
5097#if V8_TARGET_ARCH_S390X
5098 ltgfr(dst, src);
5099#else
5100 ltr(dst, src);
5101#endif
5102}
5103
5104// Load And Test Pointer Sized (Reg <- Reg)
5105void MacroAssembler::LoadAndTestP(Register dst, Register src) {
5106#if V8_TARGET_ARCH_S390X
5107 ltgr(dst, src);
5108#else
5109 ltr(dst, src);
5110#endif
5111}
5112
5113// Load And Test 32-bit (Reg <- Mem)
5114void MacroAssembler::LoadAndTest32(Register dst, const MemOperand& mem) {
5115 lt_z(dst, mem);
5116}
5117
5118// Load And Test Pointer Sized (Reg <- Mem)
5119void MacroAssembler::LoadAndTestP(Register dst, const MemOperand& mem) {
5120#if V8_TARGET_ARCH_S390X
5121 ltg(dst, mem);
5122#else
5123 lt_z(dst, mem);
5124#endif
5125}
5126
5127// Load Double Precision (64-bit) Floating Point number from memory
5128void MacroAssembler::LoadDouble(DoubleRegister dst, const MemOperand& mem) {
5129 // for 32bit and 64bit we all use 64bit floating point regs
5130 if (is_uint12(mem.offset())) {
5131 ld(dst, mem);
5132 } else {
5133 ldy(dst, mem);
5134 }
5135}
5136
5137// Load Single Precision (32-bit) Floating Point number from memory
5138void MacroAssembler::LoadFloat32(DoubleRegister dst, const MemOperand& mem) {
5139 if (is_uint12(mem.offset())) {
5140 le_z(dst, mem);
5141 } else {
5142 DCHECK(is_int20(mem.offset()));
5143 ley(dst, mem);
5144 }
5145}
5146
5147// Load Single Precision (32-bit) Floating Point number from memory,
5148// and convert to Double Precision (64-bit)
5149void MacroAssembler::LoadFloat32ConvertToDouble(DoubleRegister dst,
5150 const MemOperand& mem) {
5151 LoadFloat32(dst, mem);
5152 ldebr(dst, dst);
5153}
5154
5155// Store Double Precision (64-bit) Floating Point number to memory
5156void MacroAssembler::StoreDouble(DoubleRegister dst, const MemOperand& mem) {
5157 if (is_uint12(mem.offset())) {
5158 std(dst, mem);
5159 } else {
5160 stdy(dst, mem);
5161 }
5162}
5163
5164// Store Single Precision (32-bit) Floating Point number to memory
5165void MacroAssembler::StoreFloat32(DoubleRegister src, const MemOperand& mem) {
5166 if (is_uint12(mem.offset())) {
5167 ste(src, mem);
5168 } else {
5169 stey(src, mem);
5170 }
5171}
5172
5173// Convert Double precision (64-bit) to Single Precision (32-bit)
5174// and store resulting Float32 to memory
5175void MacroAssembler::StoreDoubleAsFloat32(DoubleRegister src,
5176 const MemOperand& mem,
5177 DoubleRegister scratch) {
5178 ledbr(scratch, src);
5179 StoreFloat32(scratch, mem);
5180}
5181
5182// Variable length depending on whether offset fits into immediate field
5183// MemOperand of RX or RXY format
5184void MacroAssembler::StoreW(Register src, const MemOperand& mem,
5185 Register scratch) {
5186 Register base = mem.rb();
5187 int offset = mem.offset();
5188
5189 bool use_RXform = false;
5190 bool use_RXYform = false;
5191
5192 if (is_uint12(offset)) {
5193 // RX-format supports unsigned 12-bits offset.
5194 use_RXform = true;
5195 } else if (is_int20(offset)) {
5196 // RXY-format supports signed 20-bits offset.
5197 use_RXYform = true;
5198 } else if (!scratch.is(no_reg)) {
5199 // Materialize offset into scratch register.
5200 LoadIntLiteral(scratch, offset);
5201 } else {
5202 // scratch is no_reg
5203 DCHECK(false);
5204 }
5205
5206 if (use_RXform) {
5207 st(src, mem);
5208 } else if (use_RXYform) {
5209 sty(src, mem);
5210 } else {
5211 StoreW(src, MemOperand(base, scratch));
5212 }
5213}
5214
5215// Loads 16-bits half-word value from memory and sign extends to pointer
5216// sized register
5217void MacroAssembler::LoadHalfWordP(Register dst, const MemOperand& mem,
5218 Register scratch) {
5219 Register base = mem.rb();
5220 int offset = mem.offset();
5221
5222 if (!is_int20(offset)) {
5223 DCHECK(!scratch.is(no_reg));
5224 LoadIntLiteral(scratch, offset);
5225#if V8_TARGET_ARCH_S390X
5226 lgh(dst, MemOperand(base, scratch));
5227#else
5228 lh(dst, MemOperand(base, scratch));
5229#endif
5230 } else {
5231#if V8_TARGET_ARCH_S390X
5232 lgh(dst, mem);
5233#else
5234 if (is_uint12(offset)) {
5235 lh(dst, mem);
5236 } else {
5237 lhy(dst, mem);
5238 }
5239#endif
5240 }
5241}
5242
5243// Variable length depending on whether offset fits into immediate field
5244// MemOperand current only supports d-form
5245void MacroAssembler::StoreHalfWord(Register src, const MemOperand& mem,
5246 Register scratch) {
5247 Register base = mem.rb();
5248 int offset = mem.offset();
5249
5250 if (is_uint12(offset)) {
5251 sth(src, mem);
5252 } else if (is_int20(offset)) {
5253 sthy(src, mem);
5254 } else {
5255 DCHECK(!scratch.is(no_reg));
5256 LoadIntLiteral(scratch, offset);
5257 sth(src, MemOperand(base, scratch));
5258 }
5259}
5260
5261// Variable length depending on whether offset fits into immediate field
5262// MemOperand current only supports d-form
5263void MacroAssembler::StoreByte(Register src, const MemOperand& mem,
5264 Register scratch) {
5265 Register base = mem.rb();
5266 int offset = mem.offset();
5267
5268 if (is_uint12(offset)) {
5269 stc(src, mem);
5270 } else if (is_int20(offset)) {
5271 stcy(src, mem);
5272 } else {
5273 DCHECK(!scratch.is(no_reg));
5274 LoadIntLiteral(scratch, offset);
5275 stc(src, MemOperand(base, scratch));
5276 }
5277}
5278
5279// Shift left logical for 32-bit integer types.
5280void MacroAssembler::ShiftLeft(Register dst, Register src, const Operand& val) {
5281 if (dst.is(src)) {
5282 sll(dst, val);
5283 } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
5284 sllk(dst, src, val);
5285 } else {
5286 lr(dst, src);
5287 sll(dst, val);
5288 }
5289}
5290
5291// Shift left logical for 32-bit integer types.
5292void MacroAssembler::ShiftLeft(Register dst, Register src, Register val) {
5293 if (dst.is(src)) {
5294 sll(dst, val);
5295 } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
5296 sllk(dst, src, val);
5297 } else {
5298 DCHECK(!dst.is(val)); // The lr/sll path clobbers val.
5299 lr(dst, src);
5300 sll(dst, val);
5301 }
5302}
5303
5304// Shift right logical for 32-bit integer types.
5305void MacroAssembler::ShiftRight(Register dst, Register src,
5306 const Operand& val) {
5307 if (dst.is(src)) {
5308 srl(dst, val);
5309 } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
5310 srlk(dst, src, val);
5311 } else {
5312 lr(dst, src);
5313 srl(dst, val);
5314 }
5315}
5316
5317// Shift right logical for 32-bit integer types.
5318void MacroAssembler::ShiftRight(Register dst, Register src, Register val) {
Ben Murdochda12d292016-06-02 14:46:10 +01005319 if (dst.is(src)) {
5320 srl(dst, val);
5321 } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
5322 srlk(dst, src, val);
5323 } else {
Ben Murdoch6f5d0ea2016-06-15 14:45:46 +01005324 DCHECK(!dst.is(val)); // The lr/srl path clobbers val.
Ben Murdochda12d292016-06-02 14:46:10 +01005325 lr(dst, src);
5326 srl(dst, val);
5327 }
5328}
5329
5330// Shift left arithmetic for 32-bit integer types.
5331void MacroAssembler::ShiftLeftArith(Register dst, Register src,
5332 const Operand& val) {
5333 if (dst.is(src)) {
5334 sla(dst, val);
5335 } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
5336 slak(dst, src, val);
5337 } else {
5338 lr(dst, src);
5339 sla(dst, val);
5340 }
5341}
5342
5343// Shift left arithmetic for 32-bit integer types.
5344void MacroAssembler::ShiftLeftArith(Register dst, Register src, Register val) {
Ben Murdochda12d292016-06-02 14:46:10 +01005345 if (dst.is(src)) {
5346 sla(dst, val);
5347 } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
5348 slak(dst, src, val);
5349 } else {
Ben Murdoch6f5d0ea2016-06-15 14:45:46 +01005350 DCHECK(!dst.is(val)); // The lr/sla path clobbers val.
Ben Murdochda12d292016-06-02 14:46:10 +01005351 lr(dst, src);
5352 sla(dst, val);
5353 }
5354}
5355
5356// Shift right arithmetic for 32-bit integer types.
5357void MacroAssembler::ShiftRightArith(Register dst, Register src,
5358 const Operand& val) {
5359 if (dst.is(src)) {
5360 sra(dst, val);
5361 } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
5362 srak(dst, src, val);
5363 } else {
5364 lr(dst, src);
5365 sra(dst, val);
5366 }
5367}
5368
5369// Shift right arithmetic for 32-bit integer types.
5370void MacroAssembler::ShiftRightArith(Register dst, Register src, Register val) {
Ben Murdochda12d292016-06-02 14:46:10 +01005371 if (dst.is(src)) {
5372 sra(dst, val);
5373 } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
5374 srak(dst, src, val);
5375 } else {
Ben Murdoch6f5d0ea2016-06-15 14:45:46 +01005376 DCHECK(!dst.is(val)); // The lr/sra path clobbers val.
Ben Murdochda12d292016-06-02 14:46:10 +01005377 lr(dst, src);
5378 sra(dst, val);
5379 }
5380}
5381
5382// Clear right most # of bits
5383void MacroAssembler::ClearRightImm(Register dst, Register src,
5384 const Operand& val) {
5385 int numBitsToClear = val.imm_ % (kPointerSize * 8);
5386
5387 // Try to use RISBG if possible
5388 if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) {
5389 int endBit = 63 - numBitsToClear;
5390 risbg(dst, src, Operand::Zero(), Operand(endBit), Operand::Zero(), true);
5391 return;
5392 }
5393
5394 uint64_t hexMask = ~((1L << numBitsToClear) - 1);
5395
5396 // S390 AND instr clobbers source. Make a copy if necessary
5397 if (!dst.is(src)) LoadRR(dst, src);
5398
5399 if (numBitsToClear <= 16) {
5400 nill(dst, Operand(static_cast<uint16_t>(hexMask)));
5401 } else if (numBitsToClear <= 32) {
5402 nilf(dst, Operand(static_cast<uint32_t>(hexMask)));
5403 } else if (numBitsToClear <= 64) {
5404 nilf(dst, Operand(static_cast<intptr_t>(0)));
5405 nihf(dst, Operand(hexMask >> 32));
5406 }
5407}
5408
5409void MacroAssembler::Popcnt32(Register dst, Register src) {
5410 DCHECK(!src.is(r0));
5411 DCHECK(!dst.is(r0));
5412
5413 popcnt(dst, src);
5414 ShiftRight(r0, dst, Operand(16));
5415 ar(dst, r0);
5416 ShiftRight(r0, dst, Operand(8));
5417 ar(dst, r0);
Ben Murdochc5610432016-08-08 18:44:38 +01005418 LoadB(dst, dst);
Ben Murdochda12d292016-06-02 14:46:10 +01005419}
5420
5421#ifdef V8_TARGET_ARCH_S390X
5422void MacroAssembler::Popcnt64(Register dst, Register src) {
5423 DCHECK(!src.is(r0));
5424 DCHECK(!dst.is(r0));
5425
5426 popcnt(dst, src);
5427 ShiftRightP(r0, dst, Operand(32));
5428 AddP(dst, r0);
5429 ShiftRightP(r0, dst, Operand(16));
5430 AddP(dst, r0);
5431 ShiftRightP(r0, dst, Operand(8));
5432 AddP(dst, r0);
Ben Murdochc5610432016-08-08 18:44:38 +01005433 LoadB(dst, dst);
Ben Murdochda12d292016-06-02 14:46:10 +01005434}
5435#endif
5436
5437#ifdef DEBUG
5438bool AreAliased(Register reg1, Register reg2, Register reg3, Register reg4,
5439 Register reg5, Register reg6, Register reg7, Register reg8,
5440 Register reg9, Register reg10) {
5441 int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() + reg3.is_valid() +
5442 reg4.is_valid() + reg5.is_valid() + reg6.is_valid() +
5443 reg7.is_valid() + reg8.is_valid() + reg9.is_valid() +
5444 reg10.is_valid();
5445
5446 RegList regs = 0;
5447 if (reg1.is_valid()) regs |= reg1.bit();
5448 if (reg2.is_valid()) regs |= reg2.bit();
5449 if (reg3.is_valid()) regs |= reg3.bit();
5450 if (reg4.is_valid()) regs |= reg4.bit();
5451 if (reg5.is_valid()) regs |= reg5.bit();
5452 if (reg6.is_valid()) regs |= reg6.bit();
5453 if (reg7.is_valid()) regs |= reg7.bit();
5454 if (reg8.is_valid()) regs |= reg8.bit();
5455 if (reg9.is_valid()) regs |= reg9.bit();
5456 if (reg10.is_valid()) regs |= reg10.bit();
5457 int n_of_non_aliasing_regs = NumRegs(regs);
5458
5459 return n_of_valid_regs != n_of_non_aliasing_regs;
5460}
5461#endif
5462
5463CodePatcher::CodePatcher(Isolate* isolate, byte* address, int size,
5464 FlushICache flush_cache)
5465 : address_(address),
5466 size_(size),
5467 masm_(isolate, address, size_ + Assembler::kGap, CodeObjectRequired::kNo),
5468 flush_cache_(flush_cache) {
5469 // Create a new macro assembler pointing to the address of the code to patch.
5470 // The size is adjusted with kGap on order for the assembler to generate size
5471 // bytes of instructions without failing with buffer size constraints.
5472 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
5473}
5474
5475CodePatcher::~CodePatcher() {
5476 // Indicate that code has changed.
5477 if (flush_cache_ == FLUSH) {
5478 Assembler::FlushICache(masm_.isolate(), address_, size_);
5479 }
5480
5481 // Check that the code was patched as expected.
5482 DCHECK(masm_.pc_ == address_ + size_);
5483 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
5484}
5485
5486void MacroAssembler::TruncatingDiv(Register result, Register dividend,
5487 int32_t divisor) {
5488 DCHECK(!dividend.is(result));
5489 DCHECK(!dividend.is(r0));
5490 DCHECK(!result.is(r0));
5491 base::MagicNumbersForDivision<uint32_t> mag =
5492 base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
5493#ifdef V8_TARGET_ARCH_S390X
5494 LoadRR(result, dividend);
5495 MulP(result, Operand(mag.multiplier));
5496 ShiftRightArithP(result, result, Operand(32));
5497
5498#else
5499 lay(sp, MemOperand(sp, -kPointerSize));
5500 StoreP(r1, MemOperand(sp));
5501
5502 mov(r1, Operand(mag.multiplier));
5503 mr_z(r0, dividend); // r0:r1 = r1 * dividend
5504
5505 LoadRR(result, r0);
5506 LoadP(r1, MemOperand(sp));
5507 la(sp, MemOperand(sp, kPointerSize));
5508#endif
5509 bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
5510 if (divisor > 0 && neg) {
5511 AddP(result, dividend);
5512 }
5513 if (divisor < 0 && !neg && mag.multiplier > 0) {
5514 SubP(result, dividend);
5515 }
5516 if (mag.shift > 0) ShiftRightArith(result, result, Operand(mag.shift));
5517 ExtractBit(r0, dividend, 31);
5518 AddP(result, r0);
5519}
5520
5521} // namespace internal
5522} // namespace v8
5523
5524#endif // V8_TARGET_ARCH_S390