blob: 9cd35ab01c397eef2ca56197f4cd52825c99e2b0 [file] [log] [blame]
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001// 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008#if V8_TARGET_ARCH_PPC
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"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014#include "src/debug/debug.h"
15#include "src/register-configuration.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016#include "src/runtime/runtime.h"
17
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018#include "src/ppc/macro-assembler-ppc.h"
19
Emily Bernierd0a1eb72015-03-24 16:35:39 -040020namespace v8 {
21namespace internal {
22
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000023MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size,
24 CodeObjectRequired create_code_object)
Emily Bernierd0a1eb72015-03-24 16:35:39 -040025 : Assembler(arg_isolate, buffer, size),
26 generating_stub_(false),
27 has_frame_(false) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000028 if (create_code_object == CodeObjectRequired::kYes) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040029 code_object_ =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000030 Handle<Object>::New(isolate()->heap()->undefined_value(), isolate());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040031 }
32}
33
34
35void MacroAssembler::Jump(Register target) {
36 mtctr(target);
37 bctr();
38}
39
40
41void MacroAssembler::JumpToJSEntry(Register target) {
42 Move(ip, target);
43 Jump(ip);
44}
45
46
47void MacroAssembler::Jump(intptr_t target, RelocInfo::Mode rmode,
48 Condition cond, CRegister cr) {
49 Label skip;
50
51 if (cond != al) b(NegateCondition(cond), &skip, cr);
52
53 DCHECK(rmode == RelocInfo::CODE_TARGET || rmode == RelocInfo::RUNTIME_ENTRY);
54
55 mov(ip, Operand(target, rmode));
56 mtctr(ip);
57 bctr();
58
59 bind(&skip);
60}
61
62
63void MacroAssembler::Jump(Address target, RelocInfo::Mode rmode, Condition cond,
64 CRegister cr) {
65 DCHECK(!RelocInfo::IsCodeTarget(rmode));
66 Jump(reinterpret_cast<intptr_t>(target), rmode, cond, cr);
67}
68
69
70void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
71 Condition cond) {
72 DCHECK(RelocInfo::IsCodeTarget(rmode));
73 // 'code' is always generated ppc code, never THUMB code
74 AllowDeferredHandleDereference embedding_raw_address;
75 Jump(reinterpret_cast<intptr_t>(code.location()), rmode, cond);
76}
77
78
79int MacroAssembler::CallSize(Register target) { return 2 * kInstrSize; }
80
81
82void MacroAssembler::Call(Register target) {
83 BlockTrampolinePoolScope block_trampoline_pool(this);
84 Label start;
85 bind(&start);
86
87 // Statement positions are expected to be recorded when the target
88 // address is loaded.
89 positions_recorder()->WriteRecordedPositions();
90
91 // branch via link register and set LK bit for return point
92 mtctr(target);
93 bctrl();
94
95 DCHECK_EQ(CallSize(target), SizeOfCodeGeneratedSince(&start));
96}
97
98
99void MacroAssembler::CallJSEntry(Register target) {
100 DCHECK(target.is(ip));
101 Call(target);
102}
103
104
105int MacroAssembler::CallSize(Address target, RelocInfo::Mode rmode,
106 Condition cond) {
107 Operand mov_operand = Operand(reinterpret_cast<intptr_t>(target), rmode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000108 return (2 + instructions_required_for_mov(ip, mov_operand)) * kInstrSize;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400109}
110
111
112int MacroAssembler::CallSizeNotPredictableCodeSize(Address target,
113 RelocInfo::Mode rmode,
114 Condition cond) {
115 return (2 + kMovInstructionsNoConstantPool) * kInstrSize;
116}
117
118
119void MacroAssembler::Call(Address target, RelocInfo::Mode rmode,
120 Condition cond) {
121 BlockTrampolinePoolScope block_trampoline_pool(this);
122 DCHECK(cond == al);
123
124#ifdef DEBUG
125 // Check the expected size before generating code to ensure we assume the same
126 // constant pool availability (e.g., whether constant pool is full or not).
127 int expected_size = CallSize(target, rmode, cond);
128 Label start;
129 bind(&start);
130#endif
131
132 // Statement positions are expected to be recorded when the target
133 // address is loaded.
134 positions_recorder()->WriteRecordedPositions();
135
136 // This can likely be optimized to make use of bc() with 24bit relative
137 //
138 // RecordRelocInfo(x.rmode_, x.imm_);
139 // bc( BA, .... offset, LKset);
140 //
141
142 mov(ip, Operand(reinterpret_cast<intptr_t>(target), rmode));
143 mtctr(ip);
144 bctrl();
145
146 DCHECK_EQ(expected_size, SizeOfCodeGeneratedSince(&start));
147}
148
149
150int MacroAssembler::CallSize(Handle<Code> code, RelocInfo::Mode rmode,
151 TypeFeedbackId ast_id, Condition cond) {
152 AllowDeferredHandleDereference using_raw_address;
153 return CallSize(reinterpret_cast<Address>(code.location()), rmode, cond);
154}
155
156
157void MacroAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode,
158 TypeFeedbackId ast_id, Condition cond) {
159 BlockTrampolinePoolScope block_trampoline_pool(this);
160 DCHECK(RelocInfo::IsCodeTarget(rmode));
161
162#ifdef DEBUG
163 // Check the expected size before generating code to ensure we assume the same
164 // constant pool availability (e.g., whether constant pool is full or not).
165 int expected_size = CallSize(code, rmode, ast_id, cond);
166 Label start;
167 bind(&start);
168#endif
169
170 if (rmode == RelocInfo::CODE_TARGET && !ast_id.IsNone()) {
171 SetRecordedAstId(ast_id);
172 rmode = RelocInfo::CODE_TARGET_WITH_ID;
173 }
174 AllowDeferredHandleDereference using_raw_address;
175 Call(reinterpret_cast<Address>(code.location()), rmode, cond);
176 DCHECK_EQ(expected_size, SizeOfCodeGeneratedSince(&start));
177}
178
179
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000180void MacroAssembler::Drop(int count) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400181 if (count > 0) {
182 Add(sp, sp, count * kPointerSize, r0);
183 }
184}
185
186
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400187void MacroAssembler::Call(Label* target) { b(target, SetLK); }
188
189
190void MacroAssembler::Push(Handle<Object> handle) {
191 mov(r0, Operand(handle));
192 push(r0);
193}
194
195
196void MacroAssembler::Move(Register dst, Handle<Object> value) {
197 AllowDeferredHandleDereference smi_check;
198 if (value->IsSmi()) {
199 LoadSmiLiteral(dst, reinterpret_cast<Smi*>(*value));
200 } else {
201 DCHECK(value->IsHeapObject());
202 if (isolate()->heap()->InNewSpace(*value)) {
203 Handle<Cell> cell = isolate()->factory()->NewCell(value);
204 mov(dst, Operand(cell));
205 LoadP(dst, FieldMemOperand(dst, Cell::kValueOffset));
206 } else {
207 mov(dst, Operand(value));
208 }
209 }
210}
211
212
213void MacroAssembler::Move(Register dst, Register src, Condition cond) {
214 DCHECK(cond == al);
215 if (!dst.is(src)) {
216 mr(dst, src);
217 }
218}
219
220
221void MacroAssembler::Move(DoubleRegister dst, DoubleRegister src) {
222 if (!dst.is(src)) {
223 fmr(dst, src);
224 }
225}
226
227
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000228void MacroAssembler::MultiPush(RegList regs, Register location) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400229 int16_t num_to_push = NumberOfBitsSet(regs);
230 int16_t stack_offset = num_to_push * kPointerSize;
231
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000232 subi(location, location, Operand(stack_offset));
233 for (int16_t i = Register::kNumRegisters - 1; i >= 0; i--) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400234 if ((regs & (1 << i)) != 0) {
235 stack_offset -= kPointerSize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000236 StoreP(ToRegister(i), MemOperand(location, stack_offset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400237 }
238 }
239}
240
241
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242void MacroAssembler::MultiPop(RegList regs, Register location) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400243 int16_t stack_offset = 0;
244
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000245 for (int16_t i = 0; i < Register::kNumRegisters; i++) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400246 if ((regs & (1 << i)) != 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000247 LoadP(ToRegister(i), MemOperand(location, stack_offset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400248 stack_offset += kPointerSize;
249 }
250 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000251 addi(location, location, Operand(stack_offset));
252}
253
254
255void MacroAssembler::MultiPushDoubles(RegList dregs, Register location) {
256 int16_t num_to_push = NumberOfBitsSet(dregs);
257 int16_t stack_offset = num_to_push * kDoubleSize;
258
259 subi(location, location, Operand(stack_offset));
260 for (int16_t i = DoubleRegister::kNumRegisters - 1; i >= 0; i--) {
261 if ((dregs & (1 << i)) != 0) {
262 DoubleRegister dreg = DoubleRegister::from_code(i);
263 stack_offset -= kDoubleSize;
264 stfd(dreg, MemOperand(location, stack_offset));
265 }
266 }
267}
268
269
270void MacroAssembler::MultiPopDoubles(RegList dregs, Register location) {
271 int16_t stack_offset = 0;
272
273 for (int16_t i = 0; i < DoubleRegister::kNumRegisters; i++) {
274 if ((dregs & (1 << i)) != 0) {
275 DoubleRegister dreg = DoubleRegister::from_code(i);
276 lfd(dreg, MemOperand(location, stack_offset));
277 stack_offset += kDoubleSize;
278 }
279 }
280 addi(location, location, Operand(stack_offset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400281}
282
283
284void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index,
285 Condition cond) {
286 DCHECK(cond == al);
287 LoadP(destination, MemOperand(kRootRegister, index << kPointerSizeLog2), r0);
288}
289
290
291void MacroAssembler::StoreRoot(Register source, Heap::RootListIndex index,
292 Condition cond) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000293 DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400294 DCHECK(cond == al);
295 StoreP(source, MemOperand(kRootRegister, index << kPointerSizeLog2), r0);
296}
297
298
299void MacroAssembler::InNewSpace(Register object, Register scratch,
300 Condition cond, Label* branch) {
301 // N.B. scratch may be same register as object
302 DCHECK(cond == eq || cond == ne);
303 mov(r0, Operand(ExternalReference::new_space_mask(isolate())));
304 and_(scratch, object, r0);
305 mov(r0, Operand(ExternalReference::new_space_start(isolate())));
306 cmp(scratch, r0);
307 b(cond, branch);
308}
309
310
311void MacroAssembler::RecordWriteField(
312 Register object, int offset, Register value, Register dst,
313 LinkRegisterStatus lr_status, SaveFPRegsMode save_fp,
314 RememberedSetAction remembered_set_action, SmiCheck smi_check,
315 PointersToHereCheck pointers_to_here_check_for_value) {
316 // First, check if a write barrier is even needed. The tests below
317 // catch stores of Smis.
318 Label done;
319
320 // Skip barrier if writing a smi.
321 if (smi_check == INLINE_SMI_CHECK) {
322 JumpIfSmi(value, &done);
323 }
324
325 // Although the object register is tagged, the offset is relative to the start
326 // of the object, so so offset must be a multiple of kPointerSize.
327 DCHECK(IsAligned(offset, kPointerSize));
328
329 Add(dst, object, offset - kHeapObjectTag, r0);
330 if (emit_debug_code()) {
331 Label ok;
332 andi(r0, dst, Operand((1 << kPointerSizeLog2) - 1));
333 beq(&ok, cr0);
334 stop("Unaligned cell in write barrier");
335 bind(&ok);
336 }
337
338 RecordWrite(object, dst, value, lr_status, save_fp, remembered_set_action,
339 OMIT_SMI_CHECK, pointers_to_here_check_for_value);
340
341 bind(&done);
342
343 // Clobber clobbered input registers when running with the debug-code flag
344 // turned on to provoke errors.
345 if (emit_debug_code()) {
346 mov(value, Operand(bit_cast<intptr_t>(kZapValue + 4)));
347 mov(dst, Operand(bit_cast<intptr_t>(kZapValue + 8)));
348 }
349}
350
351
352// Will clobber 4 registers: object, map, dst, ip. The
353// register 'object' contains a heap object pointer.
354void MacroAssembler::RecordWriteForMap(Register object, Register map,
355 Register dst,
356 LinkRegisterStatus lr_status,
357 SaveFPRegsMode fp_mode) {
358 if (emit_debug_code()) {
359 LoadP(dst, FieldMemOperand(map, HeapObject::kMapOffset));
360 Cmpi(dst, Operand(isolate()->factory()->meta_map()), r0);
361 Check(eq, kWrongAddressOrValuePassedToRecordWrite);
362 }
363
364 if (!FLAG_incremental_marking) {
365 return;
366 }
367
368 if (emit_debug_code()) {
369 LoadP(ip, FieldMemOperand(object, HeapObject::kMapOffset));
370 cmp(ip, map);
371 Check(eq, kWrongAddressOrValuePassedToRecordWrite);
372 }
373
374 Label done;
375
376 // A single check of the map's pages interesting flag suffices, since it is
377 // only set during incremental collection, and then it's also guaranteed that
378 // the from object's page's interesting flag is also set. This optimization
379 // relies on the fact that maps can never be in new space.
380 CheckPageFlag(map,
381 map, // Used as scratch.
382 MemoryChunk::kPointersToHereAreInterestingMask, eq, &done);
383
384 addi(dst, object, Operand(HeapObject::kMapOffset - kHeapObjectTag));
385 if (emit_debug_code()) {
386 Label ok;
387 andi(r0, dst, Operand((1 << kPointerSizeLog2) - 1));
388 beq(&ok, cr0);
389 stop("Unaligned cell in write barrier");
390 bind(&ok);
391 }
392
393 // Record the actual write.
394 if (lr_status == kLRHasNotBeenSaved) {
395 mflr(r0);
396 push(r0);
397 }
398 RecordWriteStub stub(isolate(), object, map, dst, OMIT_REMEMBERED_SET,
399 fp_mode);
400 CallStub(&stub);
401 if (lr_status == kLRHasNotBeenSaved) {
402 pop(r0);
403 mtlr(r0);
404 }
405
406 bind(&done);
407
408 // Count number of write barriers in generated code.
409 isolate()->counters()->write_barriers_static()->Increment();
410 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip, dst);
411
412 // Clobber clobbered registers when running with the debug-code flag
413 // turned on to provoke errors.
414 if (emit_debug_code()) {
415 mov(dst, Operand(bit_cast<intptr_t>(kZapValue + 12)));
416 mov(map, Operand(bit_cast<intptr_t>(kZapValue + 16)));
417 }
418}
419
420
421// Will clobber 4 registers: object, address, scratch, ip. The
422// register 'object' contains a heap object pointer. The heap object
423// tag is shifted away.
424void MacroAssembler::RecordWrite(
425 Register object, Register address, Register value,
426 LinkRegisterStatus lr_status, SaveFPRegsMode fp_mode,
427 RememberedSetAction remembered_set_action, SmiCheck smi_check,
428 PointersToHereCheck pointers_to_here_check_for_value) {
429 DCHECK(!object.is(value));
430 if (emit_debug_code()) {
431 LoadP(r0, MemOperand(address));
432 cmp(r0, value);
433 Check(eq, kWrongAddressOrValuePassedToRecordWrite);
434 }
435
436 if (remembered_set_action == OMIT_REMEMBERED_SET &&
437 !FLAG_incremental_marking) {
438 return;
439 }
440
441 // First, check if a write barrier is even needed. The tests below
442 // catch stores of smis and stores into the young generation.
443 Label done;
444
445 if (smi_check == INLINE_SMI_CHECK) {
446 JumpIfSmi(value, &done);
447 }
448
449 if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) {
450 CheckPageFlag(value,
451 value, // Used as scratch.
452 MemoryChunk::kPointersToHereAreInterestingMask, eq, &done);
453 }
454 CheckPageFlag(object,
455 value, // Used as scratch.
456 MemoryChunk::kPointersFromHereAreInterestingMask, eq, &done);
457
458 // Record the actual write.
459 if (lr_status == kLRHasNotBeenSaved) {
460 mflr(r0);
461 push(r0);
462 }
463 RecordWriteStub stub(isolate(), object, value, address, remembered_set_action,
464 fp_mode);
465 CallStub(&stub);
466 if (lr_status == kLRHasNotBeenSaved) {
467 pop(r0);
468 mtlr(r0);
469 }
470
471 bind(&done);
472
473 // Count number of write barriers in generated code.
474 isolate()->counters()->write_barriers_static()->Increment();
475 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip,
476 value);
477
478 // Clobber clobbered registers when running with the debug-code flag
479 // turned on to provoke errors.
480 if (emit_debug_code()) {
481 mov(address, Operand(bit_cast<intptr_t>(kZapValue + 12)));
482 mov(value, Operand(bit_cast<intptr_t>(kZapValue + 16)));
483 }
484}
485
486
487void MacroAssembler::RememberedSetHelper(Register object, // For debug tests.
488 Register address, Register scratch,
489 SaveFPRegsMode fp_mode,
490 RememberedSetFinalAction and_then) {
491 Label done;
492 if (emit_debug_code()) {
493 Label ok;
494 JumpIfNotInNewSpace(object, scratch, &ok);
495 stop("Remembered set pointer is in new space");
496 bind(&ok);
497 }
498 // Load store buffer top.
499 ExternalReference store_buffer =
500 ExternalReference::store_buffer_top(isolate());
501 mov(ip, Operand(store_buffer));
502 LoadP(scratch, MemOperand(ip));
503 // Store pointer to buffer and increment buffer top.
504 StoreP(address, MemOperand(scratch));
505 addi(scratch, scratch, Operand(kPointerSize));
506 // Write back new top of buffer.
507 StoreP(scratch, MemOperand(ip));
508 // Call stub on end of buffer.
509 // Check for end of buffer.
510 mov(r0, Operand(StoreBuffer::kStoreBufferOverflowBit));
511 and_(r0, scratch, r0, SetRC);
512
513 if (and_then == kFallThroughAtEnd) {
514 beq(&done, cr0);
515 } else {
516 DCHECK(and_then == kReturnAtEnd);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000517 Ret(eq, cr0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400518 }
519 mflr(r0);
520 push(r0);
521 StoreBufferOverflowStub store_buffer_overflow(isolate(), fp_mode);
522 CallStub(&store_buffer_overflow);
523 pop(r0);
524 mtlr(r0);
525 bind(&done);
526 if (and_then == kReturnAtEnd) {
527 Ret();
528 }
529}
530
531
532void MacroAssembler::PushFixedFrame(Register marker_reg) {
533 mflr(r0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000534 if (FLAG_enable_embedded_constant_pool) {
535 if (marker_reg.is_valid()) {
536 Push(r0, fp, kConstantPoolRegister, cp, marker_reg);
537 } else {
538 Push(r0, fp, kConstantPoolRegister, cp);
539 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400540 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000541 if (marker_reg.is_valid()) {
542 Push(r0, fp, cp, marker_reg);
543 } else {
544 Push(r0, fp, cp);
545 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400546 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400547}
548
549
550void MacroAssembler::PopFixedFrame(Register marker_reg) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000551 if (FLAG_enable_embedded_constant_pool) {
552 if (marker_reg.is_valid()) {
553 Pop(r0, fp, kConstantPoolRegister, cp, marker_reg);
554 } else {
555 Pop(r0, fp, kConstantPoolRegister, cp);
556 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400557 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000558 if (marker_reg.is_valid()) {
559 Pop(r0, fp, cp, marker_reg);
560 } else {
561 Pop(r0, fp, cp);
562 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400563 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400564 mtlr(r0);
565}
566
567
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000568const RegList MacroAssembler::kSafepointSavedRegisters = Register::kAllocatable;
569const int MacroAssembler::kNumSafepointSavedRegisters =
570 Register::kNumAllocatable;
571
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400572// Push and pop all registers that can hold pointers.
573void MacroAssembler::PushSafepointRegisters() {
574 // Safepoints expect a block of kNumSafepointRegisters values on the
575 // stack, so adjust the stack for unsaved registers.
576 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
577 DCHECK(num_unsaved >= 0);
578 if (num_unsaved > 0) {
579 subi(sp, sp, Operand(num_unsaved * kPointerSize));
580 }
581 MultiPush(kSafepointSavedRegisters);
582}
583
584
585void MacroAssembler::PopSafepointRegisters() {
586 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
587 MultiPop(kSafepointSavedRegisters);
588 if (num_unsaved > 0) {
589 addi(sp, sp, Operand(num_unsaved * kPointerSize));
590 }
591}
592
593
594void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) {
595 StoreP(src, SafepointRegisterSlot(dst));
596}
597
598
599void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) {
600 LoadP(dst, SafepointRegisterSlot(src));
601}
602
603
604int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
605 // The registers are pushed starting with the highest encoding,
606 // which means that lowest encodings are closest to the stack pointer.
607 RegList regs = kSafepointSavedRegisters;
608 int index = 0;
609
610 DCHECK(reg_code >= 0 && reg_code < kNumRegisters);
611
612 for (int16_t i = 0; i < reg_code; i++) {
613 if ((regs & (1 << i)) != 0) {
614 index++;
615 }
616 }
617
618 return index;
619}
620
621
622MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) {
623 return MemOperand(sp, SafepointRegisterStackIndex(reg.code()) * kPointerSize);
624}
625
626
627MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) {
628 // General purpose registers are pushed last on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000629 const RegisterConfiguration* config =
630 RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT);
631 int doubles_size = config->num_allocatable_double_registers() * kDoubleSize;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400632 int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize;
633 return MemOperand(sp, doubles_size + register_offset);
634}
635
636
637void MacroAssembler::CanonicalizeNaN(const DoubleRegister dst,
638 const DoubleRegister src) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000639 // Turn potential sNaN into qNaN.
640 fsub(dst, src, kDoubleRegZero);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400641}
642
643
644void MacroAssembler::ConvertIntToDouble(Register src,
645 DoubleRegister double_dst) {
646 MovIntToDouble(double_dst, src, r0);
647 fcfid(double_dst, double_dst);
648}
649
650
651void MacroAssembler::ConvertUnsignedIntToDouble(Register src,
652 DoubleRegister double_dst) {
653 MovUnsignedIntToDouble(double_dst, src, r0);
654 fcfid(double_dst, double_dst);
655}
656
657
658void MacroAssembler::ConvertIntToFloat(const DoubleRegister dst,
659 const Register src,
660 const Register int_scratch) {
661 MovIntToDouble(dst, src, int_scratch);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000662 fcfids(dst, dst);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400663}
664
665
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000666#if V8_TARGET_ARCH_PPC64
667void MacroAssembler::ConvertInt64ToDouble(Register src,
668 DoubleRegister double_dst) {
669 MovInt64ToDouble(double_dst, src);
670 fcfid(double_dst, double_dst);
671}
672
673
674void MacroAssembler::ConvertUnsignedInt64ToFloat(Register src,
675 DoubleRegister double_dst) {
676 MovInt64ToDouble(double_dst, src);
677 fcfidus(double_dst, double_dst);
678}
679
680
681void MacroAssembler::ConvertUnsignedInt64ToDouble(Register src,
682 DoubleRegister double_dst) {
683 MovInt64ToDouble(double_dst, src);
684 fcfidu(double_dst, double_dst);
685}
686
687
688void MacroAssembler::ConvertInt64ToFloat(Register src,
689 DoubleRegister double_dst) {
690 MovInt64ToDouble(double_dst, src);
691 fcfids(double_dst, double_dst);
692}
693#endif
694
695
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400696void MacroAssembler::ConvertDoubleToInt64(const DoubleRegister double_input,
697#if !V8_TARGET_ARCH_PPC64
698 const Register dst_hi,
699#endif
700 const Register dst,
701 const DoubleRegister double_dst,
702 FPRoundingMode rounding_mode) {
703 if (rounding_mode == kRoundToZero) {
704 fctidz(double_dst, double_input);
705 } else {
706 SetRoundingMode(rounding_mode);
707 fctid(double_dst, double_input);
708 ResetRoundingMode();
709 }
710
711 MovDoubleToInt64(
712#if !V8_TARGET_ARCH_PPC64
713 dst_hi,
714#endif
715 dst, double_dst);
716}
717
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000718#if V8_TARGET_ARCH_PPC64
719void MacroAssembler::ConvertDoubleToUnsignedInt64(
720 const DoubleRegister double_input, const Register dst,
721 const DoubleRegister double_dst, FPRoundingMode rounding_mode) {
722 if (rounding_mode == kRoundToZero) {
723 fctiduz(double_dst, double_input);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400724 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000725 SetRoundingMode(rounding_mode);
726 fctidu(double_dst, double_input);
727 ResetRoundingMode();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400728 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000729
730 MovDoubleToInt64(dst, double_dst);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400731}
732#endif
733
734
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000735void MacroAssembler::LoadConstantPoolPointerRegisterFromCodeTargetAddress(
736 Register code_target_address) {
737 lwz(kConstantPoolRegister,
738 MemOperand(code_target_address,
739 Code::kConstantPoolOffset - Code::kHeaderSize));
740 add(kConstantPoolRegister, kConstantPoolRegister, code_target_address);
741}
742
743
744void MacroAssembler::LoadConstantPoolPointerRegister(Register base,
745 int code_start_delta) {
746 add_label_offset(kConstantPoolRegister, base, ConstantPoolPosition(),
747 code_start_delta);
748}
749
750
751void MacroAssembler::LoadConstantPoolPointerRegister() {
752 mov_label_addr(kConstantPoolRegister, ConstantPoolPosition());
753}
754
755
756void MacroAssembler::StubPrologue(Register base, int prologue_offset) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400757 LoadSmiLiteral(r11, Smi::FromInt(StackFrame::STUB));
758 PushFixedFrame(r11);
759 // Adjust FP to point to saved FP.
760 addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000761 if (FLAG_enable_embedded_constant_pool) {
762 if (!base.is(no_reg)) {
763 // base contains prologue address
764 LoadConstantPoolPointerRegister(base, -prologue_offset);
765 } else {
766 LoadConstantPoolPointerRegister();
767 }
768 set_constant_pool_available(true);
769 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400770}
771
772
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000773void MacroAssembler::Prologue(bool code_pre_aging, Register base,
774 int prologue_offset) {
775 DCHECK(!base.is(no_reg));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400776 {
777 PredictableCodeSizeScope predictible_code_size_scope(
778 this, kNoCodeAgeSequenceLength);
779 Assembler::BlockTrampolinePoolScope block_trampoline_pool(this);
780 // The following instructions must remain together and unmodified
781 // for code aging to work properly.
782 if (code_pre_aging) {
783 // Pre-age the code.
784 // This matches the code found in PatchPlatformCodeAge()
785 Code* stub = Code::GetPreAgedCodeAgeStub(isolate());
786 intptr_t target = reinterpret_cast<intptr_t>(stub->instruction_start());
787 // Don't use Call -- we need to preserve ip and lr
788 nop(); // marker to detect sequence (see IsOld)
789 mov(r3, Operand(target));
790 Jump(r3);
791 for (int i = 0; i < kCodeAgingSequenceNops; i++) {
792 nop();
793 }
794 } else {
795 // This matches the code found in GetNoCodeAgeSequence()
796 PushFixedFrame(r4);
797 // Adjust fp to point to saved fp.
798 addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
799 for (int i = 0; i < kNoCodeAgeSequenceNops; i++) {
800 nop();
801 }
802 }
803 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000804 if (FLAG_enable_embedded_constant_pool) {
805 // base contains prologue address
806 LoadConstantPoolPointerRegister(base, -prologue_offset);
807 set_constant_pool_available(true);
808 }
809}
810
811
812void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) {
813 LoadP(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
814 LoadP(vector, FieldMemOperand(vector, JSFunction::kSharedFunctionInfoOffset));
815 LoadP(vector,
816 FieldMemOperand(vector, SharedFunctionInfo::kFeedbackVectorOffset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400817}
818
819
820void MacroAssembler::EnterFrame(StackFrame::Type type,
821 bool load_constant_pool_pointer_reg) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000822 if (FLAG_enable_embedded_constant_pool && load_constant_pool_pointer_reg) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400823 PushFixedFrame();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400824 // This path should not rely on ip containing code entry.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000825 LoadConstantPoolPointerRegister();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400826 LoadSmiLiteral(ip, Smi::FromInt(type));
827 push(ip);
828 } else {
829 LoadSmiLiteral(ip, Smi::FromInt(type));
830 PushFixedFrame(ip);
831 }
832 // Adjust FP to point to saved FP.
833 addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
834
835 mov(r0, Operand(CodeObject()));
836 push(r0);
837}
838
839
840int MacroAssembler::LeaveFrame(StackFrame::Type type, int stack_adjustment) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400841 ConstantPoolUnavailableScope constant_pool_unavailable(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400842 // r3: preserved
843 // r4: preserved
844 // r5: preserved
845
846 // Drop the execution stack down to the frame pointer and restore
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000847 // the caller's state.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400848 int frame_ends;
849 LoadP(r0, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
850 LoadP(ip, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000851 if (FLAG_enable_embedded_constant_pool) {
852 const int exitOffset = ExitFrameConstants::kConstantPoolOffset;
853 const int standardOffset = StandardFrameConstants::kConstantPoolOffset;
854 const int offset =
855 ((type == StackFrame::EXIT) ? exitOffset : standardOffset);
856 LoadP(kConstantPoolRegister, MemOperand(fp, offset));
857 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400858 mtlr(r0);
859 frame_ends = pc_offset();
860 Add(sp, fp, StandardFrameConstants::kCallerSPOffset + stack_adjustment, r0);
861 mr(fp, ip);
862 return frame_ends;
863}
864
865
866// ExitFrame layout (probably wrongish.. needs updating)
867//
868// SP -> previousSP
869// LK reserved
870// code
871// sp_on_exit (for debug?)
872// oldSP->prev SP
873// LK
874// <parameters on stack>
875
876// Prior to calling EnterExitFrame, we've got a bunch of parameters
877// on the stack that we need to wrap a real frame around.. so first
878// we reserve a slot for LK and push the previous SP which is captured
879// in the fp register (r31)
880// Then - we buy a new frame
881
882void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) {
883 // Set up the frame structure on the stack.
884 DCHECK_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement);
885 DCHECK_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset);
886 DCHECK_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset);
887 DCHECK(stack_space > 0);
888
889 // This is an opportunity to build a frame to wrap
890 // all of the pushes that have happened inside of V8
891 // since we were called from C code
892
893 // replicate ARM frame - TODO make this more closely follow PPC ABI
894 mflr(r0);
895 Push(r0, fp);
896 mr(fp, sp);
897 // Reserve room for saved entry sp and code object.
898 subi(sp, sp, Operand(ExitFrameConstants::kFrameSize));
899
900 if (emit_debug_code()) {
901 li(r8, Operand::Zero());
902 StoreP(r8, MemOperand(fp, ExitFrameConstants::kSPOffset));
903 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000904 if (FLAG_enable_embedded_constant_pool) {
905 StoreP(kConstantPoolRegister,
906 MemOperand(fp, ExitFrameConstants::kConstantPoolOffset));
907 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400908 mov(r8, Operand(CodeObject()));
909 StoreP(r8, MemOperand(fp, ExitFrameConstants::kCodeOffset));
910
911 // Save the frame pointer and the context in top.
912 mov(r8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
913 StoreP(fp, MemOperand(r8));
914 mov(r8, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
915 StoreP(cp, MemOperand(r8));
916
917 // Optionally save all volatile double registers.
918 if (save_doubles) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000919 MultiPushDoubles(kCallerSavedDoubles);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400920 // Note that d0 will be accessible at
921 // fp - ExitFrameConstants::kFrameSize -
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000922 // kNumCallerSavedDoubles * kDoubleSize,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400923 // since the sp slot and code slot were pushed after the fp.
924 }
925
926 addi(sp, sp, Operand(-stack_space * kPointerSize));
927
928 // Allocate and align the frame preparing for calling the runtime
929 // function.
930 const int frame_alignment = ActivationFrameAlignment();
931 if (frame_alignment > kPointerSize) {
932 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
933 ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
934 }
935 li(r0, Operand::Zero());
936 StorePU(r0, MemOperand(sp, -kNumRequiredStackFrameSlots * kPointerSize));
937
938 // Set the exit frame sp value to point just before the return address
939 // location.
940 addi(r8, sp, Operand((kStackFrameExtraParamSlot + 1) * kPointerSize));
941 StoreP(r8, MemOperand(fp, ExitFrameConstants::kSPOffset));
942}
943
944
945void MacroAssembler::InitializeNewString(Register string, Register length,
946 Heap::RootListIndex map_index,
947 Register scratch1, Register scratch2) {
948 SmiTag(scratch1, length);
949 LoadRoot(scratch2, map_index);
950 StoreP(scratch1, FieldMemOperand(string, String::kLengthOffset), r0);
951 li(scratch1, Operand(String::kEmptyHashField));
952 StoreP(scratch2, FieldMemOperand(string, HeapObject::kMapOffset), r0);
953 StoreP(scratch1, FieldMemOperand(string, String::kHashFieldSlot), r0);
954}
955
956
957int MacroAssembler::ActivationFrameAlignment() {
958#if !defined(USE_SIMULATOR)
959 // Running on the real platform. Use the alignment as mandated by the local
960 // environment.
961 // Note: This will break if we ever start generating snapshots on one PPC
962 // platform for another PPC platform with a different alignment.
963 return base::OS::ActivationFrameAlignment();
964#else // Simulated
965 // If we are using the simulator then we should always align to the expected
966 // alignment. As the simulator is used to generate snapshots we do not know
967 // if the target platform will need alignment, so this is controlled from a
968 // flag.
969 return FLAG_sim_stack_alignment;
970#endif
971}
972
973
974void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000975 bool restore_context,
976 bool argument_count_is_length) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400977 ConstantPoolUnavailableScope constant_pool_unavailable(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400978 // Optionally restore all double registers.
979 if (save_doubles) {
980 // Calculate the stack location of the saved doubles and restore them.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000981 const int kNumRegs = kNumCallerSavedDoubles;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400982 const int offset =
983 (ExitFrameConstants::kFrameSize + kNumRegs * kDoubleSize);
984 addi(r6, fp, Operand(-offset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000985 MultiPopDoubles(kCallerSavedDoubles, r6);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400986 }
987
988 // Clear top frame.
989 li(r6, Operand::Zero());
990 mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
991 StoreP(r6, MemOperand(ip));
992
993 // Restore current context from top and clear it in debug mode.
994 if (restore_context) {
995 mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
996 LoadP(cp, MemOperand(ip));
997 }
998#ifdef DEBUG
999 mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
1000 StoreP(r6, MemOperand(ip));
1001#endif
1002
1003 // Tear down the exit frame, pop the arguments, and return.
1004 LeaveFrame(StackFrame::EXIT);
1005
1006 if (argument_count.is_valid()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001007 if (!argument_count_is_length) {
1008 ShiftLeftImm(argument_count, argument_count, Operand(kPointerSizeLog2));
1009 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001010 add(sp, sp, argument_count);
1011 }
1012}
1013
1014
1015void MacroAssembler::MovFromFloatResult(const DoubleRegister dst) {
1016 Move(dst, d1);
1017}
1018
1019
1020void MacroAssembler::MovFromFloatParameter(const DoubleRegister dst) {
1021 Move(dst, d1);
1022}
1023
1024
1025void MacroAssembler::InvokePrologue(const ParameterCount& expected,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001026 const ParameterCount& actual, Label* done,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001027 bool* definitely_mismatches,
1028 InvokeFlag flag,
1029 const CallWrapper& call_wrapper) {
1030 bool definitely_matches = false;
1031 *definitely_mismatches = false;
1032 Label regular_invoke;
1033
1034 // Check whether the expected and actual arguments count match. If not,
1035 // setup registers according to contract with ArgumentsAdaptorTrampoline:
1036 // r3: actual arguments count
1037 // r4: function (passed through to callee)
1038 // r5: expected arguments count
1039
1040 // The code below is made a lot easier because the calling code already sets
1041 // up actual and expected registers according to the contract if values are
1042 // passed in registers.
1043
1044 // ARM has some sanity checks as per below, considering add them for PPC
1045 // DCHECK(actual.is_immediate() || actual.reg().is(r3));
1046 // DCHECK(expected.is_immediate() || expected.reg().is(r5));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001047
1048 if (expected.is_immediate()) {
1049 DCHECK(actual.is_immediate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001050 mov(r3, Operand(actual.immediate()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001051 if (expected.immediate() == actual.immediate()) {
1052 definitely_matches = true;
1053 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001054 const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
1055 if (expected.immediate() == sentinel) {
1056 // Don't worry about adapting arguments for builtins that
1057 // don't want that done. Skip adaption code by making it look
1058 // like we have a match between expected and actual number of
1059 // arguments.
1060 definitely_matches = true;
1061 } else {
1062 *definitely_mismatches = true;
1063 mov(r5, Operand(expected.immediate()));
1064 }
1065 }
1066 } else {
1067 if (actual.is_immediate()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001068 mov(r3, Operand(actual.immediate()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001069 cmpi(expected.reg(), Operand(actual.immediate()));
1070 beq(&regular_invoke);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001071 } else {
1072 cmp(expected.reg(), actual.reg());
1073 beq(&regular_invoke);
1074 }
1075 }
1076
1077 if (!definitely_matches) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001078 Handle<Code> adaptor = isolate()->builtins()->ArgumentsAdaptorTrampoline();
1079 if (flag == CALL_FUNCTION) {
1080 call_wrapper.BeforeCall(CallSize(adaptor));
1081 Call(adaptor);
1082 call_wrapper.AfterCall();
1083 if (!*definitely_mismatches) {
1084 b(done);
1085 }
1086 } else {
1087 Jump(adaptor, RelocInfo::CODE_TARGET);
1088 }
1089 bind(&regular_invoke);
1090 }
1091}
1092
1093
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001094void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target,
1095 const ParameterCount& expected,
1096 const ParameterCount& actual) {
1097 Label skip_flooding;
1098 ExternalReference step_in_enabled =
1099 ExternalReference::debug_step_in_enabled_address(isolate());
1100 mov(r7, Operand(step_in_enabled));
1101 lbz(r7, MemOperand(r7));
1102 cmpi(r7, Operand::Zero());
1103 beq(&skip_flooding);
1104 {
1105 FrameScope frame(this,
1106 has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
1107 if (expected.is_reg()) {
1108 SmiTag(expected.reg());
1109 Push(expected.reg());
1110 }
1111 if (actual.is_reg()) {
1112 SmiTag(actual.reg());
1113 Push(actual.reg());
1114 }
1115 if (new_target.is_valid()) {
1116 Push(new_target);
1117 }
1118 Push(fun, fun);
1119 CallRuntime(Runtime::kDebugPrepareStepInIfStepping, 1);
1120 Pop(fun);
1121 if (new_target.is_valid()) {
1122 Pop(new_target);
1123 }
1124 if (actual.is_reg()) {
1125 Pop(actual.reg());
1126 SmiUntag(actual.reg());
1127 }
1128 if (expected.is_reg()) {
1129 Pop(expected.reg());
1130 SmiUntag(expected.reg());
1131 }
1132 }
1133 bind(&skip_flooding);
1134}
1135
1136
1137void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
1138 const ParameterCount& expected,
1139 const ParameterCount& actual,
1140 InvokeFlag flag,
1141 const CallWrapper& call_wrapper) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001142 // You can't call a function without a valid frame.
1143 DCHECK(flag == JUMP_FUNCTION || has_frame());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001144 DCHECK(function.is(r4));
1145 DCHECK_IMPLIES(new_target.is_valid(), new_target.is(r6));
1146
1147 if (call_wrapper.NeedsDebugStepCheck()) {
1148 FloodFunctionIfStepping(function, new_target, expected, actual);
1149 }
1150
1151 // Clear the new.target register if not given.
1152 if (!new_target.is_valid()) {
1153 LoadRoot(r6, Heap::kUndefinedValueRootIndex);
1154 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001155
1156 Label done;
1157 bool definitely_mismatches = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001158 InvokePrologue(expected, actual, &done, &definitely_mismatches, flag,
1159 call_wrapper);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001160 if (!definitely_mismatches) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001161 // We call indirectly through the code field in the function to
1162 // allow recompilation to take effect without changing any of the
1163 // call sites.
1164 Register code = ip;
1165 LoadP(code, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001166 if (flag == CALL_FUNCTION) {
1167 call_wrapper.BeforeCall(CallSize(code));
1168 CallJSEntry(code);
1169 call_wrapper.AfterCall();
1170 } else {
1171 DCHECK(flag == JUMP_FUNCTION);
1172 JumpToJSEntry(code);
1173 }
1174
1175 // Continue here if InvokePrologue does handle the invocation due to
1176 // mismatched parameter counts.
1177 bind(&done);
1178 }
1179}
1180
1181
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001182void MacroAssembler::InvokeFunction(Register fun, Register new_target,
1183 const ParameterCount& actual,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001184 InvokeFlag flag,
1185 const CallWrapper& call_wrapper) {
1186 // You can't call a function without a valid frame.
1187 DCHECK(flag == JUMP_FUNCTION || has_frame());
1188
1189 // Contract with called JS functions requires that function is passed in r4.
1190 DCHECK(fun.is(r4));
1191
1192 Register expected_reg = r5;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001193 Register temp_reg = r7;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001194
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001195 LoadP(temp_reg, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001196 LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
1197 LoadWordArith(expected_reg,
1198 FieldMemOperand(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001199 temp_reg, SharedFunctionInfo::kFormalParameterCountOffset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001200#if !defined(V8_TARGET_ARCH_PPC64)
1201 SmiUntag(expected_reg);
1202#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001203
1204 ParameterCount expected(expected_reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001205 InvokeFunctionCode(fun, new_target, expected, actual, flag, call_wrapper);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001206}
1207
1208
1209void MacroAssembler::InvokeFunction(Register function,
1210 const ParameterCount& expected,
1211 const ParameterCount& actual,
1212 InvokeFlag flag,
1213 const CallWrapper& call_wrapper) {
1214 // You can't call a function without a valid frame.
1215 DCHECK(flag == JUMP_FUNCTION || has_frame());
1216
1217 // Contract with called JS functions requires that function is passed in r4.
1218 DCHECK(function.is(r4));
1219
1220 // Get the function and setup the context.
1221 LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
1222
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001223 InvokeFunctionCode(r4, no_reg, expected, actual, flag, call_wrapper);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001224}
1225
1226
1227void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
1228 const ParameterCount& expected,
1229 const ParameterCount& actual,
1230 InvokeFlag flag,
1231 const CallWrapper& call_wrapper) {
1232 Move(r4, function);
1233 InvokeFunction(r4, expected, actual, flag, call_wrapper);
1234}
1235
1236
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001237void MacroAssembler::IsObjectJSStringType(Register object, Register scratch,
1238 Label* fail) {
1239 DCHECK(kNotStringTag != 0);
1240
1241 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
1242 lbz(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
1243 andi(r0, scratch, Operand(kIsNotStringMask));
1244 bne(fail, cr0);
1245}
1246
1247
1248void MacroAssembler::IsObjectNameType(Register object, Register scratch,
1249 Label* fail) {
1250 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
1251 lbz(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
1252 cmpi(scratch, Operand(LAST_NAME_TYPE));
1253 bgt(fail);
1254}
1255
1256
1257void MacroAssembler::DebugBreak() {
1258 li(r3, Operand::Zero());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001259 mov(r4,
1260 Operand(ExternalReference(Runtime::kHandleDebuggerStatement, isolate())));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001261 CEntryStub ces(isolate(), 1);
1262 DCHECK(AllowThisStubCall(&ces));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001263 Call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001264}
1265
1266
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001267void MacroAssembler::PushStackHandler() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001268 // Adjust this code if not the case.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001269 STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001270 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001271
1272 // Link the current handler as the next handler.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001273 // Preserve r3-r7.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001274 mov(r8, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
1275 LoadP(r0, MemOperand(r8));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001276 push(r0);
1277
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001278 // Set this new handler as the current one.
1279 StoreP(sp, MemOperand(r8));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001280}
1281
1282
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001283void MacroAssembler::PopStackHandler() {
1284 STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001285 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001286
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001287 pop(r4);
1288 mov(ip, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001289 StoreP(r4, MemOperand(ip));
1290}
1291
1292
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001293void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
1294 Register scratch, Label* miss) {
1295 Label same_contexts;
1296
1297 DCHECK(!holder_reg.is(scratch));
1298 DCHECK(!holder_reg.is(ip));
1299 DCHECK(!scratch.is(ip));
1300
1301 // Load current lexical context from the stack frame.
1302 LoadP(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset));
1303// In debug mode, make sure the lexical context is set.
1304#ifdef DEBUG
1305 cmpi(scratch, Operand::Zero());
1306 Check(ne, kWeShouldNotHaveAnEmptyLexicalContext);
1307#endif
1308
1309 // Load the native context of the current context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001310 LoadP(scratch, ContextMemOperand(scratch, Context::NATIVE_CONTEXT_INDEX));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001311
1312 // Check the context is a native context.
1313 if (emit_debug_code()) {
1314 // Cannot use ip as a temporary in this verification code. Due to the fact
1315 // that ip is clobbered as part of cmp with an object Operand.
1316 push(holder_reg); // Temporarily save holder on the stack.
1317 // Read the first word and compare to the native_context_map.
1318 LoadP(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset));
1319 LoadRoot(ip, Heap::kNativeContextMapRootIndex);
1320 cmp(holder_reg, ip);
1321 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext);
1322 pop(holder_reg); // Restore holder.
1323 }
1324
1325 // Check if both contexts are the same.
1326 LoadP(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
1327 cmp(scratch, ip);
1328 beq(&same_contexts);
1329
1330 // Check the context is a native context.
1331 if (emit_debug_code()) {
1332 // Cannot use ip as a temporary in this verification code. Due to the fact
1333 // that ip is clobbered as part of cmp with an object Operand.
1334 push(holder_reg); // Temporarily save holder on the stack.
1335 mr(holder_reg, ip); // Move ip to its holding place.
1336 LoadRoot(ip, Heap::kNullValueRootIndex);
1337 cmp(holder_reg, ip);
1338 Check(ne, kJSGlobalProxyContextShouldNotBeNull);
1339
1340 LoadP(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset));
1341 LoadRoot(ip, Heap::kNativeContextMapRootIndex);
1342 cmp(holder_reg, ip);
1343 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext);
1344 // Restore ip is not needed. ip is reloaded below.
1345 pop(holder_reg); // Restore holder.
1346 // Restore ip to holder's context.
1347 LoadP(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
1348 }
1349
1350 // Check that the security token in the calling global object is
1351 // compatible with the security token in the receiving global
1352 // object.
1353 int token_offset =
1354 Context::kHeaderSize + Context::SECURITY_TOKEN_INDEX * kPointerSize;
1355
1356 LoadP(scratch, FieldMemOperand(scratch, token_offset));
1357 LoadP(ip, FieldMemOperand(ip, token_offset));
1358 cmp(scratch, ip);
1359 bne(miss);
1360
1361 bind(&same_contexts);
1362}
1363
1364
1365// Compute the hash code from the untagged key. This must be kept in sync with
1366// ComputeIntegerHash in utils.h and KeyedLoadGenericStub in
1367// code-stub-hydrogen.cc
1368void MacroAssembler::GetNumberHash(Register t0, Register scratch) {
1369 // First of all we assign the hash seed to scratch.
1370 LoadRoot(scratch, Heap::kHashSeedRootIndex);
1371 SmiUntag(scratch);
1372
1373 // Xor original key with a seed.
1374 xor_(t0, t0, scratch);
1375
1376 // Compute the hash code from the untagged key. This must be kept in sync
1377 // with ComputeIntegerHash in utils.h.
1378 //
1379 // hash = ~hash + (hash << 15);
1380 notx(scratch, t0);
1381 slwi(t0, t0, Operand(15));
1382 add(t0, scratch, t0);
1383 // hash = hash ^ (hash >> 12);
1384 srwi(scratch, t0, Operand(12));
1385 xor_(t0, t0, scratch);
1386 // hash = hash + (hash << 2);
1387 slwi(scratch, t0, Operand(2));
1388 add(t0, t0, scratch);
1389 // hash = hash ^ (hash >> 4);
1390 srwi(scratch, t0, Operand(4));
1391 xor_(t0, t0, scratch);
1392 // hash = hash * 2057;
1393 mr(r0, t0);
1394 slwi(scratch, t0, Operand(3));
1395 add(t0, t0, scratch);
1396 slwi(scratch, r0, Operand(11));
1397 add(t0, t0, scratch);
1398 // hash = hash ^ (hash >> 16);
1399 srwi(scratch, t0, Operand(16));
1400 xor_(t0, t0, scratch);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001401 // hash & 0x3fffffff
1402 ExtractBitRange(t0, t0, 29, 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001403}
1404
1405
1406void MacroAssembler::LoadFromNumberDictionary(Label* miss, Register elements,
1407 Register key, Register result,
1408 Register t0, Register t1,
1409 Register t2) {
1410 // Register use:
1411 //
1412 // elements - holds the slow-case elements of the receiver on entry.
1413 // Unchanged unless 'result' is the same register.
1414 //
1415 // key - holds the smi key on entry.
1416 // Unchanged unless 'result' is the same register.
1417 //
1418 // result - holds the result on exit if the load succeeded.
1419 // Allowed to be the same as 'key' or 'result'.
1420 // Unchanged on bailout so 'key' or 'result' can be used
1421 // in further computation.
1422 //
1423 // Scratch registers:
1424 //
1425 // t0 - holds the untagged key on entry and holds the hash once computed.
1426 //
1427 // t1 - used to hold the capacity mask of the dictionary
1428 //
1429 // t2 - used for the index into the dictionary.
1430 Label done;
1431
1432 GetNumberHash(t0, t1);
1433
1434 // Compute the capacity mask.
1435 LoadP(t1, FieldMemOperand(elements, SeededNumberDictionary::kCapacityOffset));
1436 SmiUntag(t1);
1437 subi(t1, t1, Operand(1));
1438
1439 // Generate an unrolled loop that performs a few probes before giving up.
1440 for (int i = 0; i < kNumberDictionaryProbes; i++) {
1441 // Use t2 for index calculations and keep the hash intact in t0.
1442 mr(t2, t0);
1443 // Compute the masked index: (hash + i + i * i) & mask.
1444 if (i > 0) {
1445 addi(t2, t2, Operand(SeededNumberDictionary::GetProbeOffset(i)));
1446 }
1447 and_(t2, t2, t1);
1448
1449 // Scale the index by multiplying by the element size.
1450 DCHECK(SeededNumberDictionary::kEntrySize == 3);
1451 slwi(ip, t2, Operand(1));
1452 add(t2, t2, ip); // t2 = t2 * 3
1453
1454 // Check if the key is identical to the name.
1455 slwi(t2, t2, Operand(kPointerSizeLog2));
1456 add(t2, elements, t2);
1457 LoadP(ip,
1458 FieldMemOperand(t2, SeededNumberDictionary::kElementsStartOffset));
1459 cmp(key, ip);
1460 if (i != kNumberDictionaryProbes - 1) {
1461 beq(&done);
1462 } else {
1463 bne(miss);
1464 }
1465 }
1466
1467 bind(&done);
1468 // Check that the value is a field property.
1469 // t2: elements + (index * kPointerSize)
1470 const int kDetailsOffset =
1471 SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
1472 LoadP(t1, FieldMemOperand(t2, kDetailsOffset));
1473 LoadSmiLiteral(ip, Smi::FromInt(PropertyDetails::TypeField::kMask));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001474 DCHECK_EQ(DATA, 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001475 and_(r0, t1, ip, SetRC);
1476 bne(miss, cr0);
1477
1478 // Get the value at the masked, scaled index and return.
1479 const int kValueOffset =
1480 SeededNumberDictionary::kElementsStartOffset + kPointerSize;
1481 LoadP(result, FieldMemOperand(t2, kValueOffset));
1482}
1483
1484
1485void MacroAssembler::Allocate(int object_size, Register result,
1486 Register scratch1, Register scratch2,
1487 Label* gc_required, AllocationFlags flags) {
1488 DCHECK(object_size <= Page::kMaxRegularHeapObjectSize);
1489 if (!FLAG_inline_new) {
1490 if (emit_debug_code()) {
1491 // Trash the registers to simulate an allocation failure.
1492 li(result, Operand(0x7091));
1493 li(scratch1, Operand(0x7191));
1494 li(scratch2, Operand(0x7291));
1495 }
1496 b(gc_required);
1497 return;
1498 }
1499
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001500 DCHECK(!AreAliased(result, scratch1, scratch2, ip));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001501
1502 // Make object size into bytes.
1503 if ((flags & SIZE_IN_WORDS) != 0) {
1504 object_size *= kPointerSize;
1505 }
1506 DCHECK_EQ(0, static_cast<int>(object_size & kObjectAlignmentMask));
1507
1508 // Check relative positions of allocation top and limit addresses.
1509 ExternalReference allocation_top =
1510 AllocationUtils::GetAllocationTopReference(isolate(), flags);
1511 ExternalReference allocation_limit =
1512 AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1513
1514 intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address());
1515 intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address());
1516 DCHECK((limit - top) == kPointerSize);
1517
1518 // Set up allocation top address register.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001519 Register top_address = scratch1;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001520 // This code stores a temporary value in ip. This is OK, as the code below
1521 // does not need ip for implicit literal generation.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001522 Register alloc_limit = ip;
1523 Register result_end = scratch2;
1524 mov(top_address, Operand(allocation_top));
1525
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001526 if ((flags & RESULT_CONTAINS_TOP) == 0) {
1527 // Load allocation top into result and allocation limit into ip.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001528 LoadP(result, MemOperand(top_address));
1529 LoadP(alloc_limit, MemOperand(top_address, kPointerSize));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001530 } else {
1531 if (emit_debug_code()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001532 // Assert that result actually contains top on entry.
1533 LoadP(alloc_limit, MemOperand(top_address));
1534 cmp(result, alloc_limit);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001535 Check(eq, kUnexpectedAllocationTop);
1536 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001537 // Load allocation limit. Result already contains allocation top.
1538 LoadP(alloc_limit, MemOperand(top_address, limit - top));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001539 }
1540
1541 if ((flags & DOUBLE_ALIGNMENT) != 0) {
1542 // Align the next allocation. Storing the filler map without checking top is
1543 // safe in new-space because the limit of the heap is aligned there.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001544#if V8_TARGET_ARCH_PPC64
1545 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
1546#else
1547 STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001548 andi(result_end, result, Operand(kDoubleAlignmentMask));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001549 Label aligned;
1550 beq(&aligned, cr0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001551 if ((flags & PRETENURE) != 0) {
1552 cmpl(result, alloc_limit);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001553 bge(gc_required);
1554 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001555 mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
1556 stw(result_end, MemOperand(result));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001557 addi(result, result, Operand(kDoubleSize / 2));
1558 bind(&aligned);
1559#endif
1560 }
1561
1562 // Calculate new top and bail out if new space is exhausted. Use result
1563 // to calculate the new top.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001564 sub(r0, alloc_limit, result);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001565 if (is_int16(object_size)) {
1566 cmpi(r0, Operand(object_size));
1567 blt(gc_required);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001568 addi(result_end, result, Operand(object_size));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001569 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001570 Cmpi(r0, Operand(object_size), result_end);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001571 blt(gc_required);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001572 add(result_end, result, result_end);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001573 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001574 StoreP(result_end, MemOperand(top_address));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001575
1576 // Tag object if requested.
1577 if ((flags & TAG_OBJECT) != 0) {
1578 addi(result, result, Operand(kHeapObjectTag));
1579 }
1580}
1581
1582
1583void MacroAssembler::Allocate(Register object_size, Register result,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001584 Register result_end, Register scratch,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001585 Label* gc_required, AllocationFlags flags) {
1586 if (!FLAG_inline_new) {
1587 if (emit_debug_code()) {
1588 // Trash the registers to simulate an allocation failure.
1589 li(result, Operand(0x7091));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001590 li(scratch, Operand(0x7191));
1591 li(result_end, Operand(0x7291));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001592 }
1593 b(gc_required);
1594 return;
1595 }
1596
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001597 // |object_size| and |result_end| may overlap if the DOUBLE_ALIGNMENT flag
1598 // is not specified. Other registers must not overlap.
1599 DCHECK(!AreAliased(object_size, result, scratch, ip));
1600 DCHECK(!AreAliased(result_end, result, scratch, ip));
1601 DCHECK((flags & DOUBLE_ALIGNMENT) == 0 || !object_size.is(result_end));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001602
1603 // Check relative positions of allocation top and limit addresses.
1604 ExternalReference allocation_top =
1605 AllocationUtils::GetAllocationTopReference(isolate(), flags);
1606 ExternalReference allocation_limit =
1607 AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1608 intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address());
1609 intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address());
1610 DCHECK((limit - top) == kPointerSize);
1611
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001612 // Set up allocation top address and allocation limit registers.
1613 Register top_address = scratch;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001614 // This code stores a temporary value in ip. This is OK, as the code below
1615 // does not need ip for implicit literal generation.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001616 Register alloc_limit = ip;
1617 mov(top_address, Operand(allocation_top));
1618
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001619 if ((flags & RESULT_CONTAINS_TOP) == 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001620 // Load allocation top into result and allocation limit into alloc_limit..
1621 LoadP(result, MemOperand(top_address));
1622 LoadP(alloc_limit, MemOperand(top_address, kPointerSize));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001623 } else {
1624 if (emit_debug_code()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001625 // Assert that result actually contains top on entry.
1626 LoadP(alloc_limit, MemOperand(top_address));
1627 cmp(result, alloc_limit);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001628 Check(eq, kUnexpectedAllocationTop);
1629 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001630 // Load allocation limit. Result already contains allocation top.
1631 LoadP(alloc_limit, MemOperand(top_address, limit - top));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001632 }
1633
1634 if ((flags & DOUBLE_ALIGNMENT) != 0) {
1635 // Align the next allocation. Storing the filler map without checking top is
1636 // safe in new-space because the limit of the heap is aligned there.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001637#if V8_TARGET_ARCH_PPC64
1638 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
1639#else
1640 STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001641 andi(result_end, result, Operand(kDoubleAlignmentMask));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001642 Label aligned;
1643 beq(&aligned, cr0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001644 if ((flags & PRETENURE) != 0) {
1645 cmpl(result, alloc_limit);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001646 bge(gc_required);
1647 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001648 mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
1649 stw(result_end, MemOperand(result));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001650 addi(result, result, Operand(kDoubleSize / 2));
1651 bind(&aligned);
1652#endif
1653 }
1654
1655 // Calculate new top and bail out if new space is exhausted. Use result
1656 // to calculate the new top. Object size may be in words so a shift is
1657 // required to get the number of bytes.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001658 sub(r0, alloc_limit, result);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001659 if ((flags & SIZE_IN_WORDS) != 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001660 ShiftLeftImm(result_end, object_size, Operand(kPointerSizeLog2));
1661 cmp(r0, result_end);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001662 blt(gc_required);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001663 add(result_end, result, result_end);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001664 } else {
1665 cmp(r0, object_size);
1666 blt(gc_required);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001667 add(result_end, result, object_size);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001668 }
1669
1670 // Update allocation top. result temporarily holds the new top.
1671 if (emit_debug_code()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001672 andi(r0, result_end, Operand(kObjectAlignmentMask));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001673 Check(eq, kUnalignedAllocationInNewSpace, cr0);
1674 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001675 StoreP(result_end, MemOperand(top_address));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001676
1677 // Tag object if requested.
1678 if ((flags & TAG_OBJECT) != 0) {
1679 addi(result, result, Operand(kHeapObjectTag));
1680 }
1681}
1682
1683
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001684void MacroAssembler::AllocateTwoByteString(Register result, Register length,
1685 Register scratch1, Register scratch2,
1686 Register scratch3,
1687 Label* gc_required) {
1688 // Calculate the number of bytes needed for the characters in the string while
1689 // observing object alignment.
1690 DCHECK((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
1691 slwi(scratch1, length, Operand(1)); // Length in bytes, not chars.
1692 addi(scratch1, scratch1,
1693 Operand(kObjectAlignmentMask + SeqTwoByteString::kHeaderSize));
1694 mov(r0, Operand(~kObjectAlignmentMask));
1695 and_(scratch1, scratch1, r0);
1696
1697 // Allocate two-byte string in new space.
1698 Allocate(scratch1, result, scratch2, scratch3, gc_required, TAG_OBJECT);
1699
1700 // Set the map, length and hash field.
1701 InitializeNewString(result, length, Heap::kStringMapRootIndex, scratch1,
1702 scratch2);
1703}
1704
1705
1706void MacroAssembler::AllocateOneByteString(Register result, Register length,
1707 Register scratch1, Register scratch2,
1708 Register scratch3,
1709 Label* gc_required) {
1710 // Calculate the number of bytes needed for the characters in the string while
1711 // observing object alignment.
1712 DCHECK((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
1713 DCHECK(kCharSize == 1);
1714 addi(scratch1, length,
1715 Operand(kObjectAlignmentMask + SeqOneByteString::kHeaderSize));
1716 li(r0, Operand(~kObjectAlignmentMask));
1717 and_(scratch1, scratch1, r0);
1718
1719 // Allocate one-byte string in new space.
1720 Allocate(scratch1, result, scratch2, scratch3, gc_required, TAG_OBJECT);
1721
1722 // Set the map, length and hash field.
1723 InitializeNewString(result, length, Heap::kOneByteStringMapRootIndex,
1724 scratch1, scratch2);
1725}
1726
1727
1728void MacroAssembler::AllocateTwoByteConsString(Register result, Register length,
1729 Register scratch1,
1730 Register scratch2,
1731 Label* gc_required) {
1732 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
1733 TAG_OBJECT);
1734
1735 InitializeNewString(result, length, Heap::kConsStringMapRootIndex, scratch1,
1736 scratch2);
1737}
1738
1739
1740void MacroAssembler::AllocateOneByteConsString(Register result, Register length,
1741 Register scratch1,
1742 Register scratch2,
1743 Label* gc_required) {
1744 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
1745 TAG_OBJECT);
1746
1747 InitializeNewString(result, length, Heap::kConsOneByteStringMapRootIndex,
1748 scratch1, scratch2);
1749}
1750
1751
1752void MacroAssembler::AllocateTwoByteSlicedString(Register result,
1753 Register length,
1754 Register scratch1,
1755 Register scratch2,
1756 Label* gc_required) {
1757 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
1758 TAG_OBJECT);
1759
1760 InitializeNewString(result, length, Heap::kSlicedStringMapRootIndex, scratch1,
1761 scratch2);
1762}
1763
1764
1765void MacroAssembler::AllocateOneByteSlicedString(Register result,
1766 Register length,
1767 Register scratch1,
1768 Register scratch2,
1769 Label* gc_required) {
1770 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
1771 TAG_OBJECT);
1772
1773 InitializeNewString(result, length, Heap::kSlicedOneByteStringMapRootIndex,
1774 scratch1, scratch2);
1775}
1776
1777
1778void MacroAssembler::CompareObjectType(Register object, Register map,
1779 Register type_reg, InstanceType type) {
1780 const Register temp = type_reg.is(no_reg) ? r0 : type_reg;
1781
1782 LoadP(map, FieldMemOperand(object, HeapObject::kMapOffset));
1783 CompareInstanceType(map, temp, type);
1784}
1785
1786
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001787void MacroAssembler::CompareInstanceType(Register map, Register type_reg,
1788 InstanceType type) {
1789 STATIC_ASSERT(Map::kInstanceTypeOffset < 4096);
1790 STATIC_ASSERT(LAST_TYPE < 256);
1791 lbz(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
1792 cmpi(type_reg, Operand(type));
1793}
1794
1795
1796void MacroAssembler::CompareRoot(Register obj, Heap::RootListIndex index) {
1797 DCHECK(!obj.is(r0));
1798 LoadRoot(r0, index);
1799 cmp(obj, r0);
1800}
1801
1802
1803void MacroAssembler::CheckFastElements(Register map, Register scratch,
1804 Label* fail) {
1805 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
1806 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
1807 STATIC_ASSERT(FAST_ELEMENTS == 2);
1808 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
1809 lbz(scratch, FieldMemOperand(map, Map::kBitField2Offset));
1810 STATIC_ASSERT(Map::kMaximumBitField2FastHoleyElementValue < 0x8000);
1811 cmpli(scratch, Operand(Map::kMaximumBitField2FastHoleyElementValue));
1812 bgt(fail);
1813}
1814
1815
1816void MacroAssembler::CheckFastObjectElements(Register map, Register scratch,
1817 Label* fail) {
1818 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
1819 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
1820 STATIC_ASSERT(FAST_ELEMENTS == 2);
1821 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
1822 lbz(scratch, FieldMemOperand(map, Map::kBitField2Offset));
1823 cmpli(scratch, Operand(Map::kMaximumBitField2FastHoleySmiElementValue));
1824 ble(fail);
1825 cmpli(scratch, Operand(Map::kMaximumBitField2FastHoleyElementValue));
1826 bgt(fail);
1827}
1828
1829
1830void MacroAssembler::CheckFastSmiElements(Register map, Register scratch,
1831 Label* fail) {
1832 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
1833 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
1834 lbz(scratch, FieldMemOperand(map, Map::kBitField2Offset));
1835 cmpli(scratch, Operand(Map::kMaximumBitField2FastHoleySmiElementValue));
1836 bgt(fail);
1837}
1838
1839
1840void MacroAssembler::StoreNumberToDoubleElements(
1841 Register value_reg, Register key_reg, Register elements_reg,
1842 Register scratch1, DoubleRegister double_scratch, Label* fail,
1843 int elements_offset) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001844 DCHECK(!AreAliased(value_reg, key_reg, elements_reg, scratch1));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001845 Label smi_value, store;
1846
1847 // Handle smi values specially.
1848 JumpIfSmi(value_reg, &smi_value);
1849
1850 // Ensure that the object is a heap number
1851 CheckMap(value_reg, scratch1, isolate()->factory()->heap_number_map(), fail,
1852 DONT_DO_SMI_CHECK);
1853
1854 lfd(double_scratch, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001855 // Double value, turn potential sNaN into qNaN.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001856 CanonicalizeNaN(double_scratch);
1857 b(&store);
1858
1859 bind(&smi_value);
1860 SmiToDouble(double_scratch, value_reg);
1861
1862 bind(&store);
1863 SmiToDoubleArrayOffset(scratch1, key_reg);
1864 add(scratch1, elements_reg, scratch1);
1865 stfd(double_scratch, FieldMemOperand(scratch1, FixedDoubleArray::kHeaderSize -
1866 elements_offset));
1867}
1868
1869
1870void MacroAssembler::AddAndCheckForOverflow(Register dst, Register left,
1871 Register right,
1872 Register overflow_dst,
1873 Register scratch) {
1874 DCHECK(!dst.is(overflow_dst));
1875 DCHECK(!dst.is(scratch));
1876 DCHECK(!overflow_dst.is(scratch));
1877 DCHECK(!overflow_dst.is(left));
1878 DCHECK(!overflow_dst.is(right));
1879
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001880 bool left_is_right = left.is(right);
1881 RCBit xorRC = left_is_right ? SetRC : LeaveRC;
1882
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001883 // C = A+B; C overflows if A/B have same sign and C has diff sign than A
1884 if (dst.is(left)) {
1885 mr(scratch, left); // Preserve left.
1886 add(dst, left, right); // Left is overwritten.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001887 xor_(overflow_dst, dst, scratch, xorRC); // Original left.
1888 if (!left_is_right) xor_(scratch, dst, right);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001889 } else if (dst.is(right)) {
1890 mr(scratch, right); // Preserve right.
1891 add(dst, left, right); // Right is overwritten.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001892 xor_(overflow_dst, dst, left, xorRC);
1893 if (!left_is_right) xor_(scratch, dst, scratch); // Original right.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001894 } else {
1895 add(dst, left, right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001896 xor_(overflow_dst, dst, left, xorRC);
1897 if (!left_is_right) xor_(scratch, dst, right);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001898 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001899 if (!left_is_right) and_(overflow_dst, scratch, overflow_dst, SetRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001900}
1901
1902
1903void MacroAssembler::AddAndCheckForOverflow(Register dst, Register left,
1904 intptr_t right,
1905 Register overflow_dst,
1906 Register scratch) {
1907 Register original_left = left;
1908 DCHECK(!dst.is(overflow_dst));
1909 DCHECK(!dst.is(scratch));
1910 DCHECK(!overflow_dst.is(scratch));
1911 DCHECK(!overflow_dst.is(left));
1912
1913 // C = A+B; C overflows if A/B have same sign and C has diff sign than A
1914 if (dst.is(left)) {
1915 // Preserve left.
1916 original_left = overflow_dst;
1917 mr(original_left, left);
1918 }
1919 Add(dst, left, right, scratch);
1920 xor_(overflow_dst, dst, original_left);
1921 if (right >= 0) {
1922 and_(overflow_dst, overflow_dst, dst, SetRC);
1923 } else {
1924 andc(overflow_dst, overflow_dst, dst, SetRC);
1925 }
1926}
1927
1928
1929void MacroAssembler::SubAndCheckForOverflow(Register dst, Register left,
1930 Register right,
1931 Register overflow_dst,
1932 Register scratch) {
1933 DCHECK(!dst.is(overflow_dst));
1934 DCHECK(!dst.is(scratch));
1935 DCHECK(!overflow_dst.is(scratch));
1936 DCHECK(!overflow_dst.is(left));
1937 DCHECK(!overflow_dst.is(right));
1938
1939 // C = A-B; C overflows if A/B have diff signs and C has diff sign than A
1940 if (dst.is(left)) {
1941 mr(scratch, left); // Preserve left.
1942 sub(dst, left, right); // Left is overwritten.
1943 xor_(overflow_dst, dst, scratch);
1944 xor_(scratch, scratch, right);
1945 and_(overflow_dst, overflow_dst, scratch, SetRC);
1946 } else if (dst.is(right)) {
1947 mr(scratch, right); // Preserve right.
1948 sub(dst, left, right); // Right is overwritten.
1949 xor_(overflow_dst, dst, left);
1950 xor_(scratch, left, scratch);
1951 and_(overflow_dst, overflow_dst, scratch, SetRC);
1952 } else {
1953 sub(dst, left, right);
1954 xor_(overflow_dst, dst, left);
1955 xor_(scratch, left, right);
1956 and_(overflow_dst, scratch, overflow_dst, SetRC);
1957 }
1958}
1959
1960
1961void MacroAssembler::CompareMap(Register obj, Register scratch, Handle<Map> map,
1962 Label* early_success) {
1963 LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
1964 CompareMap(scratch, map, early_success);
1965}
1966
1967
1968void MacroAssembler::CompareMap(Register obj_map, Handle<Map> map,
1969 Label* early_success) {
1970 mov(r0, Operand(map));
1971 cmp(obj_map, r0);
1972}
1973
1974
1975void MacroAssembler::CheckMap(Register obj, Register scratch, Handle<Map> map,
1976 Label* fail, SmiCheckType smi_check_type) {
1977 if (smi_check_type == DO_SMI_CHECK) {
1978 JumpIfSmi(obj, fail);
1979 }
1980
1981 Label success;
1982 CompareMap(obj, scratch, map, &success);
1983 bne(fail);
1984 bind(&success);
1985}
1986
1987
1988void MacroAssembler::CheckMap(Register obj, Register scratch,
1989 Heap::RootListIndex index, Label* fail,
1990 SmiCheckType smi_check_type) {
1991 if (smi_check_type == DO_SMI_CHECK) {
1992 JumpIfSmi(obj, fail);
1993 }
1994 LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
1995 LoadRoot(r0, index);
1996 cmp(scratch, r0);
1997 bne(fail);
1998}
1999
2000
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002001void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1,
2002 Register scratch2, Handle<WeakCell> cell,
2003 Handle<Code> success,
2004 SmiCheckType smi_check_type) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002005 Label fail;
2006 if (smi_check_type == DO_SMI_CHECK) {
2007 JumpIfSmi(obj, &fail);
2008 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002009 LoadP(scratch1, FieldMemOperand(obj, HeapObject::kMapOffset));
2010 CmpWeakValue(scratch1, cell, scratch2);
2011 Jump(success, RelocInfo::CODE_TARGET, eq);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002012 bind(&fail);
2013}
2014
2015
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002016void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell,
2017 Register scratch, CRegister cr) {
2018 mov(scratch, Operand(cell));
2019 LoadP(scratch, FieldMemOperand(scratch, WeakCell::kValueOffset));
2020 cmp(value, scratch, cr);
2021}
2022
2023
2024void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) {
2025 mov(value, Operand(cell));
2026 LoadP(value, FieldMemOperand(value, WeakCell::kValueOffset));
2027}
2028
2029
2030void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
2031 Label* miss) {
2032 GetWeakValue(value, cell);
2033 JumpIfSmi(value, miss);
2034}
2035
2036
2037void MacroAssembler::GetMapConstructor(Register result, Register map,
2038 Register temp, Register temp2) {
2039 Label done, loop;
2040 LoadP(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset));
2041 bind(&loop);
2042 JumpIfSmi(result, &done);
2043 CompareObjectType(result, temp, temp2, MAP_TYPE);
2044 bne(&done);
2045 LoadP(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset));
2046 b(&loop);
2047 bind(&done);
2048}
2049
2050
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002051void MacroAssembler::TryGetFunctionPrototype(Register function, Register result,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002052 Register scratch, Label* miss) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002053 // Get the prototype or initial map from the function.
2054 LoadP(result,
2055 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2056
2057 // If the prototype or initial map is the hole, don't return it and
2058 // simply miss the cache instead. This will allow us to allocate a
2059 // prototype object on-demand in the runtime system.
2060 LoadRoot(r0, Heap::kTheHoleValueRootIndex);
2061 cmp(result, r0);
2062 beq(miss);
2063
2064 // If the function does not have an initial map, we're done.
2065 Label done;
2066 CompareObjectType(result, scratch, scratch, MAP_TYPE);
2067 bne(&done);
2068
2069 // Get the prototype from the initial map.
2070 LoadP(result, FieldMemOperand(result, Map::kPrototypeOffset));
2071
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002072 // All done.
2073 bind(&done);
2074}
2075
2076
2077void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id,
2078 Condition cond) {
2079 DCHECK(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs.
2080 Call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id, cond);
2081}
2082
2083
2084void MacroAssembler::TailCallStub(CodeStub* stub, Condition cond) {
2085 Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond);
2086}
2087
2088
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002089bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
2090 return has_frame_ || !stub->SometimesSetsUpAFrame();
2091}
2092
2093
2094void MacroAssembler::IndexFromHash(Register hash, Register index) {
2095 // If the hash field contains an array index pick it out. The assert checks
2096 // that the constants for the maximum number of digits for an array index
2097 // cached in the hash field and the number of bits reserved for it does not
2098 // conflict.
2099 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
2100 (1 << String::kArrayIndexValueBits));
2101 DecodeFieldToSmi<String::ArrayIndexValueBits>(index, hash);
2102}
2103
2104
2105void MacroAssembler::SmiToDouble(DoubleRegister value, Register smi) {
2106 SmiUntag(ip, smi);
2107 ConvertIntToDouble(ip, value);
2108}
2109
2110
2111void MacroAssembler::TestDoubleIsInt32(DoubleRegister double_input,
2112 Register scratch1, Register scratch2,
2113 DoubleRegister double_scratch) {
2114 TryDoubleToInt32Exact(scratch1, double_input, scratch2, double_scratch);
2115}
2116
2117
2118void MacroAssembler::TryDoubleToInt32Exact(Register result,
2119 DoubleRegister double_input,
2120 Register scratch,
2121 DoubleRegister double_scratch) {
2122 Label done;
2123 DCHECK(!double_input.is(double_scratch));
2124
2125 ConvertDoubleToInt64(double_input,
2126#if !V8_TARGET_ARCH_PPC64
2127 scratch,
2128#endif
2129 result, double_scratch);
2130
2131#if V8_TARGET_ARCH_PPC64
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002132 TestIfInt32(result, r0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002133#else
2134 TestIfInt32(scratch, result, r0);
2135#endif
2136 bne(&done);
2137
2138 // convert back and compare
2139 fcfid(double_scratch, double_scratch);
2140 fcmpu(double_scratch, double_input);
2141 bind(&done);
2142}
2143
2144
2145void MacroAssembler::TryInt32Floor(Register result, DoubleRegister double_input,
2146 Register input_high, Register scratch,
2147 DoubleRegister double_scratch, Label* done,
2148 Label* exact) {
2149 DCHECK(!result.is(input_high));
2150 DCHECK(!double_input.is(double_scratch));
2151 Label exception;
2152
2153 MovDoubleHighToInt(input_high, double_input);
2154
2155 // Test for NaN/Inf
2156 ExtractBitMask(result, input_high, HeapNumber::kExponentMask);
2157 cmpli(result, Operand(0x7ff));
2158 beq(&exception);
2159
2160 // Convert (rounding to -Inf)
2161 ConvertDoubleToInt64(double_input,
2162#if !V8_TARGET_ARCH_PPC64
2163 scratch,
2164#endif
2165 result, double_scratch, kRoundToMinusInf);
2166
2167// Test for overflow
2168#if V8_TARGET_ARCH_PPC64
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002169 TestIfInt32(result, r0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002170#else
2171 TestIfInt32(scratch, result, r0);
2172#endif
2173 bne(&exception);
2174
2175 // Test for exactness
2176 fcfid(double_scratch, double_scratch);
2177 fcmpu(double_scratch, double_input);
2178 beq(exact);
2179 b(done);
2180
2181 bind(&exception);
2182}
2183
2184
2185void MacroAssembler::TryInlineTruncateDoubleToI(Register result,
2186 DoubleRegister double_input,
2187 Label* done) {
2188 DoubleRegister double_scratch = kScratchDoubleReg;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002189#if !V8_TARGET_ARCH_PPC64
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002190 Register scratch = ip;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002191#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002192
2193 ConvertDoubleToInt64(double_input,
2194#if !V8_TARGET_ARCH_PPC64
2195 scratch,
2196#endif
2197 result, double_scratch);
2198
2199// Test for overflow
2200#if V8_TARGET_ARCH_PPC64
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002201 TestIfInt32(result, r0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002202#else
2203 TestIfInt32(scratch, result, r0);
2204#endif
2205 beq(done);
2206}
2207
2208
2209void MacroAssembler::TruncateDoubleToI(Register result,
2210 DoubleRegister double_input) {
2211 Label done;
2212
2213 TryInlineTruncateDoubleToI(result, double_input, &done);
2214
2215 // If we fell through then inline version didn't succeed - call stub instead.
2216 mflr(r0);
2217 push(r0);
2218 // Put input on stack.
2219 stfdu(double_input, MemOperand(sp, -kDoubleSize));
2220
2221 DoubleToIStub stub(isolate(), sp, result, 0, true, true);
2222 CallStub(&stub);
2223
2224 addi(sp, sp, Operand(kDoubleSize));
2225 pop(r0);
2226 mtlr(r0);
2227
2228 bind(&done);
2229}
2230
2231
2232void MacroAssembler::TruncateHeapNumberToI(Register result, Register object) {
2233 Label done;
2234 DoubleRegister double_scratch = kScratchDoubleReg;
2235 DCHECK(!result.is(object));
2236
2237 lfd(double_scratch, FieldMemOperand(object, HeapNumber::kValueOffset));
2238 TryInlineTruncateDoubleToI(result, double_scratch, &done);
2239
2240 // If we fell through then inline version didn't succeed - call stub instead.
2241 mflr(r0);
2242 push(r0);
2243 DoubleToIStub stub(isolate(), object, result,
2244 HeapNumber::kValueOffset - kHeapObjectTag, true, true);
2245 CallStub(&stub);
2246 pop(r0);
2247 mtlr(r0);
2248
2249 bind(&done);
2250}
2251
2252
2253void MacroAssembler::TruncateNumberToI(Register object, Register result,
2254 Register heap_number_map,
2255 Register scratch1, Label* not_number) {
2256 Label done;
2257 DCHECK(!result.is(object));
2258
2259 UntagAndJumpIfSmi(result, object, &done);
2260 JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number);
2261 TruncateHeapNumberToI(result, object);
2262
2263 bind(&done);
2264}
2265
2266
2267void MacroAssembler::GetLeastBitsFromSmi(Register dst, Register src,
2268 int num_least_bits) {
2269#if V8_TARGET_ARCH_PPC64
2270 rldicl(dst, src, kBitsPerPointer - kSmiShift,
2271 kBitsPerPointer - num_least_bits);
2272#else
2273 rlwinm(dst, src, kBitsPerPointer - kSmiShift,
2274 kBitsPerPointer - num_least_bits, 31);
2275#endif
2276}
2277
2278
2279void MacroAssembler::GetLeastBitsFromInt32(Register dst, Register src,
2280 int num_least_bits) {
2281 rlwinm(dst, src, 0, 32 - num_least_bits, 31);
2282}
2283
2284
2285void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments,
2286 SaveFPRegsMode save_doubles) {
2287 // All parameters are on the stack. r3 has the return value after call.
2288
2289 // If the expected number of arguments of the runtime function is
2290 // constant, we check that the actual number of arguments match the
2291 // expectation.
2292 CHECK(f->nargs < 0 || f->nargs == num_arguments);
2293
2294 // TODO(1236192): Most runtime routines don't need the number of
2295 // arguments passed in because it is constant. At some point we
2296 // should remove this need and make the runtime routine entry code
2297 // smarter.
2298 mov(r3, Operand(num_arguments));
2299 mov(r4, Operand(ExternalReference(f, isolate())));
2300 CEntryStub stub(isolate(),
2301#if V8_TARGET_ARCH_PPC64
2302 f->result_size,
2303#else
2304 1,
2305#endif
2306 save_doubles);
2307 CallStub(&stub);
2308}
2309
2310
2311void MacroAssembler::CallExternalReference(const ExternalReference& ext,
2312 int num_arguments) {
2313 mov(r3, Operand(num_arguments));
2314 mov(r4, Operand(ext));
2315
2316 CEntryStub stub(isolate(), 1);
2317 CallStub(&stub);
2318}
2319
2320
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002321void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
2322 const Runtime::Function* function = Runtime::FunctionForId(fid);
2323 DCHECK_EQ(1, function->result_size);
2324 if (function->nargs >= 0) {
2325 mov(r3, Operand(function->nargs));
2326 }
2327 JumpToExternalReference(ExternalReference(fid, isolate()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002328}
2329
2330
2331void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin) {
2332 mov(r4, Operand(builtin));
2333 CEntryStub stub(isolate(), 1);
2334 Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
2335}
2336
2337
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002338void MacroAssembler::InvokeBuiltin(int native_context_index, InvokeFlag flag,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002339 const CallWrapper& call_wrapper) {
2340 // You can't call a builtin without a valid frame.
2341 DCHECK(flag == JUMP_FUNCTION || has_frame());
2342
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002343 // Fake a parameter count to avoid emitting code to do the check.
2344 ParameterCount expected(0);
2345 LoadNativeContextSlot(native_context_index, r4);
2346 InvokeFunctionCode(r4, no_reg, expected, expected, flag, call_wrapper);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002347}
2348
2349
2350void MacroAssembler::SetCounter(StatsCounter* counter, int value,
2351 Register scratch1, Register scratch2) {
2352 if (FLAG_native_code_counters && counter->Enabled()) {
2353 mov(scratch1, Operand(value));
2354 mov(scratch2, Operand(ExternalReference(counter)));
2355 stw(scratch1, MemOperand(scratch2));
2356 }
2357}
2358
2359
2360void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
2361 Register scratch1, Register scratch2) {
2362 DCHECK(value > 0);
2363 if (FLAG_native_code_counters && counter->Enabled()) {
2364 mov(scratch2, Operand(ExternalReference(counter)));
2365 lwz(scratch1, MemOperand(scratch2));
2366 addi(scratch1, scratch1, Operand(value));
2367 stw(scratch1, MemOperand(scratch2));
2368 }
2369}
2370
2371
2372void MacroAssembler::DecrementCounter(StatsCounter* counter, int value,
2373 Register scratch1, Register scratch2) {
2374 DCHECK(value > 0);
2375 if (FLAG_native_code_counters && counter->Enabled()) {
2376 mov(scratch2, Operand(ExternalReference(counter)));
2377 lwz(scratch1, MemOperand(scratch2));
2378 subi(scratch1, scratch1, Operand(value));
2379 stw(scratch1, MemOperand(scratch2));
2380 }
2381}
2382
2383
2384void MacroAssembler::Assert(Condition cond, BailoutReason reason,
2385 CRegister cr) {
2386 if (emit_debug_code()) Check(cond, reason, cr);
2387}
2388
2389
2390void MacroAssembler::AssertFastElements(Register elements) {
2391 if (emit_debug_code()) {
2392 DCHECK(!elements.is(r0));
2393 Label ok;
2394 push(elements);
2395 LoadP(elements, FieldMemOperand(elements, HeapObject::kMapOffset));
2396 LoadRoot(r0, Heap::kFixedArrayMapRootIndex);
2397 cmp(elements, r0);
2398 beq(&ok);
2399 LoadRoot(r0, Heap::kFixedDoubleArrayMapRootIndex);
2400 cmp(elements, r0);
2401 beq(&ok);
2402 LoadRoot(r0, Heap::kFixedCOWArrayMapRootIndex);
2403 cmp(elements, r0);
2404 beq(&ok);
2405 Abort(kJSObjectWithFastElementsMapHasSlowElements);
2406 bind(&ok);
2407 pop(elements);
2408 }
2409}
2410
2411
2412void MacroAssembler::Check(Condition cond, BailoutReason reason, CRegister cr) {
2413 Label L;
2414 b(cond, &L, cr);
2415 Abort(reason);
2416 // will not return here
2417 bind(&L);
2418}
2419
2420
2421void MacroAssembler::Abort(BailoutReason reason) {
2422 Label abort_start;
2423 bind(&abort_start);
2424#ifdef DEBUG
2425 const char* msg = GetBailoutReason(reason);
2426 if (msg != NULL) {
2427 RecordComment("Abort message: ");
2428 RecordComment(msg);
2429 }
2430
2431 if (FLAG_trap_on_abort) {
2432 stop(msg);
2433 return;
2434 }
2435#endif
2436
2437 LoadSmiLiteral(r0, Smi::FromInt(reason));
2438 push(r0);
2439 // Disable stub call restrictions to always allow calls to abort.
2440 if (!has_frame_) {
2441 // We don't actually want to generate a pile of code for this, so just
2442 // claim there is a stack frame, without generating one.
2443 FrameScope scope(this, StackFrame::NONE);
2444 CallRuntime(Runtime::kAbort, 1);
2445 } else {
2446 CallRuntime(Runtime::kAbort, 1);
2447 }
2448 // will not return here
2449}
2450
2451
2452void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
2453 if (context_chain_length > 0) {
2454 // Move up the chain of contexts to the context containing the slot.
2455 LoadP(dst, MemOperand(cp, Context::SlotOffset(Context::PREVIOUS_INDEX)));
2456 for (int i = 1; i < context_chain_length; i++) {
2457 LoadP(dst, MemOperand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX)));
2458 }
2459 } else {
2460 // Slot is in the current function context. Move it into the
2461 // destination register in case we store into it (the write barrier
2462 // cannot be allowed to destroy the context in esi).
2463 mr(dst, cp);
2464 }
2465}
2466
2467
2468void MacroAssembler::LoadTransitionedArrayMapConditional(
2469 ElementsKind expected_kind, ElementsKind transitioned_kind,
2470 Register map_in_out, Register scratch, Label* no_map_match) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002471 DCHECK(IsFastElementsKind(expected_kind));
2472 DCHECK(IsFastElementsKind(transitioned_kind));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002473
2474 // Check that the function's map is the same as the expected cached map.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002475 LoadP(scratch, NativeContextMemOperand());
2476 LoadP(ip, ContextMemOperand(scratch, Context::ArrayMapIndex(expected_kind)));
2477 cmp(map_in_out, ip);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002478 bne(no_map_match);
2479
2480 // Use the transitioned cached map.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002481 LoadP(map_in_out,
2482 ContextMemOperand(scratch, Context::ArrayMapIndex(transitioned_kind)));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002483}
2484
2485
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002486void MacroAssembler::LoadNativeContextSlot(int index, Register dst) {
2487 LoadP(dst, NativeContextMemOperand());
2488 LoadP(dst, ContextMemOperand(dst, index));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002489}
2490
2491
2492void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
2493 Register map,
2494 Register scratch) {
2495 // Load the initial map. The global functions all have initial maps.
2496 LoadP(map,
2497 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2498 if (emit_debug_code()) {
2499 Label ok, fail;
2500 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK);
2501 b(&ok);
2502 bind(&fail);
2503 Abort(kGlobalFunctionsMustHaveInitialMap);
2504 bind(&ok);
2505 }
2506}
2507
2508
2509void MacroAssembler::JumpIfNotPowerOfTwoOrZero(
2510 Register reg, Register scratch, Label* not_power_of_two_or_zero) {
2511 subi(scratch, reg, Operand(1));
2512 cmpi(scratch, Operand::Zero());
2513 blt(not_power_of_two_or_zero);
2514 and_(r0, scratch, reg, SetRC);
2515 bne(not_power_of_two_or_zero, cr0);
2516}
2517
2518
2519void MacroAssembler::JumpIfNotPowerOfTwoOrZeroAndNeg(Register reg,
2520 Register scratch,
2521 Label* zero_and_neg,
2522 Label* not_power_of_two) {
2523 subi(scratch, reg, Operand(1));
2524 cmpi(scratch, Operand::Zero());
2525 blt(zero_and_neg);
2526 and_(r0, scratch, reg, SetRC);
2527 bne(not_power_of_two, cr0);
2528}
2529
2530#if !V8_TARGET_ARCH_PPC64
2531void MacroAssembler::SmiTagCheckOverflow(Register reg, Register overflow) {
2532 DCHECK(!reg.is(overflow));
2533 mr(overflow, reg); // Save original value.
2534 SmiTag(reg);
2535 xor_(overflow, overflow, reg, SetRC); // Overflow if (value ^ 2 * value) < 0.
2536}
2537
2538
2539void MacroAssembler::SmiTagCheckOverflow(Register dst, Register src,
2540 Register overflow) {
2541 if (dst.is(src)) {
2542 // Fall back to slower case.
2543 SmiTagCheckOverflow(dst, overflow);
2544 } else {
2545 DCHECK(!dst.is(src));
2546 DCHECK(!dst.is(overflow));
2547 DCHECK(!src.is(overflow));
2548 SmiTag(dst, src);
2549 xor_(overflow, dst, src, SetRC); // Overflow if (value ^ 2 * value) < 0.
2550 }
2551}
2552#endif
2553
2554void MacroAssembler::JumpIfNotBothSmi(Register reg1, Register reg2,
2555 Label* on_not_both_smi) {
2556 STATIC_ASSERT(kSmiTag == 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002557 orx(r0, reg1, reg2, LeaveRC);
2558 JumpIfNotSmi(r0, on_not_both_smi);
2559}
2560
2561
2562void MacroAssembler::UntagAndJumpIfSmi(Register dst, Register src,
2563 Label* smi_case) {
2564 STATIC_ASSERT(kSmiTag == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002565 TestBitRange(src, kSmiTagSize - 1, 0, r0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002566 SmiUntag(dst, src);
2567 beq(smi_case, cr0);
2568}
2569
2570
2571void MacroAssembler::UntagAndJumpIfNotSmi(Register dst, Register src,
2572 Label* non_smi_case) {
2573 STATIC_ASSERT(kSmiTag == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002574 TestBitRange(src, kSmiTagSize - 1, 0, r0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002575 SmiUntag(dst, src);
2576 bne(non_smi_case, cr0);
2577}
2578
2579
2580void MacroAssembler::JumpIfEitherSmi(Register reg1, Register reg2,
2581 Label* on_either_smi) {
2582 STATIC_ASSERT(kSmiTag == 0);
2583 JumpIfSmi(reg1, on_either_smi);
2584 JumpIfSmi(reg2, on_either_smi);
2585}
2586
2587
2588void MacroAssembler::AssertNotSmi(Register object) {
2589 if (emit_debug_code()) {
2590 STATIC_ASSERT(kSmiTag == 0);
2591 TestIfSmi(object, r0);
2592 Check(ne, kOperandIsASmi, cr0);
2593 }
2594}
2595
2596
2597void MacroAssembler::AssertSmi(Register object) {
2598 if (emit_debug_code()) {
2599 STATIC_ASSERT(kSmiTag == 0);
2600 TestIfSmi(object, r0);
2601 Check(eq, kOperandIsNotSmi, cr0);
2602 }
2603}
2604
2605
2606void MacroAssembler::AssertString(Register object) {
2607 if (emit_debug_code()) {
2608 STATIC_ASSERT(kSmiTag == 0);
2609 TestIfSmi(object, r0);
2610 Check(ne, kOperandIsASmiAndNotAString, cr0);
2611 push(object);
2612 LoadP(object, FieldMemOperand(object, HeapObject::kMapOffset));
2613 CompareInstanceType(object, object, FIRST_NONSTRING_TYPE);
2614 pop(object);
2615 Check(lt, kOperandIsNotAString);
2616 }
2617}
2618
2619
2620void MacroAssembler::AssertName(Register object) {
2621 if (emit_debug_code()) {
2622 STATIC_ASSERT(kSmiTag == 0);
2623 TestIfSmi(object, r0);
2624 Check(ne, kOperandIsASmiAndNotAName, cr0);
2625 push(object);
2626 LoadP(object, FieldMemOperand(object, HeapObject::kMapOffset));
2627 CompareInstanceType(object, object, LAST_NAME_TYPE);
2628 pop(object);
2629 Check(le, kOperandIsNotAName);
2630 }
2631}
2632
2633
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002634void MacroAssembler::AssertFunction(Register object) {
2635 if (emit_debug_code()) {
2636 STATIC_ASSERT(kSmiTag == 0);
2637 TestIfSmi(object, r0);
2638 Check(ne, kOperandIsASmiAndNotAFunction, cr0);
2639 push(object);
2640 CompareObjectType(object, object, object, JS_FUNCTION_TYPE);
2641 pop(object);
2642 Check(eq, kOperandIsNotAFunction);
2643 }
2644}
2645
2646
2647void MacroAssembler::AssertBoundFunction(Register object) {
2648 if (emit_debug_code()) {
2649 STATIC_ASSERT(kSmiTag == 0);
2650 TestIfSmi(object, r0);
2651 Check(ne, kOperandIsASmiAndNotABoundFunction, cr0);
2652 push(object);
2653 CompareObjectType(object, object, object, JS_BOUND_FUNCTION_TYPE);
2654 pop(object);
2655 Check(eq, kOperandIsNotABoundFunction);
2656 }
2657}
2658
2659
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002660void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
2661 Register scratch) {
2662 if (emit_debug_code()) {
2663 Label done_checking;
2664 AssertNotSmi(object);
2665 CompareRoot(object, Heap::kUndefinedValueRootIndex);
2666 beq(&done_checking);
2667 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
2668 CompareRoot(scratch, Heap::kAllocationSiteMapRootIndex);
2669 Assert(eq, kExpectedUndefinedOrCell);
2670 bind(&done_checking);
2671 }
2672}
2673
2674
2675void MacroAssembler::AssertIsRoot(Register reg, Heap::RootListIndex index) {
2676 if (emit_debug_code()) {
2677 CompareRoot(reg, index);
2678 Check(eq, kHeapNumberMapRegisterClobbered);
2679 }
2680}
2681
2682
2683void MacroAssembler::JumpIfNotHeapNumber(Register object,
2684 Register heap_number_map,
2685 Register scratch,
2686 Label* on_not_heap_number) {
2687 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
2688 AssertIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
2689 cmp(scratch, heap_number_map);
2690 bne(on_not_heap_number);
2691}
2692
2693
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002694void MacroAssembler::JumpIfNonSmisNotBothSequentialOneByteStrings(
2695 Register first, Register second, Register scratch1, Register scratch2,
2696 Label* failure) {
2697 // Test that both first and second are sequential one-byte strings.
2698 // Assume that they are non-smis.
2699 LoadP(scratch1, FieldMemOperand(first, HeapObject::kMapOffset));
2700 LoadP(scratch2, FieldMemOperand(second, HeapObject::kMapOffset));
2701 lbz(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
2702 lbz(scratch2, FieldMemOperand(scratch2, Map::kInstanceTypeOffset));
2703
2704 JumpIfBothInstanceTypesAreNotSequentialOneByte(scratch1, scratch2, scratch1,
2705 scratch2, failure);
2706}
2707
2708void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register first,
2709 Register second,
2710 Register scratch1,
2711 Register scratch2,
2712 Label* failure) {
2713 // Check that neither is a smi.
2714 and_(scratch1, first, second);
2715 JumpIfSmi(scratch1, failure);
2716 JumpIfNonSmisNotBothSequentialOneByteStrings(first, second, scratch1,
2717 scratch2, failure);
2718}
2719
2720
2721void MacroAssembler::JumpIfNotUniqueNameInstanceType(Register reg,
2722 Label* not_unique_name) {
2723 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
2724 Label succeed;
2725 andi(r0, reg, Operand(kIsNotStringMask | kIsNotInternalizedMask));
2726 beq(&succeed, cr0);
2727 cmpi(reg, Operand(SYMBOL_TYPE));
2728 bne(not_unique_name);
2729
2730 bind(&succeed);
2731}
2732
2733
2734// Allocates a heap number or jumps to the need_gc label if the young space
2735// is full and a scavenge is needed.
2736void MacroAssembler::AllocateHeapNumber(Register result, Register scratch1,
2737 Register scratch2,
2738 Register heap_number_map,
2739 Label* gc_required,
2740 TaggingMode tagging_mode,
2741 MutableMode mode) {
2742 // Allocate an object in the heap for the heap number and tag it as a heap
2743 // object.
2744 Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required,
2745 tagging_mode == TAG_RESULT ? TAG_OBJECT : NO_ALLOCATION_FLAGS);
2746
2747 Heap::RootListIndex map_index = mode == MUTABLE
2748 ? Heap::kMutableHeapNumberMapRootIndex
2749 : Heap::kHeapNumberMapRootIndex;
2750 AssertIsRoot(heap_number_map, map_index);
2751
2752 // Store heap number map in the allocated object.
2753 if (tagging_mode == TAG_RESULT) {
2754 StoreP(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset),
2755 r0);
2756 } else {
2757 StoreP(heap_number_map, MemOperand(result, HeapObject::kMapOffset));
2758 }
2759}
2760
2761
2762void MacroAssembler::AllocateHeapNumberWithValue(
2763 Register result, DoubleRegister value, Register scratch1, Register scratch2,
2764 Register heap_number_map, Label* gc_required) {
2765 AllocateHeapNumber(result, scratch1, scratch2, heap_number_map, gc_required);
2766 stfd(value, FieldMemOperand(result, HeapNumber::kValueOffset));
2767}
2768
2769
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002770void MacroAssembler::AllocateJSValue(Register result, Register constructor,
2771 Register value, Register scratch1,
2772 Register scratch2, Label* gc_required) {
2773 DCHECK(!result.is(constructor));
2774 DCHECK(!result.is(scratch1));
2775 DCHECK(!result.is(scratch2));
2776 DCHECK(!result.is(value));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002777
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002778 // Allocate JSValue in new space.
2779 Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required, TAG_OBJECT);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002780
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002781 // Initialize the JSValue.
2782 LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2);
2783 StoreP(scratch1, FieldMemOperand(result, HeapObject::kMapOffset), r0);
2784 LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex);
2785 StoreP(scratch1, FieldMemOperand(result, JSObject::kPropertiesOffset), r0);
2786 StoreP(scratch1, FieldMemOperand(result, JSObject::kElementsOffset), r0);
2787 StoreP(value, FieldMemOperand(result, JSValue::kValueOffset), r0);
2788 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002789}
2790
2791
2792void MacroAssembler::CopyBytes(Register src, Register dst, Register length,
2793 Register scratch) {
2794 Label align_loop, aligned, word_loop, byte_loop, byte_loop_1, done;
2795
2796 DCHECK(!scratch.is(r0));
2797
2798 cmpi(length, Operand::Zero());
2799 beq(&done);
2800
2801 // Check src alignment and length to see whether word_loop is possible
2802 andi(scratch, src, Operand(kPointerSize - 1));
2803 beq(&aligned, cr0);
2804 subfic(scratch, scratch, Operand(kPointerSize * 2));
2805 cmp(length, scratch);
2806 blt(&byte_loop);
2807
2808 // Align src before copying in word size chunks.
2809 subi(scratch, scratch, Operand(kPointerSize));
2810 mtctr(scratch);
2811 bind(&align_loop);
2812 lbz(scratch, MemOperand(src));
2813 addi(src, src, Operand(1));
2814 subi(length, length, Operand(1));
2815 stb(scratch, MemOperand(dst));
2816 addi(dst, dst, Operand(1));
2817 bdnz(&align_loop);
2818
2819 bind(&aligned);
2820
2821 // Copy bytes in word size chunks.
2822 if (emit_debug_code()) {
2823 andi(r0, src, Operand(kPointerSize - 1));
2824 Assert(eq, kExpectingAlignmentForCopyBytes, cr0);
2825 }
2826
2827 ShiftRightImm(scratch, length, Operand(kPointerSizeLog2));
2828 cmpi(scratch, Operand::Zero());
2829 beq(&byte_loop);
2830
2831 mtctr(scratch);
2832 bind(&word_loop);
2833 LoadP(scratch, MemOperand(src));
2834 addi(src, src, Operand(kPointerSize));
2835 subi(length, length, Operand(kPointerSize));
2836 if (CpuFeatures::IsSupported(UNALIGNED_ACCESSES)) {
2837 // currently false for PPC - but possible future opt
2838 StoreP(scratch, MemOperand(dst));
2839 addi(dst, dst, Operand(kPointerSize));
2840 } else {
2841#if V8_TARGET_LITTLE_ENDIAN
2842 stb(scratch, MemOperand(dst, 0));
2843 ShiftRightImm(scratch, scratch, Operand(8));
2844 stb(scratch, MemOperand(dst, 1));
2845 ShiftRightImm(scratch, scratch, Operand(8));
2846 stb(scratch, MemOperand(dst, 2));
2847 ShiftRightImm(scratch, scratch, Operand(8));
2848 stb(scratch, MemOperand(dst, 3));
2849#if V8_TARGET_ARCH_PPC64
2850 ShiftRightImm(scratch, scratch, Operand(8));
2851 stb(scratch, MemOperand(dst, 4));
2852 ShiftRightImm(scratch, scratch, Operand(8));
2853 stb(scratch, MemOperand(dst, 5));
2854 ShiftRightImm(scratch, scratch, Operand(8));
2855 stb(scratch, MemOperand(dst, 6));
2856 ShiftRightImm(scratch, scratch, Operand(8));
2857 stb(scratch, MemOperand(dst, 7));
2858#endif
2859#else
2860#if V8_TARGET_ARCH_PPC64
2861 stb(scratch, MemOperand(dst, 7));
2862 ShiftRightImm(scratch, scratch, Operand(8));
2863 stb(scratch, MemOperand(dst, 6));
2864 ShiftRightImm(scratch, scratch, Operand(8));
2865 stb(scratch, MemOperand(dst, 5));
2866 ShiftRightImm(scratch, scratch, Operand(8));
2867 stb(scratch, MemOperand(dst, 4));
2868 ShiftRightImm(scratch, scratch, Operand(8));
2869#endif
2870 stb(scratch, MemOperand(dst, 3));
2871 ShiftRightImm(scratch, scratch, Operand(8));
2872 stb(scratch, MemOperand(dst, 2));
2873 ShiftRightImm(scratch, scratch, Operand(8));
2874 stb(scratch, MemOperand(dst, 1));
2875 ShiftRightImm(scratch, scratch, Operand(8));
2876 stb(scratch, MemOperand(dst, 0));
2877#endif
2878 addi(dst, dst, Operand(kPointerSize));
2879 }
2880 bdnz(&word_loop);
2881
2882 // Copy the last bytes if any left.
2883 cmpi(length, Operand::Zero());
2884 beq(&done);
2885
2886 bind(&byte_loop);
2887 mtctr(length);
2888 bind(&byte_loop_1);
2889 lbz(scratch, MemOperand(src));
2890 addi(src, src, Operand(1));
2891 stb(scratch, MemOperand(dst));
2892 addi(dst, dst, Operand(1));
2893 bdnz(&byte_loop_1);
2894
2895 bind(&done);
2896}
2897
2898
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002899void MacroAssembler::InitializeNFieldsWithFiller(Register current_address,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002900 Register count,
2901 Register filler) {
2902 Label loop;
2903 mtctr(count);
2904 bind(&loop);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002905 StoreP(filler, MemOperand(current_address));
2906 addi(current_address, current_address, Operand(kPointerSize));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002907 bdnz(&loop);
2908}
2909
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002910void MacroAssembler::InitializeFieldsWithFiller(Register current_address,
2911 Register end_address,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002912 Register filler) {
2913 Label done;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002914 sub(r0, end_address, current_address, LeaveOE, SetRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002915 beq(&done, cr0);
2916 ShiftRightImm(r0, r0, Operand(kPointerSizeLog2));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002917 InitializeNFieldsWithFiller(current_address, r0, filler);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002918 bind(&done);
2919}
2920
2921
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002922void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialOneByte(
2923 Register first, Register second, Register scratch1, Register scratch2,
2924 Label* failure) {
2925 const int kFlatOneByteStringMask =
2926 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
2927 const int kFlatOneByteStringTag =
2928 kStringTag | kOneByteStringTag | kSeqStringTag;
2929 andi(scratch1, first, Operand(kFlatOneByteStringMask));
2930 andi(scratch2, second, Operand(kFlatOneByteStringMask));
2931 cmpi(scratch1, Operand(kFlatOneByteStringTag));
2932 bne(failure);
2933 cmpi(scratch2, Operand(kFlatOneByteStringTag));
2934 bne(failure);
2935}
2936
2937
2938void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte(Register type,
2939 Register scratch,
2940 Label* failure) {
2941 const int kFlatOneByteStringMask =
2942 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
2943 const int kFlatOneByteStringTag =
2944 kStringTag | kOneByteStringTag | kSeqStringTag;
2945 andi(scratch, type, Operand(kFlatOneByteStringMask));
2946 cmpi(scratch, Operand(kFlatOneByteStringTag));
2947 bne(failure);
2948}
2949
2950static const int kRegisterPassedArguments = 8;
2951
2952
2953int MacroAssembler::CalculateStackPassedWords(int num_reg_arguments,
2954 int num_double_arguments) {
2955 int stack_passed_words = 0;
2956 if (num_double_arguments > DoubleRegister::kNumRegisters) {
2957 stack_passed_words +=
2958 2 * (num_double_arguments - DoubleRegister::kNumRegisters);
2959 }
2960 // Up to 8 simple arguments are passed in registers r3..r10.
2961 if (num_reg_arguments > kRegisterPassedArguments) {
2962 stack_passed_words += num_reg_arguments - kRegisterPassedArguments;
2963 }
2964 return stack_passed_words;
2965}
2966
2967
2968void MacroAssembler::EmitSeqStringSetCharCheck(Register string, Register index,
2969 Register value,
2970 uint32_t encoding_mask) {
2971 Label is_object;
2972 TestIfSmi(string, r0);
2973 Check(ne, kNonObject, cr0);
2974
2975 LoadP(ip, FieldMemOperand(string, HeapObject::kMapOffset));
2976 lbz(ip, FieldMemOperand(ip, Map::kInstanceTypeOffset));
2977
2978 andi(ip, ip, Operand(kStringRepresentationMask | kStringEncodingMask));
2979 cmpi(ip, Operand(encoding_mask));
2980 Check(eq, kUnexpectedStringType);
2981
2982// The index is assumed to be untagged coming in, tag it to compare with the
2983// string length without using a temp register, it is restored at the end of
2984// this function.
2985#if !V8_TARGET_ARCH_PPC64
2986 Label index_tag_ok, index_tag_bad;
2987 JumpIfNotSmiCandidate(index, r0, &index_tag_bad);
2988#endif
2989 SmiTag(index, index);
2990#if !V8_TARGET_ARCH_PPC64
2991 b(&index_tag_ok);
2992 bind(&index_tag_bad);
2993 Abort(kIndexIsTooLarge);
2994 bind(&index_tag_ok);
2995#endif
2996
2997 LoadP(ip, FieldMemOperand(string, String::kLengthOffset));
2998 cmp(index, ip);
2999 Check(lt, kIndexIsTooLarge);
3000
3001 DCHECK(Smi::FromInt(0) == 0);
3002 cmpi(index, Operand::Zero());
3003 Check(ge, kIndexIsNegative);
3004
3005 SmiUntag(index, index);
3006}
3007
3008
3009void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
3010 int num_double_arguments,
3011 Register scratch) {
3012 int frame_alignment = ActivationFrameAlignment();
3013 int stack_passed_arguments =
3014 CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
3015 int stack_space = kNumRequiredStackFrameSlots;
3016
3017 if (frame_alignment > kPointerSize) {
3018 // Make stack end at alignment and make room for stack arguments
3019 // -- preserving original value of sp.
3020 mr(scratch, sp);
3021 addi(sp, sp, Operand(-(stack_passed_arguments + 1) * kPointerSize));
3022 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
3023 ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
3024 StoreP(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
3025 } else {
3026 // Make room for stack arguments
3027 stack_space += stack_passed_arguments;
3028 }
3029
3030 // Allocate frame with required slots to make ABI work.
3031 li(r0, Operand::Zero());
3032 StorePU(r0, MemOperand(sp, -stack_space * kPointerSize));
3033}
3034
3035
3036void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
3037 Register scratch) {
3038 PrepareCallCFunction(num_reg_arguments, 0, scratch);
3039}
3040
3041
3042void MacroAssembler::MovToFloatParameter(DoubleRegister src) { Move(d1, src); }
3043
3044
3045void MacroAssembler::MovToFloatResult(DoubleRegister src) { Move(d1, src); }
3046
3047
3048void MacroAssembler::MovToFloatParameters(DoubleRegister src1,
3049 DoubleRegister src2) {
3050 if (src2.is(d1)) {
3051 DCHECK(!src1.is(d2));
3052 Move(d2, src2);
3053 Move(d1, src1);
3054 } else {
3055 Move(d1, src1);
3056 Move(d2, src2);
3057 }
3058}
3059
3060
3061void MacroAssembler::CallCFunction(ExternalReference function,
3062 int num_reg_arguments,
3063 int num_double_arguments) {
3064 mov(ip, Operand(function));
3065 CallCFunctionHelper(ip, num_reg_arguments, num_double_arguments);
3066}
3067
3068
3069void MacroAssembler::CallCFunction(Register function, int num_reg_arguments,
3070 int num_double_arguments) {
3071 CallCFunctionHelper(function, num_reg_arguments, num_double_arguments);
3072}
3073
3074
3075void MacroAssembler::CallCFunction(ExternalReference function,
3076 int num_arguments) {
3077 CallCFunction(function, num_arguments, 0);
3078}
3079
3080
3081void MacroAssembler::CallCFunction(Register function, int num_arguments) {
3082 CallCFunction(function, num_arguments, 0);
3083}
3084
3085
3086void MacroAssembler::CallCFunctionHelper(Register function,
3087 int num_reg_arguments,
3088 int num_double_arguments) {
3089 DCHECK(has_frame());
3090// Just call directly. The function called cannot cause a GC, or
3091// allow preemption, so the return address in the link register
3092// stays correct.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003093 Register dest = function;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003094#if ABI_USES_FUNCTION_DESCRIPTORS && !defined(USE_SIMULATOR)
3095 // AIX uses a function descriptor. When calling C code be aware
3096 // of this descriptor and pick up values from it
3097 LoadP(ToRegister(ABI_TOC_REGISTER), MemOperand(function, kPointerSize));
3098 LoadP(ip, MemOperand(function, 0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003099 dest = ip;
3100#elif ABI_CALL_VIA_IP
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003101 Move(ip, function);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003102 dest = ip;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003103#endif
3104
3105 Call(dest);
3106
3107 // Remove frame bought in PrepareCallCFunction
3108 int stack_passed_arguments =
3109 CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
3110 int stack_space = kNumRequiredStackFrameSlots + stack_passed_arguments;
3111 if (ActivationFrameAlignment() > kPointerSize) {
3112 LoadP(sp, MemOperand(sp, stack_space * kPointerSize));
3113 } else {
3114 addi(sp, sp, Operand(stack_space * kPointerSize));
3115 }
3116}
3117
3118
3119void MacroAssembler::FlushICache(Register address, size_t size,
3120 Register scratch) {
3121 if (CpuFeatures::IsSupported(INSTR_AND_DATA_CACHE_COHERENCY)) {
3122 sync();
3123 icbi(r0, address);
3124 isync();
3125 return;
3126 }
3127
3128 Label done;
3129
3130 dcbf(r0, address);
3131 sync();
3132 icbi(r0, address);
3133 isync();
3134
3135 // This code handles ranges which cross a single cacheline boundary.
3136 // scratch is last cacheline which intersects range.
3137 const int kCacheLineSizeLog2 = WhichPowerOf2(CpuFeatures::cache_line_size());
3138
3139 DCHECK(size > 0 && size <= (size_t)(1 << kCacheLineSizeLog2));
3140 addi(scratch, address, Operand(size - 1));
3141 ClearRightImm(scratch, scratch, Operand(kCacheLineSizeLog2));
3142 cmpl(scratch, address);
3143 ble(&done);
3144
3145 dcbf(r0, scratch);
3146 sync();
3147 icbi(r0, scratch);
3148 isync();
3149
3150 bind(&done);
3151}
3152
3153
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003154void MacroAssembler::DecodeConstantPoolOffset(Register result,
3155 Register location) {
3156 Label overflow_access, done;
3157 DCHECK(!AreAliased(result, location, r0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003158
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003159 // Determine constant pool access type
3160 // Caller has already placed the instruction word at location in result.
3161 ExtractBitRange(r0, result, 31, 26);
3162 cmpi(r0, Operand(ADDIS >> 26));
3163 beq(&overflow_access);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003164
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003165 // Regular constant pool access
3166 // extract the load offset
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003167 andi(result, result, Operand(kImm16Mask));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003168 b(&done);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003169
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003170 bind(&overflow_access);
3171 // Overflow constant pool access
3172 // shift addis immediate
3173 slwi(r0, result, Operand(16));
3174 // sign-extend and add the load offset
3175 lwz(result, MemOperand(location, kInstrSize));
3176 extsh(result, result);
3177 add(result, r0, result);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003178
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003179 bind(&done);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003180}
3181
3182
3183void MacroAssembler::CheckPageFlag(
3184 Register object,
3185 Register scratch, // scratch may be same register as object
3186 int mask, Condition cc, Label* condition_met) {
3187 DCHECK(cc == ne || cc == eq);
3188 ClearRightImm(scratch, object, Operand(kPageSizeBits));
3189 LoadP(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset));
3190
3191 And(r0, scratch, Operand(mask), SetRC);
3192
3193 if (cc == ne) {
3194 bne(condition_met, cr0);
3195 }
3196 if (cc == eq) {
3197 beq(condition_met, cr0);
3198 }
3199}
3200
3201
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003202void MacroAssembler::JumpIfBlack(Register object, Register scratch0,
3203 Register scratch1, Label* on_black) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003204 HasColor(object, scratch0, scratch1, on_black, 1, 1); // kBlackBitPattern.
3205 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003206}
3207
3208
3209void MacroAssembler::HasColor(Register object, Register bitmap_scratch,
3210 Register mask_scratch, Label* has_color,
3211 int first_bit, int second_bit) {
3212 DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, no_reg));
3213
3214 GetMarkBits(object, bitmap_scratch, mask_scratch);
3215
3216 Label other_color, word_boundary;
3217 lwz(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
3218 // Test the first bit
3219 and_(r0, ip, mask_scratch, SetRC);
3220 b(first_bit == 1 ? eq : ne, &other_color, cr0);
3221 // Shift left 1
3222 // May need to load the next cell
3223 slwi(mask_scratch, mask_scratch, Operand(1), SetRC);
3224 beq(&word_boundary, cr0);
3225 // Test the second bit
3226 and_(r0, ip, mask_scratch, SetRC);
3227 b(second_bit == 1 ? ne : eq, has_color, cr0);
3228 b(&other_color);
3229
3230 bind(&word_boundary);
3231 lwz(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize + kIntSize));
3232 andi(r0, ip, Operand(1));
3233 b(second_bit == 1 ? ne : eq, has_color, cr0);
3234 bind(&other_color);
3235}
3236
3237
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003238void MacroAssembler::GetMarkBits(Register addr_reg, Register bitmap_reg,
3239 Register mask_reg) {
3240 DCHECK(!AreAliased(addr_reg, bitmap_reg, mask_reg, no_reg));
3241 DCHECK((~Page::kPageAlignmentMask & 0xffff) == 0);
3242 lis(r0, Operand((~Page::kPageAlignmentMask >> 16)));
3243 and_(bitmap_reg, addr_reg, r0);
3244 const int kLowBits = kPointerSizeLog2 + Bitmap::kBitsPerCellLog2;
3245 ExtractBitRange(mask_reg, addr_reg, kLowBits - 1, kPointerSizeLog2);
3246 ExtractBitRange(ip, addr_reg, kPageSizeBits - 1, kLowBits);
3247 ShiftLeftImm(ip, ip, Operand(Bitmap::kBytesPerCellLog2));
3248 add(bitmap_reg, bitmap_reg, ip);
3249 li(ip, Operand(1));
3250 slw(mask_reg, ip, mask_reg);
3251}
3252
3253
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003254void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch,
3255 Register mask_scratch, Register load_scratch,
3256 Label* value_is_white) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003257 DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, ip));
3258 GetMarkBits(value, bitmap_scratch, mask_scratch);
3259
3260 // If the value is black or grey we don't need to do anything.
3261 DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003262 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
3263 DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003264 DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
3265
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003266 // Since both black and grey have a 1 in the first position and white does
3267 // not have a 1 there we only need to check one bit.
3268 lwz(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
3269 and_(r0, mask_scratch, load_scratch, SetRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003270 beq(value_is_white, cr0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003271}
3272
3273
3274// Saturate a value into 8-bit unsigned integer
3275// if input_value < 0, output_value is 0
3276// if input_value > 255, output_value is 255
3277// otherwise output_value is the input_value
3278void MacroAssembler::ClampUint8(Register output_reg, Register input_reg) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003279 int satval = (1 << 8) - 1;
3280
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003281 if (CpuFeatures::IsSupported(ISELECT)) {
3282 // set to 0 if negative
3283 cmpi(input_reg, Operand::Zero());
3284 isel(lt, output_reg, r0, input_reg);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003285
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003286 // set to satval if > satval
3287 li(r0, Operand(satval));
3288 cmpi(output_reg, Operand(satval));
3289 isel(lt, output_reg, output_reg, r0);
3290 } else {
3291 Label done, negative_label, overflow_label;
3292 cmpi(input_reg, Operand::Zero());
3293 blt(&negative_label);
3294
3295 cmpi(input_reg, Operand(satval));
3296 bgt(&overflow_label);
3297 if (!output_reg.is(input_reg)) {
3298 mr(output_reg, input_reg);
3299 }
3300 b(&done);
3301
3302 bind(&negative_label);
3303 li(output_reg, Operand::Zero()); // set to 0 if negative
3304 b(&done);
3305
3306 bind(&overflow_label); // set to satval if > satval
3307 li(output_reg, Operand(satval));
3308
3309 bind(&done);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003310 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003311}
3312
3313
3314void MacroAssembler::SetRoundingMode(FPRoundingMode RN) { mtfsfi(7, RN); }
3315
3316
3317void MacroAssembler::ResetRoundingMode() {
3318 mtfsfi(7, kRoundToNearest); // reset (default is kRoundToNearest)
3319}
3320
3321
3322void MacroAssembler::ClampDoubleToUint8(Register result_reg,
3323 DoubleRegister input_reg,
3324 DoubleRegister double_scratch) {
3325 Label above_zero;
3326 Label done;
3327 Label in_bounds;
3328
3329 LoadDoubleLiteral(double_scratch, 0.0, result_reg);
3330 fcmpu(input_reg, double_scratch);
3331 bgt(&above_zero);
3332
3333 // Double value is less than zero, NaN or Inf, return 0.
3334 LoadIntLiteral(result_reg, 0);
3335 b(&done);
3336
3337 // Double value is >= 255, return 255.
3338 bind(&above_zero);
3339 LoadDoubleLiteral(double_scratch, 255.0, result_reg);
3340 fcmpu(input_reg, double_scratch);
3341 ble(&in_bounds);
3342 LoadIntLiteral(result_reg, 255);
3343 b(&done);
3344
3345 // In 0-255 range, round and truncate.
3346 bind(&in_bounds);
3347
3348 // round to nearest (default rounding mode)
3349 fctiw(double_scratch, input_reg);
3350 MovDoubleLowToInt(result_reg, double_scratch);
3351 bind(&done);
3352}
3353
3354
3355void MacroAssembler::LoadInstanceDescriptors(Register map,
3356 Register descriptors) {
3357 LoadP(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset));
3358}
3359
3360
3361void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) {
3362 lwz(dst, FieldMemOperand(map, Map::kBitField3Offset));
3363 DecodeField<Map::NumberOfOwnDescriptorsBits>(dst);
3364}
3365
3366
3367void MacroAssembler::EnumLength(Register dst, Register map) {
3368 STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
3369 lwz(dst, FieldMemOperand(map, Map::kBitField3Offset));
3370 ExtractBitMask(dst, dst, Map::EnumLengthBits::kMask);
3371 SmiTag(dst);
3372}
3373
3374
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003375void MacroAssembler::LoadAccessor(Register dst, Register holder,
3376 int accessor_index,
3377 AccessorComponent accessor) {
3378 LoadP(dst, FieldMemOperand(holder, HeapObject::kMapOffset));
3379 LoadInstanceDescriptors(dst, dst);
3380 LoadP(dst,
3381 FieldMemOperand(dst, DescriptorArray::GetValueOffset(accessor_index)));
3382 const int getterOffset = AccessorPair::kGetterOffset;
3383 const int setterOffset = AccessorPair::kSetterOffset;
3384 int offset = ((accessor == ACCESSOR_GETTER) ? getterOffset : setterOffset);
3385 LoadP(dst, FieldMemOperand(dst, offset));
3386}
3387
3388
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003389void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) {
3390 Register empty_fixed_array_value = r9;
3391 LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
3392 Label next, start;
3393 mr(r5, r3);
3394
3395 // Check if the enum length field is properly initialized, indicating that
3396 // there is an enum cache.
3397 LoadP(r4, FieldMemOperand(r5, HeapObject::kMapOffset));
3398
3399 EnumLength(r6, r4);
3400 CmpSmiLiteral(r6, Smi::FromInt(kInvalidEnumCacheSentinel), r0);
3401 beq(call_runtime);
3402
3403 b(&start);
3404
3405 bind(&next);
3406 LoadP(r4, FieldMemOperand(r5, HeapObject::kMapOffset));
3407
3408 // For all objects but the receiver, check that the cache is empty.
3409 EnumLength(r6, r4);
3410 CmpSmiLiteral(r6, Smi::FromInt(0), r0);
3411 bne(call_runtime);
3412
3413 bind(&start);
3414
3415 // Check that there are no elements. Register r5 contains the current JS
3416 // object we've reached through the prototype chain.
3417 Label no_elements;
3418 LoadP(r5, FieldMemOperand(r5, JSObject::kElementsOffset));
3419 cmp(r5, empty_fixed_array_value);
3420 beq(&no_elements);
3421
3422 // Second chance, the object may be using the empty slow element dictionary.
3423 CompareRoot(r5, Heap::kEmptySlowElementDictionaryRootIndex);
3424 bne(call_runtime);
3425
3426 bind(&no_elements);
3427 LoadP(r5, FieldMemOperand(r4, Map::kPrototypeOffset));
3428 cmp(r5, null_value);
3429 bne(&next);
3430}
3431
3432
3433////////////////////////////////////////////////////////////////////////////////
3434//
3435// New MacroAssembler Interfaces added for PPC
3436//
3437////////////////////////////////////////////////////////////////////////////////
3438void MacroAssembler::LoadIntLiteral(Register dst, int value) {
3439 mov(dst, Operand(value));
3440}
3441
3442
3443void MacroAssembler::LoadSmiLiteral(Register dst, Smi* smi) {
3444 mov(dst, Operand(smi));
3445}
3446
3447
3448void MacroAssembler::LoadDoubleLiteral(DoubleRegister result, double value,
3449 Register scratch) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003450 if (FLAG_enable_embedded_constant_pool && is_constant_pool_available() &&
3451 !(scratch.is(r0) && ConstantPoolAccessIsInOverflow())) {
3452 ConstantPoolEntry::Access access = ConstantPoolAddEntry(value);
3453 if (access == ConstantPoolEntry::OVERFLOWED) {
3454 addis(scratch, kConstantPoolRegister, Operand::Zero());
3455 lfd(result, MemOperand(scratch, 0));
3456 } else {
3457 lfd(result, MemOperand(kConstantPoolRegister, 0));
3458 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003459 return;
3460 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003461
3462 // avoid gcc strict aliasing error using union cast
3463 union {
3464 double dval;
3465#if V8_TARGET_ARCH_PPC64
3466 intptr_t ival;
3467#else
3468 intptr_t ival[2];
3469#endif
3470 } litVal;
3471
3472 litVal.dval = value;
3473
3474#if V8_TARGET_ARCH_PPC64
3475 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
3476 mov(scratch, Operand(litVal.ival));
3477 mtfprd(result, scratch);
3478 return;
3479 }
3480#endif
3481
3482 addi(sp, sp, Operand(-kDoubleSize));
3483#if V8_TARGET_ARCH_PPC64
3484 mov(scratch, Operand(litVal.ival));
3485 std(scratch, MemOperand(sp));
3486#else
3487 LoadIntLiteral(scratch, litVal.ival[0]);
3488 stw(scratch, MemOperand(sp, 0));
3489 LoadIntLiteral(scratch, litVal.ival[1]);
3490 stw(scratch, MemOperand(sp, 4));
3491#endif
3492 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
3493 lfd(result, MemOperand(sp, 0));
3494 addi(sp, sp, Operand(kDoubleSize));
3495}
3496
3497
3498void MacroAssembler::MovIntToDouble(DoubleRegister dst, Register src,
3499 Register scratch) {
3500// sign-extend src to 64-bit
3501#if V8_TARGET_ARCH_PPC64
3502 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
3503 mtfprwa(dst, src);
3504 return;
3505 }
3506#endif
3507
3508 DCHECK(!src.is(scratch));
3509 subi(sp, sp, Operand(kDoubleSize));
3510#if V8_TARGET_ARCH_PPC64
3511 extsw(scratch, src);
3512 std(scratch, MemOperand(sp, 0));
3513#else
3514 srawi(scratch, src, 31);
3515 stw(scratch, MemOperand(sp, Register::kExponentOffset));
3516 stw(src, MemOperand(sp, Register::kMantissaOffset));
3517#endif
3518 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
3519 lfd(dst, MemOperand(sp, 0));
3520 addi(sp, sp, Operand(kDoubleSize));
3521}
3522
3523
3524void MacroAssembler::MovUnsignedIntToDouble(DoubleRegister dst, Register src,
3525 Register scratch) {
3526// zero-extend src to 64-bit
3527#if V8_TARGET_ARCH_PPC64
3528 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
3529 mtfprwz(dst, src);
3530 return;
3531 }
3532#endif
3533
3534 DCHECK(!src.is(scratch));
3535 subi(sp, sp, Operand(kDoubleSize));
3536#if V8_TARGET_ARCH_PPC64
3537 clrldi(scratch, src, Operand(32));
3538 std(scratch, MemOperand(sp, 0));
3539#else
3540 li(scratch, Operand::Zero());
3541 stw(scratch, MemOperand(sp, Register::kExponentOffset));
3542 stw(src, MemOperand(sp, Register::kMantissaOffset));
3543#endif
3544 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
3545 lfd(dst, MemOperand(sp, 0));
3546 addi(sp, sp, Operand(kDoubleSize));
3547}
3548
3549
3550void MacroAssembler::MovInt64ToDouble(DoubleRegister dst,
3551#if !V8_TARGET_ARCH_PPC64
3552 Register src_hi,
3553#endif
3554 Register src) {
3555#if V8_TARGET_ARCH_PPC64
3556 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
3557 mtfprd(dst, src);
3558 return;
3559 }
3560#endif
3561
3562 subi(sp, sp, Operand(kDoubleSize));
3563#if V8_TARGET_ARCH_PPC64
3564 std(src, MemOperand(sp, 0));
3565#else
3566 stw(src_hi, MemOperand(sp, Register::kExponentOffset));
3567 stw(src, MemOperand(sp, Register::kMantissaOffset));
3568#endif
3569 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
3570 lfd(dst, MemOperand(sp, 0));
3571 addi(sp, sp, Operand(kDoubleSize));
3572}
3573
3574
3575#if V8_TARGET_ARCH_PPC64
3576void MacroAssembler::MovInt64ComponentsToDouble(DoubleRegister dst,
3577 Register src_hi,
3578 Register src_lo,
3579 Register scratch) {
3580 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
3581 sldi(scratch, src_hi, Operand(32));
3582 rldimi(scratch, src_lo, 0, 32);
3583 mtfprd(dst, scratch);
3584 return;
3585 }
3586
3587 subi(sp, sp, Operand(kDoubleSize));
3588 stw(src_hi, MemOperand(sp, Register::kExponentOffset));
3589 stw(src_lo, MemOperand(sp, Register::kMantissaOffset));
3590 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
3591 lfd(dst, MemOperand(sp));
3592 addi(sp, sp, Operand(kDoubleSize));
3593}
3594#endif
3595
3596
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003597void MacroAssembler::InsertDoubleLow(DoubleRegister dst, Register src,
3598 Register scratch) {
3599#if V8_TARGET_ARCH_PPC64
3600 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
3601 mffprd(scratch, dst);
3602 rldimi(scratch, src, 0, 32);
3603 mtfprd(dst, scratch);
3604 return;
3605 }
3606#endif
3607
3608 subi(sp, sp, Operand(kDoubleSize));
3609 stfd(dst, MemOperand(sp));
3610 stw(src, MemOperand(sp, Register::kMantissaOffset));
3611 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
3612 lfd(dst, MemOperand(sp));
3613 addi(sp, sp, Operand(kDoubleSize));
3614}
3615
3616
3617void MacroAssembler::InsertDoubleHigh(DoubleRegister dst, Register src,
3618 Register scratch) {
3619#if V8_TARGET_ARCH_PPC64
3620 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
3621 mffprd(scratch, dst);
3622 rldimi(scratch, src, 32, 0);
3623 mtfprd(dst, scratch);
3624 return;
3625 }
3626#endif
3627
3628 subi(sp, sp, Operand(kDoubleSize));
3629 stfd(dst, MemOperand(sp));
3630 stw(src, MemOperand(sp, Register::kExponentOffset));
3631 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
3632 lfd(dst, MemOperand(sp));
3633 addi(sp, sp, Operand(kDoubleSize));
3634}
3635
3636
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003637void MacroAssembler::MovDoubleLowToInt(Register dst, DoubleRegister src) {
3638#if V8_TARGET_ARCH_PPC64
3639 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
3640 mffprwz(dst, src);
3641 return;
3642 }
3643#endif
3644
3645 subi(sp, sp, Operand(kDoubleSize));
3646 stfd(src, MemOperand(sp));
3647 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
3648 lwz(dst, MemOperand(sp, Register::kMantissaOffset));
3649 addi(sp, sp, Operand(kDoubleSize));
3650}
3651
3652
3653void MacroAssembler::MovDoubleHighToInt(Register dst, DoubleRegister src) {
3654#if V8_TARGET_ARCH_PPC64
3655 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
3656 mffprd(dst, src);
3657 srdi(dst, dst, Operand(32));
3658 return;
3659 }
3660#endif
3661
3662 subi(sp, sp, Operand(kDoubleSize));
3663 stfd(src, MemOperand(sp));
3664 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
3665 lwz(dst, MemOperand(sp, Register::kExponentOffset));
3666 addi(sp, sp, Operand(kDoubleSize));
3667}
3668
3669
3670void MacroAssembler::MovDoubleToInt64(
3671#if !V8_TARGET_ARCH_PPC64
3672 Register dst_hi,
3673#endif
3674 Register dst, DoubleRegister src) {
3675#if V8_TARGET_ARCH_PPC64
3676 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
3677 mffprd(dst, src);
3678 return;
3679 }
3680#endif
3681
3682 subi(sp, sp, Operand(kDoubleSize));
3683 stfd(src, MemOperand(sp));
3684 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
3685#if V8_TARGET_ARCH_PPC64
3686 ld(dst, MemOperand(sp, 0));
3687#else
3688 lwz(dst_hi, MemOperand(sp, Register::kExponentOffset));
3689 lwz(dst, MemOperand(sp, Register::kMantissaOffset));
3690#endif
3691 addi(sp, sp, Operand(kDoubleSize));
3692}
3693
3694
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003695void MacroAssembler::MovIntToFloat(DoubleRegister dst, Register src) {
3696 subi(sp, sp, Operand(kFloatSize));
3697 stw(src, MemOperand(sp, 0));
3698 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
3699 lfs(dst, MemOperand(sp, 0));
3700 addi(sp, sp, Operand(kFloatSize));
3701}
3702
3703
3704void MacroAssembler::MovFloatToInt(Register dst, DoubleRegister src) {
3705 subi(sp, sp, Operand(kFloatSize));
3706 frsp(src, src);
3707 stfs(src, MemOperand(sp, 0));
3708 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
3709 lwz(dst, MemOperand(sp, 0));
3710 addi(sp, sp, Operand(kFloatSize));
3711}
3712
3713
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003714void MacroAssembler::Add(Register dst, Register src, intptr_t value,
3715 Register scratch) {
3716 if (is_int16(value)) {
3717 addi(dst, src, Operand(value));
3718 } else {
3719 mov(scratch, Operand(value));
3720 add(dst, src, scratch);
3721 }
3722}
3723
3724
3725void MacroAssembler::Cmpi(Register src1, const Operand& src2, Register scratch,
3726 CRegister cr) {
3727 intptr_t value = src2.immediate();
3728 if (is_int16(value)) {
3729 cmpi(src1, src2, cr);
3730 } else {
3731 mov(scratch, src2);
3732 cmp(src1, scratch, cr);
3733 }
3734}
3735
3736
3737void MacroAssembler::Cmpli(Register src1, const Operand& src2, Register scratch,
3738 CRegister cr) {
3739 intptr_t value = src2.immediate();
3740 if (is_uint16(value)) {
3741 cmpli(src1, src2, cr);
3742 } else {
3743 mov(scratch, src2);
3744 cmpl(src1, scratch, cr);
3745 }
3746}
3747
3748
3749void MacroAssembler::Cmpwi(Register src1, const Operand& src2, Register scratch,
3750 CRegister cr) {
3751 intptr_t value = src2.immediate();
3752 if (is_int16(value)) {
3753 cmpwi(src1, src2, cr);
3754 } else {
3755 mov(scratch, src2);
3756 cmpw(src1, scratch, cr);
3757 }
3758}
3759
3760
3761void MacroAssembler::Cmplwi(Register src1, const Operand& src2,
3762 Register scratch, CRegister cr) {
3763 intptr_t value = src2.immediate();
3764 if (is_uint16(value)) {
3765 cmplwi(src1, src2, cr);
3766 } else {
3767 mov(scratch, src2);
3768 cmplw(src1, scratch, cr);
3769 }
3770}
3771
3772
3773void MacroAssembler::And(Register ra, Register rs, const Operand& rb,
3774 RCBit rc) {
3775 if (rb.is_reg()) {
3776 and_(ra, rs, rb.rm(), rc);
3777 } else {
3778 if (is_uint16(rb.imm_) && RelocInfo::IsNone(rb.rmode_) && rc == SetRC) {
3779 andi(ra, rs, rb);
3780 } else {
3781 // mov handles the relocation.
3782 DCHECK(!rs.is(r0));
3783 mov(r0, rb);
3784 and_(ra, rs, r0, rc);
3785 }
3786 }
3787}
3788
3789
3790void MacroAssembler::Or(Register ra, Register rs, const Operand& rb, RCBit rc) {
3791 if (rb.is_reg()) {
3792 orx(ra, rs, rb.rm(), rc);
3793 } else {
3794 if (is_uint16(rb.imm_) && RelocInfo::IsNone(rb.rmode_) && rc == LeaveRC) {
3795 ori(ra, rs, rb);
3796 } else {
3797 // mov handles the relocation.
3798 DCHECK(!rs.is(r0));
3799 mov(r0, rb);
3800 orx(ra, rs, r0, rc);
3801 }
3802 }
3803}
3804
3805
3806void MacroAssembler::Xor(Register ra, Register rs, const Operand& rb,
3807 RCBit rc) {
3808 if (rb.is_reg()) {
3809 xor_(ra, rs, rb.rm(), rc);
3810 } else {
3811 if (is_uint16(rb.imm_) && RelocInfo::IsNone(rb.rmode_) && rc == LeaveRC) {
3812 xori(ra, rs, rb);
3813 } else {
3814 // mov handles the relocation.
3815 DCHECK(!rs.is(r0));
3816 mov(r0, rb);
3817 xor_(ra, rs, r0, rc);
3818 }
3819 }
3820}
3821
3822
3823void MacroAssembler::CmpSmiLiteral(Register src1, Smi* smi, Register scratch,
3824 CRegister cr) {
3825#if V8_TARGET_ARCH_PPC64
3826 LoadSmiLiteral(scratch, smi);
3827 cmp(src1, scratch, cr);
3828#else
3829 Cmpi(src1, Operand(smi), scratch, cr);
3830#endif
3831}
3832
3833
3834void MacroAssembler::CmplSmiLiteral(Register src1, Smi* smi, Register scratch,
3835 CRegister cr) {
3836#if V8_TARGET_ARCH_PPC64
3837 LoadSmiLiteral(scratch, smi);
3838 cmpl(src1, scratch, cr);
3839#else
3840 Cmpli(src1, Operand(smi), scratch, cr);
3841#endif
3842}
3843
3844
3845void MacroAssembler::AddSmiLiteral(Register dst, Register src, Smi* smi,
3846 Register scratch) {
3847#if V8_TARGET_ARCH_PPC64
3848 LoadSmiLiteral(scratch, smi);
3849 add(dst, src, scratch);
3850#else
3851 Add(dst, src, reinterpret_cast<intptr_t>(smi), scratch);
3852#endif
3853}
3854
3855
3856void MacroAssembler::SubSmiLiteral(Register dst, Register src, Smi* smi,
3857 Register scratch) {
3858#if V8_TARGET_ARCH_PPC64
3859 LoadSmiLiteral(scratch, smi);
3860 sub(dst, src, scratch);
3861#else
3862 Add(dst, src, -(reinterpret_cast<intptr_t>(smi)), scratch);
3863#endif
3864}
3865
3866
3867void MacroAssembler::AndSmiLiteral(Register dst, Register src, Smi* smi,
3868 Register scratch, RCBit rc) {
3869#if V8_TARGET_ARCH_PPC64
3870 LoadSmiLiteral(scratch, smi);
3871 and_(dst, src, scratch, rc);
3872#else
3873 And(dst, src, Operand(smi), rc);
3874#endif
3875}
3876
3877
3878// Load a "pointer" sized value from the memory location
3879void MacroAssembler::LoadP(Register dst, const MemOperand& mem,
3880 Register scratch) {
3881 int offset = mem.offset();
3882
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003883 if (!is_int16(offset)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003884 /* cannot use d-form */
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003885 DCHECK(!scratch.is(no_reg));
3886 mov(scratch, Operand(offset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003887#if V8_TARGET_ARCH_PPC64
3888 ldx(dst, MemOperand(mem.ra(), scratch));
3889#else
3890 lwzx(dst, MemOperand(mem.ra(), scratch));
3891#endif
3892 } else {
3893#if V8_TARGET_ARCH_PPC64
3894 int misaligned = (offset & 3);
3895 if (misaligned) {
3896 // adjust base to conform to offset alignment requirements
3897 // Todo: enhance to use scratch if dst is unsuitable
3898 DCHECK(!dst.is(r0));
3899 addi(dst, mem.ra(), Operand((offset & 3) - 4));
3900 ld(dst, MemOperand(dst, (offset & ~3) + 4));
3901 } else {
3902 ld(dst, mem);
3903 }
3904#else
3905 lwz(dst, mem);
3906#endif
3907 }
3908}
3909
3910
3911// Store a "pointer" sized value to the memory location
3912void MacroAssembler::StoreP(Register src, const MemOperand& mem,
3913 Register scratch) {
3914 int offset = mem.offset();
3915
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003916 if (!is_int16(offset)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003917 /* cannot use d-form */
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003918 DCHECK(!scratch.is(no_reg));
3919 mov(scratch, Operand(offset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003920#if V8_TARGET_ARCH_PPC64
3921 stdx(src, MemOperand(mem.ra(), scratch));
3922#else
3923 stwx(src, MemOperand(mem.ra(), scratch));
3924#endif
3925 } else {
3926#if V8_TARGET_ARCH_PPC64
3927 int misaligned = (offset & 3);
3928 if (misaligned) {
3929 // adjust base to conform to offset alignment requirements
3930 // a suitable scratch is required here
3931 DCHECK(!scratch.is(no_reg));
3932 if (scratch.is(r0)) {
3933 LoadIntLiteral(scratch, offset);
3934 stdx(src, MemOperand(mem.ra(), scratch));
3935 } else {
3936 addi(scratch, mem.ra(), Operand((offset & 3) - 4));
3937 std(src, MemOperand(scratch, (offset & ~3) + 4));
3938 }
3939 } else {
3940 std(src, mem);
3941 }
3942#else
3943 stw(src, mem);
3944#endif
3945 }
3946}
3947
3948void MacroAssembler::LoadWordArith(Register dst, const MemOperand& mem,
3949 Register scratch) {
3950 int offset = mem.offset();
3951
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003952 if (!is_int16(offset)) {
3953 DCHECK(!scratch.is(no_reg));
3954 mov(scratch, Operand(offset));
3955 lwax(dst, MemOperand(mem.ra(), scratch));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003956 } else {
3957#if V8_TARGET_ARCH_PPC64
3958 int misaligned = (offset & 3);
3959 if (misaligned) {
3960 // adjust base to conform to offset alignment requirements
3961 // Todo: enhance to use scratch if dst is unsuitable
3962 DCHECK(!dst.is(r0));
3963 addi(dst, mem.ra(), Operand((offset & 3) - 4));
3964 lwa(dst, MemOperand(dst, (offset & ~3) + 4));
3965 } else {
3966 lwa(dst, mem);
3967 }
3968#else
3969 lwz(dst, mem);
3970#endif
3971 }
3972}
3973
3974
3975// Variable length depending on whether offset fits into immediate field
3976// MemOperand currently only supports d-form
3977void MacroAssembler::LoadWord(Register dst, const MemOperand& mem,
3978 Register scratch) {
3979 Register base = mem.ra();
3980 int offset = mem.offset();
3981
3982 if (!is_int16(offset)) {
3983 LoadIntLiteral(scratch, offset);
3984 lwzx(dst, MemOperand(base, scratch));
3985 } else {
3986 lwz(dst, mem);
3987 }
3988}
3989
3990
3991// Variable length depending on whether offset fits into immediate field
3992// MemOperand current only supports d-form
3993void MacroAssembler::StoreWord(Register src, const MemOperand& mem,
3994 Register scratch) {
3995 Register base = mem.ra();
3996 int offset = mem.offset();
3997
3998 if (!is_int16(offset)) {
3999 LoadIntLiteral(scratch, offset);
4000 stwx(src, MemOperand(base, scratch));
4001 } else {
4002 stw(src, mem);
4003 }
4004}
4005
4006
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004007void MacroAssembler::LoadHalfWordArith(Register dst, const MemOperand& mem,
4008 Register scratch) {
4009 int offset = mem.offset();
4010
4011 if (!is_int16(offset)) {
4012 DCHECK(!scratch.is(no_reg));
4013 mov(scratch, Operand(offset));
4014 lhax(dst, MemOperand(mem.ra(), scratch));
4015 } else {
4016 lha(dst, mem);
4017 }
4018}
4019
4020
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004021// Variable length depending on whether offset fits into immediate field
4022// MemOperand currently only supports d-form
4023void MacroAssembler::LoadHalfWord(Register dst, const MemOperand& mem,
4024 Register scratch) {
4025 Register base = mem.ra();
4026 int offset = mem.offset();
4027
4028 if (!is_int16(offset)) {
4029 LoadIntLiteral(scratch, offset);
4030 lhzx(dst, MemOperand(base, scratch));
4031 } else {
4032 lhz(dst, mem);
4033 }
4034}
4035
4036
4037// Variable length depending on whether offset fits into immediate field
4038// MemOperand current only supports d-form
4039void MacroAssembler::StoreHalfWord(Register src, const MemOperand& mem,
4040 Register scratch) {
4041 Register base = mem.ra();
4042 int offset = mem.offset();
4043
4044 if (!is_int16(offset)) {
4045 LoadIntLiteral(scratch, offset);
4046 sthx(src, MemOperand(base, scratch));
4047 } else {
4048 sth(src, mem);
4049 }
4050}
4051
4052
4053// Variable length depending on whether offset fits into immediate field
4054// MemOperand currently only supports d-form
4055void MacroAssembler::LoadByte(Register dst, const MemOperand& mem,
4056 Register scratch) {
4057 Register base = mem.ra();
4058 int offset = mem.offset();
4059
4060 if (!is_int16(offset)) {
4061 LoadIntLiteral(scratch, offset);
4062 lbzx(dst, MemOperand(base, scratch));
4063 } else {
4064 lbz(dst, mem);
4065 }
4066}
4067
4068
4069// Variable length depending on whether offset fits into immediate field
4070// MemOperand current only supports d-form
4071void MacroAssembler::StoreByte(Register src, const MemOperand& mem,
4072 Register scratch) {
4073 Register base = mem.ra();
4074 int offset = mem.offset();
4075
4076 if (!is_int16(offset)) {
4077 LoadIntLiteral(scratch, offset);
4078 stbx(src, MemOperand(base, scratch));
4079 } else {
4080 stb(src, mem);
4081 }
4082}
4083
4084
4085void MacroAssembler::LoadRepresentation(Register dst, const MemOperand& mem,
4086 Representation r, Register scratch) {
4087 DCHECK(!r.IsDouble());
4088 if (r.IsInteger8()) {
4089 LoadByte(dst, mem, scratch);
4090 extsb(dst, dst);
4091 } else if (r.IsUInteger8()) {
4092 LoadByte(dst, mem, scratch);
4093 } else if (r.IsInteger16()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004094 LoadHalfWordArith(dst, mem, scratch);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004095 } else if (r.IsUInteger16()) {
4096 LoadHalfWord(dst, mem, scratch);
4097#if V8_TARGET_ARCH_PPC64
4098 } else if (r.IsInteger32()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004099 LoadWordArith(dst, mem, scratch);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004100#endif
4101 } else {
4102 LoadP(dst, mem, scratch);
4103 }
4104}
4105
4106
4107void MacroAssembler::StoreRepresentation(Register src, const MemOperand& mem,
4108 Representation r, Register scratch) {
4109 DCHECK(!r.IsDouble());
4110 if (r.IsInteger8() || r.IsUInteger8()) {
4111 StoreByte(src, mem, scratch);
4112 } else if (r.IsInteger16() || r.IsUInteger16()) {
4113 StoreHalfWord(src, mem, scratch);
4114#if V8_TARGET_ARCH_PPC64
4115 } else if (r.IsInteger32()) {
4116 StoreWord(src, mem, scratch);
4117#endif
4118 } else {
4119 if (r.IsHeapObject()) {
4120 AssertNotSmi(src);
4121 } else if (r.IsSmi()) {
4122 AssertSmi(src);
4123 }
4124 StoreP(src, mem, scratch);
4125 }
4126}
4127
4128
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004129void MacroAssembler::LoadDouble(DoubleRegister dst, const MemOperand& mem,
4130 Register scratch) {
4131 Register base = mem.ra();
4132 int offset = mem.offset();
4133
4134 if (!is_int16(offset)) {
4135 mov(scratch, Operand(offset));
4136 lfdx(dst, MemOperand(base, scratch));
4137 } else {
4138 lfd(dst, mem);
4139 }
4140}
4141
4142
4143void MacroAssembler::StoreDouble(DoubleRegister src, const MemOperand& mem,
4144 Register scratch) {
4145 Register base = mem.ra();
4146 int offset = mem.offset();
4147
4148 if (!is_int16(offset)) {
4149 mov(scratch, Operand(offset));
4150 stfdx(src, MemOperand(base, scratch));
4151 } else {
4152 stfd(src, mem);
4153 }
4154}
4155
4156
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004157void MacroAssembler::TestJSArrayForAllocationMemento(Register receiver_reg,
4158 Register scratch_reg,
4159 Label* no_memento_found) {
4160 ExternalReference new_space_start =
4161 ExternalReference::new_space_start(isolate());
4162 ExternalReference new_space_allocation_top =
4163 ExternalReference::new_space_allocation_top_address(isolate());
4164 addi(scratch_reg, receiver_reg,
4165 Operand(JSArray::kSize + AllocationMemento::kSize - kHeapObjectTag));
4166 Cmpi(scratch_reg, Operand(new_space_start), r0);
4167 blt(no_memento_found);
4168 mov(ip, Operand(new_space_allocation_top));
4169 LoadP(ip, MemOperand(ip));
4170 cmp(scratch_reg, ip);
4171 bgt(no_memento_found);
4172 LoadP(scratch_reg, MemOperand(scratch_reg, -AllocationMemento::kSize));
4173 Cmpi(scratch_reg, Operand(isolate()->factory()->allocation_memento_map()),
4174 r0);
4175}
4176
4177
4178Register GetRegisterThatIsNotOneOf(Register reg1, Register reg2, Register reg3,
4179 Register reg4, Register reg5,
4180 Register reg6) {
4181 RegList regs = 0;
4182 if (reg1.is_valid()) regs |= reg1.bit();
4183 if (reg2.is_valid()) regs |= reg2.bit();
4184 if (reg3.is_valid()) regs |= reg3.bit();
4185 if (reg4.is_valid()) regs |= reg4.bit();
4186 if (reg5.is_valid()) regs |= reg5.bit();
4187 if (reg6.is_valid()) regs |= reg6.bit();
4188
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004189 const RegisterConfiguration* config =
4190 RegisterConfiguration::ArchDefault(RegisterConfiguration::CRANKSHAFT);
4191 for (int i = 0; i < config->num_allocatable_general_registers(); ++i) {
4192 int code = config->GetAllocatableGeneralCode(i);
4193 Register candidate = Register::from_code(code);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004194 if (regs & candidate.bit()) continue;
4195 return candidate;
4196 }
4197 UNREACHABLE();
4198 return no_reg;
4199}
4200
4201
4202void MacroAssembler::JumpIfDictionaryInPrototypeChain(Register object,
4203 Register scratch0,
4204 Register scratch1,
4205 Label* found) {
4206 DCHECK(!scratch1.is(scratch0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004207 Register current = scratch0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004208 Label loop_again, end;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004209
4210 // scratch contained elements pointer.
4211 mr(current, object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004212 LoadP(current, FieldMemOperand(current, HeapObject::kMapOffset));
4213 LoadP(current, FieldMemOperand(current, Map::kPrototypeOffset));
4214 CompareRoot(current, Heap::kNullValueRootIndex);
4215 beq(&end);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004216
4217 // Loop based on the map going up the prototype chain.
4218 bind(&loop_again);
4219 LoadP(current, FieldMemOperand(current, HeapObject::kMapOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004220
4221 STATIC_ASSERT(JS_PROXY_TYPE < JS_OBJECT_TYPE);
4222 STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE);
4223 lbz(scratch1, FieldMemOperand(current, Map::kInstanceTypeOffset));
4224 cmpi(scratch1, Operand(JS_OBJECT_TYPE));
4225 blt(found);
4226
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004227 lbz(scratch1, FieldMemOperand(current, Map::kBitField2Offset));
4228 DecodeField<Map::ElementsKindBits>(scratch1);
4229 cmpi(scratch1, Operand(DICTIONARY_ELEMENTS));
4230 beq(found);
4231 LoadP(current, FieldMemOperand(current, Map::kPrototypeOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004232 CompareRoot(current, Heap::kNullValueRootIndex);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004233 bne(&loop_again);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004234
4235 bind(&end);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004236}
4237
4238
4239#ifdef DEBUG
4240bool AreAliased(Register reg1, Register reg2, Register reg3, Register reg4,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004241 Register reg5, Register reg6, Register reg7, Register reg8,
4242 Register reg9, Register reg10) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004243 int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() + reg3.is_valid() +
4244 reg4.is_valid() + reg5.is_valid() + reg6.is_valid() +
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004245 reg7.is_valid() + reg8.is_valid() + reg9.is_valid() +
4246 reg10.is_valid();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004247
4248 RegList regs = 0;
4249 if (reg1.is_valid()) regs |= reg1.bit();
4250 if (reg2.is_valid()) regs |= reg2.bit();
4251 if (reg3.is_valid()) regs |= reg3.bit();
4252 if (reg4.is_valid()) regs |= reg4.bit();
4253 if (reg5.is_valid()) regs |= reg5.bit();
4254 if (reg6.is_valid()) regs |= reg6.bit();
4255 if (reg7.is_valid()) regs |= reg7.bit();
4256 if (reg8.is_valid()) regs |= reg8.bit();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004257 if (reg9.is_valid()) regs |= reg9.bit();
4258 if (reg10.is_valid()) regs |= reg10.bit();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004259 int n_of_non_aliasing_regs = NumRegs(regs);
4260
4261 return n_of_valid_regs != n_of_non_aliasing_regs;
4262}
4263#endif
4264
4265
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004266CodePatcher::CodePatcher(Isolate* isolate, byte* address, int instructions,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004267 FlushICache flush_cache)
4268 : address_(address),
4269 size_(instructions * Assembler::kInstrSize),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004270 masm_(isolate, address, size_ + Assembler::kGap, CodeObjectRequired::kNo),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004271 flush_cache_(flush_cache) {
4272 // Create a new macro assembler pointing to the address of the code to patch.
4273 // The size is adjusted with kGap on order for the assembler to generate size
4274 // bytes of instructions without failing with buffer size constraints.
4275 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
4276}
4277
4278
4279CodePatcher::~CodePatcher() {
4280 // Indicate that code has changed.
4281 if (flush_cache_ == FLUSH) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004282 Assembler::FlushICache(masm_.isolate(), address_, size_);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004283 }
4284
4285 // Check that the code was patched as expected.
4286 DCHECK(masm_.pc_ == address_ + size_);
4287 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
4288}
4289
4290
4291void CodePatcher::Emit(Instr instr) { masm()->emit(instr); }
4292
4293
4294void CodePatcher::EmitCondition(Condition cond) {
4295 Instr instr = Assembler::instr_at(masm_.pc_);
4296 switch (cond) {
4297 case eq:
4298 instr = (instr & ~kCondMask) | BT;
4299 break;
4300 case ne:
4301 instr = (instr & ~kCondMask) | BF;
4302 break;
4303 default:
4304 UNIMPLEMENTED();
4305 }
4306 masm_.emit(instr);
4307}
4308
4309
4310void MacroAssembler::TruncatingDiv(Register result, Register dividend,
4311 int32_t divisor) {
4312 DCHECK(!dividend.is(result));
4313 DCHECK(!dividend.is(r0));
4314 DCHECK(!result.is(r0));
4315 base::MagicNumbersForDivision<uint32_t> mag =
4316 base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
4317 mov(r0, Operand(mag.multiplier));
4318 mulhw(result, dividend, r0);
4319 bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
4320 if (divisor > 0 && neg) {
4321 add(result, result, dividend);
4322 }
4323 if (divisor < 0 && !neg && mag.multiplier > 0) {
4324 sub(result, result, dividend);
4325 }
4326 if (mag.shift > 0) srawi(result, result, mag.shift);
4327 ExtractBit(r0, dividend, 31);
4328 add(result, result, r0);
4329}
4330
4331} // namespace internal
4332} // namespace v8
4333
4334#endif // V8_TARGET_ARCH_PPC