blob: bda6541704db191b5ec8d7ff42951597bfcaaa40 [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
Emily Bernierd0a1eb72015-03-24 16:35:39 -040087 // branch via link register and set LK bit for return point
88 mtctr(target);
89 bctrl();
90
91 DCHECK_EQ(CallSize(target), SizeOfCodeGeneratedSince(&start));
92}
93
94
95void MacroAssembler::CallJSEntry(Register target) {
96 DCHECK(target.is(ip));
97 Call(target);
98}
99
100
101int MacroAssembler::CallSize(Address target, RelocInfo::Mode rmode,
102 Condition cond) {
103 Operand mov_operand = Operand(reinterpret_cast<intptr_t>(target), rmode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000104 return (2 + instructions_required_for_mov(ip, mov_operand)) * kInstrSize;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400105}
106
107
108int MacroAssembler::CallSizeNotPredictableCodeSize(Address target,
109 RelocInfo::Mode rmode,
110 Condition cond) {
111 return (2 + kMovInstructionsNoConstantPool) * kInstrSize;
112}
113
114
115void MacroAssembler::Call(Address target, RelocInfo::Mode rmode,
116 Condition cond) {
117 BlockTrampolinePoolScope block_trampoline_pool(this);
118 DCHECK(cond == al);
119
120#ifdef DEBUG
121 // Check the expected size before generating code to ensure we assume the same
122 // constant pool availability (e.g., whether constant pool is full or not).
123 int expected_size = CallSize(target, rmode, cond);
124 Label start;
125 bind(&start);
126#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400127 // This can likely be optimized to make use of bc() with 24bit relative
128 //
129 // RecordRelocInfo(x.rmode_, x.imm_);
130 // bc( BA, .... offset, LKset);
131 //
132
133 mov(ip, Operand(reinterpret_cast<intptr_t>(target), rmode));
134 mtctr(ip);
135 bctrl();
136
137 DCHECK_EQ(expected_size, SizeOfCodeGeneratedSince(&start));
138}
139
140
141int MacroAssembler::CallSize(Handle<Code> code, RelocInfo::Mode rmode,
142 TypeFeedbackId ast_id, Condition cond) {
143 AllowDeferredHandleDereference using_raw_address;
144 return CallSize(reinterpret_cast<Address>(code.location()), rmode, cond);
145}
146
147
148void MacroAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode,
149 TypeFeedbackId ast_id, Condition cond) {
150 BlockTrampolinePoolScope block_trampoline_pool(this);
151 DCHECK(RelocInfo::IsCodeTarget(rmode));
152
153#ifdef DEBUG
154 // Check the expected size before generating code to ensure we assume the same
155 // constant pool availability (e.g., whether constant pool is full or not).
156 int expected_size = CallSize(code, rmode, ast_id, cond);
157 Label start;
158 bind(&start);
159#endif
160
161 if (rmode == RelocInfo::CODE_TARGET && !ast_id.IsNone()) {
162 SetRecordedAstId(ast_id);
163 rmode = RelocInfo::CODE_TARGET_WITH_ID;
164 }
165 AllowDeferredHandleDereference using_raw_address;
166 Call(reinterpret_cast<Address>(code.location()), rmode, cond);
167 DCHECK_EQ(expected_size, SizeOfCodeGeneratedSince(&start));
168}
169
170
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000171void MacroAssembler::Drop(int count) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400172 if (count > 0) {
173 Add(sp, sp, count * kPointerSize, r0);
174 }
175}
176
Ben Murdoch097c5b22016-05-18 11:27:45 +0100177void MacroAssembler::Drop(Register count, Register scratch) {
178 ShiftLeftImm(scratch, count, Operand(kPointerSizeLog2));
179 add(sp, sp, scratch);
180}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400181
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400182void MacroAssembler::Call(Label* target) { b(target, SetLK); }
183
184
185void MacroAssembler::Push(Handle<Object> handle) {
186 mov(r0, Operand(handle));
187 push(r0);
188}
189
190
191void MacroAssembler::Move(Register dst, Handle<Object> value) {
192 AllowDeferredHandleDereference smi_check;
193 if (value->IsSmi()) {
194 LoadSmiLiteral(dst, reinterpret_cast<Smi*>(*value));
195 } else {
196 DCHECK(value->IsHeapObject());
197 if (isolate()->heap()->InNewSpace(*value)) {
198 Handle<Cell> cell = isolate()->factory()->NewCell(value);
199 mov(dst, Operand(cell));
200 LoadP(dst, FieldMemOperand(dst, Cell::kValueOffset));
201 } else {
202 mov(dst, Operand(value));
203 }
204 }
205}
206
207
208void MacroAssembler::Move(Register dst, Register src, Condition cond) {
209 DCHECK(cond == al);
210 if (!dst.is(src)) {
211 mr(dst, src);
212 }
213}
214
215
216void MacroAssembler::Move(DoubleRegister dst, DoubleRegister src) {
217 if (!dst.is(src)) {
218 fmr(dst, src);
219 }
220}
221
222
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000223void MacroAssembler::MultiPush(RegList regs, Register location) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400224 int16_t num_to_push = NumberOfBitsSet(regs);
225 int16_t stack_offset = num_to_push * kPointerSize;
226
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000227 subi(location, location, Operand(stack_offset));
228 for (int16_t i = Register::kNumRegisters - 1; i >= 0; i--) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400229 if ((regs & (1 << i)) != 0) {
230 stack_offset -= kPointerSize;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000231 StoreP(ToRegister(i), MemOperand(location, stack_offset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400232 }
233 }
234}
235
236
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000237void MacroAssembler::MultiPop(RegList regs, Register location) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400238 int16_t stack_offset = 0;
239
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000240 for (int16_t i = 0; i < Register::kNumRegisters; i++) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400241 if ((regs & (1 << i)) != 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242 LoadP(ToRegister(i), MemOperand(location, stack_offset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400243 stack_offset += kPointerSize;
244 }
245 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000246 addi(location, location, Operand(stack_offset));
247}
248
249
250void MacroAssembler::MultiPushDoubles(RegList dregs, Register location) {
251 int16_t num_to_push = NumberOfBitsSet(dregs);
252 int16_t stack_offset = num_to_push * kDoubleSize;
253
254 subi(location, location, Operand(stack_offset));
255 for (int16_t i = DoubleRegister::kNumRegisters - 1; i >= 0; i--) {
256 if ((dregs & (1 << i)) != 0) {
257 DoubleRegister dreg = DoubleRegister::from_code(i);
258 stack_offset -= kDoubleSize;
259 stfd(dreg, MemOperand(location, stack_offset));
260 }
261 }
262}
263
264
265void MacroAssembler::MultiPopDoubles(RegList dregs, Register location) {
266 int16_t stack_offset = 0;
267
268 for (int16_t i = 0; i < DoubleRegister::kNumRegisters; i++) {
269 if ((dregs & (1 << i)) != 0) {
270 DoubleRegister dreg = DoubleRegister::from_code(i);
271 lfd(dreg, MemOperand(location, stack_offset));
272 stack_offset += kDoubleSize;
273 }
274 }
275 addi(location, location, Operand(stack_offset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400276}
277
278
279void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index,
280 Condition cond) {
281 DCHECK(cond == al);
282 LoadP(destination, MemOperand(kRootRegister, index << kPointerSizeLog2), r0);
283}
284
285
286void MacroAssembler::StoreRoot(Register source, Heap::RootListIndex index,
287 Condition cond) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000288 DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400289 DCHECK(cond == al);
290 StoreP(source, MemOperand(kRootRegister, index << kPointerSizeLog2), r0);
291}
292
293
294void MacroAssembler::InNewSpace(Register object, Register scratch,
295 Condition cond, Label* branch) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400296 DCHECK(cond == eq || cond == ne);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100297 const int mask =
298 (1 << MemoryChunk::IN_FROM_SPACE) | (1 << MemoryChunk::IN_TO_SPACE);
299 CheckPageFlag(object, scratch, mask, cond, branch);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400300}
301
302
303void MacroAssembler::RecordWriteField(
304 Register object, int offset, Register value, Register dst,
305 LinkRegisterStatus lr_status, SaveFPRegsMode save_fp,
306 RememberedSetAction remembered_set_action, SmiCheck smi_check,
307 PointersToHereCheck pointers_to_here_check_for_value) {
308 // First, check if a write barrier is even needed. The tests below
309 // catch stores of Smis.
310 Label done;
311
312 // Skip barrier if writing a smi.
313 if (smi_check == INLINE_SMI_CHECK) {
314 JumpIfSmi(value, &done);
315 }
316
317 // Although the object register is tagged, the offset is relative to the start
318 // of the object, so so offset must be a multiple of kPointerSize.
319 DCHECK(IsAligned(offset, kPointerSize));
320
321 Add(dst, object, offset - kHeapObjectTag, r0);
322 if (emit_debug_code()) {
323 Label ok;
324 andi(r0, dst, Operand((1 << kPointerSizeLog2) - 1));
325 beq(&ok, cr0);
326 stop("Unaligned cell in write barrier");
327 bind(&ok);
328 }
329
330 RecordWrite(object, dst, value, lr_status, save_fp, remembered_set_action,
331 OMIT_SMI_CHECK, pointers_to_here_check_for_value);
332
333 bind(&done);
334
335 // Clobber clobbered input registers when running with the debug-code flag
336 // turned on to provoke errors.
337 if (emit_debug_code()) {
338 mov(value, Operand(bit_cast<intptr_t>(kZapValue + 4)));
339 mov(dst, Operand(bit_cast<intptr_t>(kZapValue + 8)));
340 }
341}
342
343
344// Will clobber 4 registers: object, map, dst, ip. The
345// register 'object' contains a heap object pointer.
346void MacroAssembler::RecordWriteForMap(Register object, Register map,
347 Register dst,
348 LinkRegisterStatus lr_status,
349 SaveFPRegsMode fp_mode) {
350 if (emit_debug_code()) {
351 LoadP(dst, FieldMemOperand(map, HeapObject::kMapOffset));
352 Cmpi(dst, Operand(isolate()->factory()->meta_map()), r0);
353 Check(eq, kWrongAddressOrValuePassedToRecordWrite);
354 }
355
356 if (!FLAG_incremental_marking) {
357 return;
358 }
359
360 if (emit_debug_code()) {
361 LoadP(ip, FieldMemOperand(object, HeapObject::kMapOffset));
362 cmp(ip, map);
363 Check(eq, kWrongAddressOrValuePassedToRecordWrite);
364 }
365
366 Label done;
367
368 // A single check of the map's pages interesting flag suffices, since it is
369 // only set during incremental collection, and then it's also guaranteed that
370 // the from object's page's interesting flag is also set. This optimization
371 // relies on the fact that maps can never be in new space.
372 CheckPageFlag(map,
373 map, // Used as scratch.
374 MemoryChunk::kPointersToHereAreInterestingMask, eq, &done);
375
376 addi(dst, object, Operand(HeapObject::kMapOffset - kHeapObjectTag));
377 if (emit_debug_code()) {
378 Label ok;
379 andi(r0, dst, Operand((1 << kPointerSizeLog2) - 1));
380 beq(&ok, cr0);
381 stop("Unaligned cell in write barrier");
382 bind(&ok);
383 }
384
385 // Record the actual write.
386 if (lr_status == kLRHasNotBeenSaved) {
387 mflr(r0);
388 push(r0);
389 }
390 RecordWriteStub stub(isolate(), object, map, dst, OMIT_REMEMBERED_SET,
391 fp_mode);
392 CallStub(&stub);
393 if (lr_status == kLRHasNotBeenSaved) {
394 pop(r0);
395 mtlr(r0);
396 }
397
398 bind(&done);
399
400 // Count number of write barriers in generated code.
401 isolate()->counters()->write_barriers_static()->Increment();
402 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip, dst);
403
404 // Clobber clobbered registers when running with the debug-code flag
405 // turned on to provoke errors.
406 if (emit_debug_code()) {
407 mov(dst, Operand(bit_cast<intptr_t>(kZapValue + 12)));
408 mov(map, Operand(bit_cast<intptr_t>(kZapValue + 16)));
409 }
410}
411
412
413// Will clobber 4 registers: object, address, scratch, ip. The
414// register 'object' contains a heap object pointer. The heap object
415// tag is shifted away.
416void MacroAssembler::RecordWrite(
417 Register object, Register address, Register value,
418 LinkRegisterStatus lr_status, SaveFPRegsMode fp_mode,
419 RememberedSetAction remembered_set_action, SmiCheck smi_check,
420 PointersToHereCheck pointers_to_here_check_for_value) {
421 DCHECK(!object.is(value));
422 if (emit_debug_code()) {
423 LoadP(r0, MemOperand(address));
424 cmp(r0, value);
425 Check(eq, kWrongAddressOrValuePassedToRecordWrite);
426 }
427
428 if (remembered_set_action == OMIT_REMEMBERED_SET &&
429 !FLAG_incremental_marking) {
430 return;
431 }
432
433 // First, check if a write barrier is even needed. The tests below
434 // catch stores of smis and stores into the young generation.
435 Label done;
436
437 if (smi_check == INLINE_SMI_CHECK) {
438 JumpIfSmi(value, &done);
439 }
440
441 if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) {
442 CheckPageFlag(value,
443 value, // Used as scratch.
444 MemoryChunk::kPointersToHereAreInterestingMask, eq, &done);
445 }
446 CheckPageFlag(object,
447 value, // Used as scratch.
448 MemoryChunk::kPointersFromHereAreInterestingMask, eq, &done);
449
450 // Record the actual write.
451 if (lr_status == kLRHasNotBeenSaved) {
452 mflr(r0);
453 push(r0);
454 }
455 RecordWriteStub stub(isolate(), object, value, address, remembered_set_action,
456 fp_mode);
457 CallStub(&stub);
458 if (lr_status == kLRHasNotBeenSaved) {
459 pop(r0);
460 mtlr(r0);
461 }
462
463 bind(&done);
464
465 // Count number of write barriers in generated code.
466 isolate()->counters()->write_barriers_static()->Increment();
467 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip,
468 value);
469
470 // Clobber clobbered registers when running with the debug-code flag
471 // turned on to provoke errors.
472 if (emit_debug_code()) {
473 mov(address, Operand(bit_cast<intptr_t>(kZapValue + 12)));
474 mov(value, Operand(bit_cast<intptr_t>(kZapValue + 16)));
475 }
476}
477
Ben Murdoch097c5b22016-05-18 11:27:45 +0100478void MacroAssembler::RecordWriteCodeEntryField(Register js_function,
479 Register code_entry,
480 Register scratch) {
481 const int offset = JSFunction::kCodeEntryOffset;
482
483 // Since a code entry (value) is always in old space, we don't need to update
484 // remembered set. If incremental marking is off, there is nothing for us to
485 // do.
486 if (!FLAG_incremental_marking) return;
487
488 DCHECK(js_function.is(r4));
489 DCHECK(code_entry.is(r7));
490 DCHECK(scratch.is(r8));
491 AssertNotSmi(js_function);
492
493 if (emit_debug_code()) {
494 addi(scratch, js_function, Operand(offset - kHeapObjectTag));
495 LoadP(ip, MemOperand(scratch));
496 cmp(ip, code_entry);
497 Check(eq, kWrongAddressOrValuePassedToRecordWrite);
498 }
499
500 // First, check if a write barrier is even needed. The tests below
501 // catch stores of Smis and stores into young gen.
502 Label done;
503
504 CheckPageFlag(code_entry, scratch,
505 MemoryChunk::kPointersToHereAreInterestingMask, eq, &done);
506 CheckPageFlag(js_function, scratch,
507 MemoryChunk::kPointersFromHereAreInterestingMask, eq, &done);
508
509 const Register dst = scratch;
510 addi(dst, js_function, Operand(offset - kHeapObjectTag));
511
512 // Save caller-saved registers. js_function and code_entry are in the
513 // caller-saved register list.
514 DCHECK(kJSCallerSaved & js_function.bit());
515 DCHECK(kJSCallerSaved & code_entry.bit());
516 mflr(r0);
517 MultiPush(kJSCallerSaved | r0.bit());
518
519 int argument_count = 3;
520 PrepareCallCFunction(argument_count, code_entry);
521
522 mr(r3, js_function);
523 mr(r4, dst);
524 mov(r5, Operand(ExternalReference::isolate_address(isolate())));
525
526 {
527 AllowExternalCallThatCantCauseGC scope(this);
528 CallCFunction(
529 ExternalReference::incremental_marking_record_write_code_entry_function(
530 isolate()),
531 argument_count);
532 }
533
534 // Restore caller-saved registers (including js_function and code_entry).
535 MultiPop(kJSCallerSaved | r0.bit());
536 mtlr(r0);
537
538 bind(&done);
539}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400540
541void MacroAssembler::RememberedSetHelper(Register object, // For debug tests.
542 Register address, Register scratch,
543 SaveFPRegsMode fp_mode,
544 RememberedSetFinalAction and_then) {
545 Label done;
546 if (emit_debug_code()) {
547 Label ok;
548 JumpIfNotInNewSpace(object, scratch, &ok);
549 stop("Remembered set pointer is in new space");
550 bind(&ok);
551 }
552 // Load store buffer top.
553 ExternalReference store_buffer =
554 ExternalReference::store_buffer_top(isolate());
555 mov(ip, Operand(store_buffer));
556 LoadP(scratch, MemOperand(ip));
557 // Store pointer to buffer and increment buffer top.
558 StoreP(address, MemOperand(scratch));
559 addi(scratch, scratch, Operand(kPointerSize));
560 // Write back new top of buffer.
561 StoreP(scratch, MemOperand(ip));
562 // Call stub on end of buffer.
563 // Check for end of buffer.
Ben Murdochda12d292016-06-02 14:46:10 +0100564 TestBitMask(scratch, StoreBuffer::kStoreBufferMask, r0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400565
566 if (and_then == kFallThroughAtEnd) {
Ben Murdochda12d292016-06-02 14:46:10 +0100567 bne(&done, cr0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400568 } else {
569 DCHECK(and_then == kReturnAtEnd);
Ben Murdochda12d292016-06-02 14:46:10 +0100570 Ret(ne, cr0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400571 }
572 mflr(r0);
573 push(r0);
574 StoreBufferOverflowStub store_buffer_overflow(isolate(), fp_mode);
575 CallStub(&store_buffer_overflow);
576 pop(r0);
577 mtlr(r0);
578 bind(&done);
579 if (and_then == kReturnAtEnd) {
580 Ret();
581 }
582}
583
Ben Murdochda12d292016-06-02 14:46:10 +0100584void MacroAssembler::PushCommonFrame(Register marker_reg) {
585 int fp_delta = 0;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400586 mflr(r0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000587 if (FLAG_enable_embedded_constant_pool) {
588 if (marker_reg.is_valid()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100589 Push(r0, fp, kConstantPoolRegister, marker_reg);
590 fp_delta = 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000591 } else {
Ben Murdochda12d292016-06-02 14:46:10 +0100592 Push(r0, fp, kConstantPoolRegister);
593 fp_delta = 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000594 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400595 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000596 if (marker_reg.is_valid()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100597 Push(r0, fp, marker_reg);
598 fp_delta = 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000599 } else {
Ben Murdochda12d292016-06-02 14:46:10 +0100600 Push(r0, fp);
601 fp_delta = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000602 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400603 }
Ben Murdochda12d292016-06-02 14:46:10 +0100604 addi(fp, sp, Operand(fp_delta * kPointerSize));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400605}
606
Ben Murdochda12d292016-06-02 14:46:10 +0100607void MacroAssembler::PopCommonFrame(Register marker_reg) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000608 if (FLAG_enable_embedded_constant_pool) {
609 if (marker_reg.is_valid()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100610 Pop(r0, fp, kConstantPoolRegister, marker_reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000611 } else {
Ben Murdochda12d292016-06-02 14:46:10 +0100612 Pop(r0, fp, kConstantPoolRegister);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000613 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400614 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000615 if (marker_reg.is_valid()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100616 Pop(r0, fp, marker_reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000617 } else {
Ben Murdochda12d292016-06-02 14:46:10 +0100618 Pop(r0, fp);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000619 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400620 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400621 mtlr(r0);
622}
623
Ben Murdochda12d292016-06-02 14:46:10 +0100624void MacroAssembler::PushStandardFrame(Register function_reg) {
625 int fp_delta = 0;
626 mflr(r0);
627 if (FLAG_enable_embedded_constant_pool) {
628 if (function_reg.is_valid()) {
629 Push(r0, fp, kConstantPoolRegister, cp, function_reg);
630 fp_delta = 3;
631 } else {
632 Push(r0, fp, kConstantPoolRegister, cp);
633 fp_delta = 2;
634 }
635 } else {
636 if (function_reg.is_valid()) {
637 Push(r0, fp, cp, function_reg);
638 fp_delta = 2;
639 } else {
640 Push(r0, fp, cp);
641 fp_delta = 1;
642 }
643 }
644 addi(fp, sp, Operand(fp_delta * kPointerSize));
645}
646
Ben Murdoch097c5b22016-05-18 11:27:45 +0100647void MacroAssembler::RestoreFrameStateForTailCall() {
648 if (FLAG_enable_embedded_constant_pool) {
649 LoadP(kConstantPoolRegister,
650 MemOperand(fp, StandardFrameConstants::kConstantPoolOffset));
651 set_constant_pool_available(false);
652 }
653 LoadP(r0, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
654 LoadP(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
655 mtlr(r0);
656}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400657
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000658const RegList MacroAssembler::kSafepointSavedRegisters = Register::kAllocatable;
659const int MacroAssembler::kNumSafepointSavedRegisters =
660 Register::kNumAllocatable;
661
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400662// Push and pop all registers that can hold pointers.
663void MacroAssembler::PushSafepointRegisters() {
664 // Safepoints expect a block of kNumSafepointRegisters values on the
665 // stack, so adjust the stack for unsaved registers.
666 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
667 DCHECK(num_unsaved >= 0);
668 if (num_unsaved > 0) {
669 subi(sp, sp, Operand(num_unsaved * kPointerSize));
670 }
671 MultiPush(kSafepointSavedRegisters);
672}
673
674
675void MacroAssembler::PopSafepointRegisters() {
676 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
677 MultiPop(kSafepointSavedRegisters);
678 if (num_unsaved > 0) {
679 addi(sp, sp, Operand(num_unsaved * kPointerSize));
680 }
681}
682
683
684void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) {
685 StoreP(src, SafepointRegisterSlot(dst));
686}
687
688
689void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) {
690 LoadP(dst, SafepointRegisterSlot(src));
691}
692
693
694int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
695 // The registers are pushed starting with the highest encoding,
696 // which means that lowest encodings are closest to the stack pointer.
697 RegList regs = kSafepointSavedRegisters;
698 int index = 0;
699
700 DCHECK(reg_code >= 0 && reg_code < kNumRegisters);
701
702 for (int16_t i = 0; i < reg_code; i++) {
703 if ((regs & (1 << i)) != 0) {
704 index++;
705 }
706 }
707
708 return index;
709}
710
711
712MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) {
713 return MemOperand(sp, SafepointRegisterStackIndex(reg.code()) * kPointerSize);
714}
715
716
717MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) {
718 // General purpose registers are pushed last on the stack.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100719 const RegisterConfiguration* config = RegisterConfiguration::Crankshaft();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000720 int doubles_size = config->num_allocatable_double_registers() * kDoubleSize;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400721 int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize;
722 return MemOperand(sp, doubles_size + register_offset);
723}
724
725
726void MacroAssembler::CanonicalizeNaN(const DoubleRegister dst,
727 const DoubleRegister src) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000728 // Turn potential sNaN into qNaN.
729 fsub(dst, src, kDoubleRegZero);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400730}
731
Ben Murdoch097c5b22016-05-18 11:27:45 +0100732void MacroAssembler::ConvertIntToDouble(Register src, DoubleRegister dst) {
733 MovIntToDouble(dst, src, r0);
734 fcfid(dst, dst);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400735}
736
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400737void MacroAssembler::ConvertUnsignedIntToDouble(Register src,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100738 DoubleRegister dst) {
739 MovUnsignedIntToDouble(dst, src, r0);
740 fcfid(dst, dst);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400741}
742
Ben Murdoch097c5b22016-05-18 11:27:45 +0100743void MacroAssembler::ConvertIntToFloat(Register src, DoubleRegister dst) {
744 MovIntToDouble(dst, src, r0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000745 fcfids(dst, dst);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400746}
747
Ben Murdoch097c5b22016-05-18 11:27:45 +0100748void MacroAssembler::ConvertUnsignedIntToFloat(Register src,
749 DoubleRegister dst) {
750 MovUnsignedIntToDouble(dst, src, r0);
751 fcfids(dst, dst);
752}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400753
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000754#if V8_TARGET_ARCH_PPC64
755void MacroAssembler::ConvertInt64ToDouble(Register src,
756 DoubleRegister double_dst) {
757 MovInt64ToDouble(double_dst, src);
758 fcfid(double_dst, double_dst);
759}
760
761
762void MacroAssembler::ConvertUnsignedInt64ToFloat(Register src,
763 DoubleRegister double_dst) {
764 MovInt64ToDouble(double_dst, src);
765 fcfidus(double_dst, double_dst);
766}
767
768
769void MacroAssembler::ConvertUnsignedInt64ToDouble(Register src,
770 DoubleRegister double_dst) {
771 MovInt64ToDouble(double_dst, src);
772 fcfidu(double_dst, double_dst);
773}
774
775
776void MacroAssembler::ConvertInt64ToFloat(Register src,
777 DoubleRegister double_dst) {
778 MovInt64ToDouble(double_dst, src);
779 fcfids(double_dst, double_dst);
780}
781#endif
782
783
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400784void MacroAssembler::ConvertDoubleToInt64(const DoubleRegister double_input,
785#if !V8_TARGET_ARCH_PPC64
786 const Register dst_hi,
787#endif
788 const Register dst,
789 const DoubleRegister double_dst,
790 FPRoundingMode rounding_mode) {
791 if (rounding_mode == kRoundToZero) {
792 fctidz(double_dst, double_input);
793 } else {
794 SetRoundingMode(rounding_mode);
795 fctid(double_dst, double_input);
796 ResetRoundingMode();
797 }
798
799 MovDoubleToInt64(
800#if !V8_TARGET_ARCH_PPC64
801 dst_hi,
802#endif
803 dst, double_dst);
804}
805
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000806#if V8_TARGET_ARCH_PPC64
807void MacroAssembler::ConvertDoubleToUnsignedInt64(
808 const DoubleRegister double_input, const Register dst,
809 const DoubleRegister double_dst, FPRoundingMode rounding_mode) {
810 if (rounding_mode == kRoundToZero) {
811 fctiduz(double_dst, double_input);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400812 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000813 SetRoundingMode(rounding_mode);
814 fctidu(double_dst, double_input);
815 ResetRoundingMode();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400816 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000817
818 MovDoubleToInt64(dst, double_dst);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400819}
820#endif
821
Ben Murdochda12d292016-06-02 14:46:10 +0100822#if !V8_TARGET_ARCH_PPC64
823void MacroAssembler::ShiftLeftPair(Register dst_low, Register dst_high,
824 Register src_low, Register src_high,
825 Register scratch, Register shift) {
826 DCHECK(!AreAliased(dst_low, src_high, shift));
827 DCHECK(!AreAliased(dst_high, src_low, shift));
828 Label less_than_32;
829 Label done;
830 cmpi(shift, Operand(32));
831 blt(&less_than_32);
832 // If shift >= 32
833 andi(scratch, shift, Operand(0x1f));
834 slw(dst_high, src_low, scratch);
835 li(dst_low, Operand::Zero());
836 b(&done);
837 bind(&less_than_32);
838 // If shift < 32
839 subfic(scratch, shift, Operand(32));
840 slw(dst_high, src_high, shift);
841 srw(scratch, src_low, scratch);
842 orx(dst_high, dst_high, scratch);
843 slw(dst_low, src_low, shift);
844 bind(&done);
845}
846
847void MacroAssembler::ShiftLeftPair(Register dst_low, Register dst_high,
848 Register src_low, Register src_high,
849 uint32_t shift) {
850 DCHECK(!AreAliased(dst_low, src_high));
851 DCHECK(!AreAliased(dst_high, src_low));
852 if (shift == 32) {
853 Move(dst_high, src_low);
854 li(dst_low, Operand::Zero());
855 } else if (shift > 32) {
856 shift &= 0x1f;
857 slwi(dst_high, src_low, Operand(shift));
858 li(dst_low, Operand::Zero());
859 } else if (shift == 0) {
860 Move(dst_low, src_low);
861 Move(dst_high, src_high);
862 } else {
863 slwi(dst_high, src_high, Operand(shift));
864 rlwimi(dst_high, src_low, shift, 32 - shift, 31);
865 slwi(dst_low, src_low, Operand(shift));
866 }
867}
868
869void MacroAssembler::ShiftRightPair(Register dst_low, Register dst_high,
870 Register src_low, Register src_high,
871 Register scratch, Register shift) {
872 DCHECK(!AreAliased(dst_low, src_high, shift));
873 DCHECK(!AreAliased(dst_high, src_low, shift));
874 Label less_than_32;
875 Label done;
876 cmpi(shift, Operand(32));
877 blt(&less_than_32);
878 // If shift >= 32
879 andi(scratch, shift, Operand(0x1f));
880 srw(dst_low, src_high, scratch);
881 li(dst_high, Operand::Zero());
882 b(&done);
883 bind(&less_than_32);
884 // If shift < 32
885 subfic(scratch, shift, Operand(32));
886 srw(dst_low, src_low, shift);
887 slw(scratch, src_high, scratch);
888 orx(dst_low, dst_low, scratch);
889 srw(dst_high, src_high, shift);
890 bind(&done);
891}
892
893void MacroAssembler::ShiftRightPair(Register dst_low, Register dst_high,
894 Register src_low, Register src_high,
895 uint32_t shift) {
896 DCHECK(!AreAliased(dst_low, src_high));
897 DCHECK(!AreAliased(dst_high, src_low));
898 if (shift == 32) {
899 Move(dst_low, src_high);
900 li(dst_high, Operand::Zero());
901 } else if (shift > 32) {
902 shift &= 0x1f;
903 srwi(dst_low, src_high, Operand(shift));
904 li(dst_high, Operand::Zero());
905 } else if (shift == 0) {
906 Move(dst_low, src_low);
907 Move(dst_high, src_high);
908 } else {
909 srwi(dst_low, src_low, Operand(shift));
910 rlwimi(dst_low, src_high, 32 - shift, 0, shift - 1);
911 srwi(dst_high, src_high, Operand(shift));
912 }
913}
914
915void MacroAssembler::ShiftRightAlgPair(Register dst_low, Register dst_high,
916 Register src_low, Register src_high,
917 Register scratch, Register shift) {
918 DCHECK(!AreAliased(dst_low, src_high, shift));
919 DCHECK(!AreAliased(dst_high, src_low, shift));
920 Label less_than_32;
921 Label done;
922 cmpi(shift, Operand(32));
923 blt(&less_than_32);
924 // If shift >= 32
925 andi(scratch, shift, Operand(0x1f));
926 sraw(dst_low, src_high, scratch);
927 srawi(dst_high, src_high, 31);
928 b(&done);
929 bind(&less_than_32);
930 // If shift < 32
931 subfic(scratch, shift, Operand(32));
932 srw(dst_low, src_low, shift);
933 slw(scratch, src_high, scratch);
934 orx(dst_low, dst_low, scratch);
935 sraw(dst_high, src_high, shift);
936 bind(&done);
937}
938
939void MacroAssembler::ShiftRightAlgPair(Register dst_low, Register dst_high,
940 Register src_low, Register src_high,
941 uint32_t shift) {
942 DCHECK(!AreAliased(dst_low, src_high));
943 DCHECK(!AreAliased(dst_high, src_low));
944 if (shift == 32) {
945 Move(dst_low, src_high);
946 srawi(dst_high, src_high, 31);
947 } else if (shift > 32) {
948 shift &= 0x1f;
949 srawi(dst_low, src_high, shift);
950 srawi(dst_high, src_high, 31);
951 } else if (shift == 0) {
952 Move(dst_low, src_low);
953 Move(dst_high, src_high);
954 } else {
955 srwi(dst_low, src_low, Operand(shift));
956 rlwimi(dst_low, src_high, 32 - shift, 0, shift - 1);
957 srawi(dst_high, src_high, shift);
958 }
959}
960#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400961
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000962void MacroAssembler::LoadConstantPoolPointerRegisterFromCodeTargetAddress(
963 Register code_target_address) {
964 lwz(kConstantPoolRegister,
965 MemOperand(code_target_address,
966 Code::kConstantPoolOffset - Code::kHeaderSize));
967 add(kConstantPoolRegister, kConstantPoolRegister, code_target_address);
968}
969
970
971void MacroAssembler::LoadConstantPoolPointerRegister(Register base,
972 int code_start_delta) {
973 add_label_offset(kConstantPoolRegister, base, ConstantPoolPosition(),
974 code_start_delta);
975}
976
977
978void MacroAssembler::LoadConstantPoolPointerRegister() {
979 mov_label_addr(kConstantPoolRegister, ConstantPoolPosition());
980}
981
Ben Murdochda12d292016-06-02 14:46:10 +0100982void MacroAssembler::StubPrologue(StackFrame::Type type, Register base,
983 int prologue_offset) {
984 {
985 ConstantPoolUnavailableScope constant_pool_unavailable(this);
986 LoadSmiLiteral(r11, Smi::FromInt(type));
987 PushCommonFrame(r11);
988 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000989 if (FLAG_enable_embedded_constant_pool) {
990 if (!base.is(no_reg)) {
991 // base contains prologue address
992 LoadConstantPoolPointerRegister(base, -prologue_offset);
993 } else {
994 LoadConstantPoolPointerRegister();
995 }
996 set_constant_pool_available(true);
997 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400998}
999
1000
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001001void MacroAssembler::Prologue(bool code_pre_aging, Register base,
1002 int prologue_offset) {
1003 DCHECK(!base.is(no_reg));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001004 {
1005 PredictableCodeSizeScope predictible_code_size_scope(
1006 this, kNoCodeAgeSequenceLength);
1007 Assembler::BlockTrampolinePoolScope block_trampoline_pool(this);
1008 // The following instructions must remain together and unmodified
1009 // for code aging to work properly.
1010 if (code_pre_aging) {
1011 // Pre-age the code.
1012 // This matches the code found in PatchPlatformCodeAge()
1013 Code* stub = Code::GetPreAgedCodeAgeStub(isolate());
1014 intptr_t target = reinterpret_cast<intptr_t>(stub->instruction_start());
1015 // Don't use Call -- we need to preserve ip and lr
1016 nop(); // marker to detect sequence (see IsOld)
1017 mov(r3, Operand(target));
1018 Jump(r3);
1019 for (int i = 0; i < kCodeAgingSequenceNops; i++) {
1020 nop();
1021 }
1022 } else {
1023 // This matches the code found in GetNoCodeAgeSequence()
Ben Murdochda12d292016-06-02 14:46:10 +01001024 PushStandardFrame(r4);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001025 for (int i = 0; i < kNoCodeAgeSequenceNops; i++) {
1026 nop();
1027 }
1028 }
1029 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001030 if (FLAG_enable_embedded_constant_pool) {
1031 // base contains prologue address
1032 LoadConstantPoolPointerRegister(base, -prologue_offset);
1033 set_constant_pool_available(true);
1034 }
1035}
1036
1037
1038void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) {
1039 LoadP(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdoch61f157c2016-09-16 13:49:30 +01001040 LoadP(vector, FieldMemOperand(vector, JSFunction::kLiteralsOffset));
1041 LoadP(vector, FieldMemOperand(vector, LiteralsArray::kFeedbackVectorOffset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001042}
1043
1044
1045void MacroAssembler::EnterFrame(StackFrame::Type type,
1046 bool load_constant_pool_pointer_reg) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001047 if (FLAG_enable_embedded_constant_pool && load_constant_pool_pointer_reg) {
Ben Murdochda12d292016-06-02 14:46:10 +01001048 // Push type explicitly so we can leverage the constant pool.
1049 // This path cannot rely on ip containing code entry.
1050 PushCommonFrame();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001051 LoadConstantPoolPointerRegister();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001052 LoadSmiLiteral(ip, Smi::FromInt(type));
1053 push(ip);
1054 } else {
1055 LoadSmiLiteral(ip, Smi::FromInt(type));
Ben Murdochda12d292016-06-02 14:46:10 +01001056 PushCommonFrame(ip);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001057 }
Ben Murdochda12d292016-06-02 14:46:10 +01001058 if (type == StackFrame::INTERNAL) {
1059 mov(r0, Operand(CodeObject()));
1060 push(r0);
1061 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001062}
1063
1064
1065int MacroAssembler::LeaveFrame(StackFrame::Type type, int stack_adjustment) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001066 ConstantPoolUnavailableScope constant_pool_unavailable(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001067 // r3: preserved
1068 // r4: preserved
1069 // r5: preserved
1070
1071 // Drop the execution stack down to the frame pointer and restore
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001072 // the caller's state.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001073 int frame_ends;
1074 LoadP(r0, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
1075 LoadP(ip, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001076 if (FLAG_enable_embedded_constant_pool) {
Ben Murdochda12d292016-06-02 14:46:10 +01001077 LoadP(kConstantPoolRegister,
1078 MemOperand(fp, StandardFrameConstants::kConstantPoolOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001079 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001080 mtlr(r0);
1081 frame_ends = pc_offset();
1082 Add(sp, fp, StandardFrameConstants::kCallerSPOffset + stack_adjustment, r0);
1083 mr(fp, ip);
1084 return frame_ends;
1085}
1086
1087
1088// ExitFrame layout (probably wrongish.. needs updating)
1089//
1090// SP -> previousSP
1091// LK reserved
1092// code
1093// sp_on_exit (for debug?)
1094// oldSP->prev SP
1095// LK
1096// <parameters on stack>
1097
1098// Prior to calling EnterExitFrame, we've got a bunch of parameters
1099// on the stack that we need to wrap a real frame around.. so first
1100// we reserve a slot for LK and push the previous SP which is captured
1101// in the fp register (r31)
1102// Then - we buy a new frame
1103
1104void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) {
1105 // Set up the frame structure on the stack.
1106 DCHECK_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement);
1107 DCHECK_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset);
1108 DCHECK_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset);
1109 DCHECK(stack_space > 0);
1110
1111 // This is an opportunity to build a frame to wrap
1112 // all of the pushes that have happened inside of V8
1113 // since we were called from C code
1114
Ben Murdochda12d292016-06-02 14:46:10 +01001115 LoadSmiLiteral(ip, Smi::FromInt(StackFrame::EXIT));
1116 PushCommonFrame(ip);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001117 // Reserve room for saved entry sp and code object.
Ben Murdochda12d292016-06-02 14:46:10 +01001118 subi(sp, fp, Operand(ExitFrameConstants::kFixedFrameSizeFromFp));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001119
1120 if (emit_debug_code()) {
1121 li(r8, Operand::Zero());
1122 StoreP(r8, MemOperand(fp, ExitFrameConstants::kSPOffset));
1123 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001124 if (FLAG_enable_embedded_constant_pool) {
1125 StoreP(kConstantPoolRegister,
1126 MemOperand(fp, ExitFrameConstants::kConstantPoolOffset));
1127 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001128 mov(r8, Operand(CodeObject()));
1129 StoreP(r8, MemOperand(fp, ExitFrameConstants::kCodeOffset));
1130
1131 // Save the frame pointer and the context in top.
1132 mov(r8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
1133 StoreP(fp, MemOperand(r8));
1134 mov(r8, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
1135 StoreP(cp, MemOperand(r8));
1136
1137 // Optionally save all volatile double registers.
1138 if (save_doubles) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001139 MultiPushDoubles(kCallerSavedDoubles);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001140 // Note that d0 will be accessible at
1141 // fp - ExitFrameConstants::kFrameSize -
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001142 // kNumCallerSavedDoubles * kDoubleSize,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001143 // since the sp slot and code slot were pushed after the fp.
1144 }
1145
1146 addi(sp, sp, Operand(-stack_space * kPointerSize));
1147
1148 // Allocate and align the frame preparing for calling the runtime
1149 // function.
1150 const int frame_alignment = ActivationFrameAlignment();
1151 if (frame_alignment > kPointerSize) {
1152 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
1153 ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
1154 }
1155 li(r0, Operand::Zero());
1156 StorePU(r0, MemOperand(sp, -kNumRequiredStackFrameSlots * kPointerSize));
1157
1158 // Set the exit frame sp value to point just before the return address
1159 // location.
1160 addi(r8, sp, Operand((kStackFrameExtraParamSlot + 1) * kPointerSize));
1161 StoreP(r8, MemOperand(fp, ExitFrameConstants::kSPOffset));
1162}
1163
1164
1165void MacroAssembler::InitializeNewString(Register string, Register length,
1166 Heap::RootListIndex map_index,
1167 Register scratch1, Register scratch2) {
1168 SmiTag(scratch1, length);
1169 LoadRoot(scratch2, map_index);
1170 StoreP(scratch1, FieldMemOperand(string, String::kLengthOffset), r0);
1171 li(scratch1, Operand(String::kEmptyHashField));
1172 StoreP(scratch2, FieldMemOperand(string, HeapObject::kMapOffset), r0);
1173 StoreP(scratch1, FieldMemOperand(string, String::kHashFieldSlot), r0);
1174}
1175
1176
1177int MacroAssembler::ActivationFrameAlignment() {
1178#if !defined(USE_SIMULATOR)
1179 // Running on the real platform. Use the alignment as mandated by the local
1180 // environment.
1181 // Note: This will break if we ever start generating snapshots on one PPC
1182 // platform for another PPC platform with a different alignment.
1183 return base::OS::ActivationFrameAlignment();
1184#else // Simulated
1185 // If we are using the simulator then we should always align to the expected
1186 // alignment. As the simulator is used to generate snapshots we do not know
1187 // if the target platform will need alignment, so this is controlled from a
1188 // flag.
1189 return FLAG_sim_stack_alignment;
1190#endif
1191}
1192
1193
1194void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001195 bool restore_context,
1196 bool argument_count_is_length) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001197 ConstantPoolUnavailableScope constant_pool_unavailable(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001198 // Optionally restore all double registers.
1199 if (save_doubles) {
1200 // Calculate the stack location of the saved doubles and restore them.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001201 const int kNumRegs = kNumCallerSavedDoubles;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001202 const int offset =
Ben Murdochda12d292016-06-02 14:46:10 +01001203 (ExitFrameConstants::kFixedFrameSizeFromFp + kNumRegs * kDoubleSize);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001204 addi(r6, fp, Operand(-offset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001205 MultiPopDoubles(kCallerSavedDoubles, r6);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001206 }
1207
1208 // Clear top frame.
1209 li(r6, Operand::Zero());
1210 mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
1211 StoreP(r6, MemOperand(ip));
1212
1213 // Restore current context from top and clear it in debug mode.
1214 if (restore_context) {
1215 mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
1216 LoadP(cp, MemOperand(ip));
1217 }
1218#ifdef DEBUG
1219 mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
1220 StoreP(r6, MemOperand(ip));
1221#endif
1222
1223 // Tear down the exit frame, pop the arguments, and return.
1224 LeaveFrame(StackFrame::EXIT);
1225
1226 if (argument_count.is_valid()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001227 if (!argument_count_is_length) {
1228 ShiftLeftImm(argument_count, argument_count, Operand(kPointerSizeLog2));
1229 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001230 add(sp, sp, argument_count);
1231 }
1232}
1233
1234
1235void MacroAssembler::MovFromFloatResult(const DoubleRegister dst) {
1236 Move(dst, d1);
1237}
1238
1239
1240void MacroAssembler::MovFromFloatParameter(const DoubleRegister dst) {
1241 Move(dst, d1);
1242}
1243
Ben Murdochda12d292016-06-02 14:46:10 +01001244void MacroAssembler::PrepareForTailCall(const ParameterCount& callee_args_count,
1245 Register caller_args_count_reg,
1246 Register scratch0, Register scratch1) {
1247#if DEBUG
1248 if (callee_args_count.is_reg()) {
1249 DCHECK(!AreAliased(callee_args_count.reg(), caller_args_count_reg, scratch0,
1250 scratch1));
1251 } else {
1252 DCHECK(!AreAliased(caller_args_count_reg, scratch0, scratch1));
1253 }
1254#endif
1255
1256 // Calculate the end of destination area where we will put the arguments
1257 // after we drop current frame. We add kPointerSize to count the receiver
1258 // argument which is not included into formal parameters count.
1259 Register dst_reg = scratch0;
1260 ShiftLeftImm(dst_reg, caller_args_count_reg, Operand(kPointerSizeLog2));
1261 add(dst_reg, fp, dst_reg);
1262 addi(dst_reg, dst_reg,
1263 Operand(StandardFrameConstants::kCallerSPOffset + kPointerSize));
1264
1265 Register src_reg = caller_args_count_reg;
1266 // Calculate the end of source area. +kPointerSize is for the receiver.
1267 if (callee_args_count.is_reg()) {
1268 ShiftLeftImm(src_reg, callee_args_count.reg(), Operand(kPointerSizeLog2));
1269 add(src_reg, sp, src_reg);
1270 addi(src_reg, src_reg, Operand(kPointerSize));
1271 } else {
1272 Add(src_reg, sp, (callee_args_count.immediate() + 1) * kPointerSize, r0);
1273 }
1274
1275 if (FLAG_debug_code) {
1276 cmpl(src_reg, dst_reg);
1277 Check(lt, kStackAccessBelowStackPointer);
1278 }
1279
1280 // Restore caller's frame pointer and return address now as they will be
1281 // overwritten by the copying loop.
1282 RestoreFrameStateForTailCall();
1283
1284 // Now copy callee arguments to the caller frame going backwards to avoid
1285 // callee arguments corruption (source and destination areas could overlap).
1286
1287 // Both src_reg and dst_reg are pointing to the word after the one to copy,
1288 // so they must be pre-decremented in the loop.
1289 Register tmp_reg = scratch1;
1290 Label loop;
1291 if (callee_args_count.is_reg()) {
1292 addi(tmp_reg, callee_args_count.reg(), Operand(1)); // +1 for receiver
1293 } else {
1294 mov(tmp_reg, Operand(callee_args_count.immediate() + 1));
1295 }
1296 mtctr(tmp_reg);
1297 bind(&loop);
1298 LoadPU(tmp_reg, MemOperand(src_reg, -kPointerSize));
1299 StorePU(tmp_reg, MemOperand(dst_reg, -kPointerSize));
1300 bdnz(&loop);
1301
1302 // Leave current frame.
1303 mr(sp, dst_reg);
1304}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001305
1306void MacroAssembler::InvokePrologue(const ParameterCount& expected,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001307 const ParameterCount& actual, Label* done,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001308 bool* definitely_mismatches,
1309 InvokeFlag flag,
1310 const CallWrapper& call_wrapper) {
1311 bool definitely_matches = false;
1312 *definitely_mismatches = false;
1313 Label regular_invoke;
1314
1315 // Check whether the expected and actual arguments count match. If not,
1316 // setup registers according to contract with ArgumentsAdaptorTrampoline:
1317 // r3: actual arguments count
1318 // r4: function (passed through to callee)
1319 // r5: expected arguments count
1320
1321 // The code below is made a lot easier because the calling code already sets
1322 // up actual and expected registers according to the contract if values are
1323 // passed in registers.
1324
1325 // ARM has some sanity checks as per below, considering add them for PPC
1326 // DCHECK(actual.is_immediate() || actual.reg().is(r3));
1327 // DCHECK(expected.is_immediate() || expected.reg().is(r5));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001328
1329 if (expected.is_immediate()) {
1330 DCHECK(actual.is_immediate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001331 mov(r3, Operand(actual.immediate()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001332 if (expected.immediate() == actual.immediate()) {
1333 definitely_matches = true;
1334 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001335 const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
1336 if (expected.immediate() == sentinel) {
1337 // Don't worry about adapting arguments for builtins that
1338 // don't want that done. Skip adaption code by making it look
1339 // like we have a match between expected and actual number of
1340 // arguments.
1341 definitely_matches = true;
1342 } else {
1343 *definitely_mismatches = true;
1344 mov(r5, Operand(expected.immediate()));
1345 }
1346 }
1347 } else {
1348 if (actual.is_immediate()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001349 mov(r3, Operand(actual.immediate()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001350 cmpi(expected.reg(), Operand(actual.immediate()));
1351 beq(&regular_invoke);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001352 } else {
1353 cmp(expected.reg(), actual.reg());
1354 beq(&regular_invoke);
1355 }
1356 }
1357
1358 if (!definitely_matches) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001359 Handle<Code> adaptor = isolate()->builtins()->ArgumentsAdaptorTrampoline();
1360 if (flag == CALL_FUNCTION) {
1361 call_wrapper.BeforeCall(CallSize(adaptor));
1362 Call(adaptor);
1363 call_wrapper.AfterCall();
1364 if (!*definitely_mismatches) {
1365 b(done);
1366 }
1367 } else {
1368 Jump(adaptor, RelocInfo::CODE_TARGET);
1369 }
1370 bind(&regular_invoke);
1371 }
1372}
1373
1374
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001375void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target,
1376 const ParameterCount& expected,
1377 const ParameterCount& actual) {
1378 Label skip_flooding;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001379 ExternalReference last_step_action =
1380 ExternalReference::debug_last_step_action_address(isolate());
1381 STATIC_ASSERT(StepFrame > StepIn);
1382 mov(r7, Operand(last_step_action));
1383 LoadByte(r7, MemOperand(r7), r0);
1384 extsb(r7, r7);
1385 cmpi(r7, Operand(StepIn));
1386 blt(&skip_flooding);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001387 {
1388 FrameScope frame(this,
1389 has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
1390 if (expected.is_reg()) {
1391 SmiTag(expected.reg());
1392 Push(expected.reg());
1393 }
1394 if (actual.is_reg()) {
1395 SmiTag(actual.reg());
1396 Push(actual.reg());
1397 }
1398 if (new_target.is_valid()) {
1399 Push(new_target);
1400 }
1401 Push(fun, fun);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001402 CallRuntime(Runtime::kDebugPrepareStepInIfStepping);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001403 Pop(fun);
1404 if (new_target.is_valid()) {
1405 Pop(new_target);
1406 }
1407 if (actual.is_reg()) {
1408 Pop(actual.reg());
1409 SmiUntag(actual.reg());
1410 }
1411 if (expected.is_reg()) {
1412 Pop(expected.reg());
1413 SmiUntag(expected.reg());
1414 }
1415 }
1416 bind(&skip_flooding);
1417}
1418
1419
1420void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
1421 const ParameterCount& expected,
1422 const ParameterCount& actual,
1423 InvokeFlag flag,
1424 const CallWrapper& call_wrapper) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001425 // You can't call a function without a valid frame.
1426 DCHECK(flag == JUMP_FUNCTION || has_frame());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001427 DCHECK(function.is(r4));
1428 DCHECK_IMPLIES(new_target.is_valid(), new_target.is(r6));
1429
1430 if (call_wrapper.NeedsDebugStepCheck()) {
1431 FloodFunctionIfStepping(function, new_target, expected, actual);
1432 }
1433
1434 // Clear the new.target register if not given.
1435 if (!new_target.is_valid()) {
1436 LoadRoot(r6, Heap::kUndefinedValueRootIndex);
1437 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001438
1439 Label done;
1440 bool definitely_mismatches = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001441 InvokePrologue(expected, actual, &done, &definitely_mismatches, flag,
1442 call_wrapper);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001443 if (!definitely_mismatches) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001444 // We call indirectly through the code field in the function to
1445 // allow recompilation to take effect without changing any of the
1446 // call sites.
1447 Register code = ip;
1448 LoadP(code, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001449 if (flag == CALL_FUNCTION) {
1450 call_wrapper.BeforeCall(CallSize(code));
1451 CallJSEntry(code);
1452 call_wrapper.AfterCall();
1453 } else {
1454 DCHECK(flag == JUMP_FUNCTION);
1455 JumpToJSEntry(code);
1456 }
1457
1458 // Continue here if InvokePrologue does handle the invocation due to
1459 // mismatched parameter counts.
1460 bind(&done);
1461 }
1462}
1463
1464
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001465void MacroAssembler::InvokeFunction(Register fun, Register new_target,
1466 const ParameterCount& actual,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001467 InvokeFlag flag,
1468 const CallWrapper& call_wrapper) {
1469 // You can't call a function without a valid frame.
1470 DCHECK(flag == JUMP_FUNCTION || has_frame());
1471
1472 // Contract with called JS functions requires that function is passed in r4.
1473 DCHECK(fun.is(r4));
1474
1475 Register expected_reg = r5;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001476 Register temp_reg = r7;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001477
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001478 LoadP(temp_reg, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001479 LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
1480 LoadWordArith(expected_reg,
1481 FieldMemOperand(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001482 temp_reg, SharedFunctionInfo::kFormalParameterCountOffset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001483#if !defined(V8_TARGET_ARCH_PPC64)
1484 SmiUntag(expected_reg);
1485#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001486
1487 ParameterCount expected(expected_reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001488 InvokeFunctionCode(fun, new_target, expected, actual, flag, call_wrapper);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001489}
1490
1491
1492void MacroAssembler::InvokeFunction(Register function,
1493 const ParameterCount& expected,
1494 const ParameterCount& actual,
1495 InvokeFlag flag,
1496 const CallWrapper& call_wrapper) {
1497 // You can't call a function without a valid frame.
1498 DCHECK(flag == JUMP_FUNCTION || has_frame());
1499
1500 // Contract with called JS functions requires that function is passed in r4.
1501 DCHECK(function.is(r4));
1502
1503 // Get the function and setup the context.
1504 LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
1505
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001506 InvokeFunctionCode(r4, no_reg, expected, actual, flag, call_wrapper);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001507}
1508
1509
1510void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
1511 const ParameterCount& expected,
1512 const ParameterCount& actual,
1513 InvokeFlag flag,
1514 const CallWrapper& call_wrapper) {
1515 Move(r4, function);
1516 InvokeFunction(r4, expected, actual, flag, call_wrapper);
1517}
1518
1519
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001520void MacroAssembler::IsObjectJSStringType(Register object, Register scratch,
1521 Label* fail) {
1522 DCHECK(kNotStringTag != 0);
1523
1524 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
1525 lbz(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
1526 andi(r0, scratch, Operand(kIsNotStringMask));
1527 bne(fail, cr0);
1528}
1529
1530
1531void MacroAssembler::IsObjectNameType(Register object, Register scratch,
1532 Label* fail) {
1533 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
1534 lbz(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
1535 cmpi(scratch, Operand(LAST_NAME_TYPE));
1536 bgt(fail);
1537}
1538
1539
1540void MacroAssembler::DebugBreak() {
1541 li(r3, Operand::Zero());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001542 mov(r4,
1543 Operand(ExternalReference(Runtime::kHandleDebuggerStatement, isolate())));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001544 CEntryStub ces(isolate(), 1);
1545 DCHECK(AllowThisStubCall(&ces));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001546 Call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001547}
1548
1549
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001550void MacroAssembler::PushStackHandler() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001551 // Adjust this code if not the case.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001552 STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001553 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001554
1555 // Link the current handler as the next handler.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001556 // Preserve r3-r7.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001557 mov(r8, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
1558 LoadP(r0, MemOperand(r8));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001559 push(r0);
1560
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001561 // Set this new handler as the current one.
1562 StoreP(sp, MemOperand(r8));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001563}
1564
1565
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001566void MacroAssembler::PopStackHandler() {
1567 STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001568 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001569
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001570 pop(r4);
1571 mov(ip, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001572 StoreP(r4, MemOperand(ip));
1573}
1574
1575
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001576void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
1577 Register scratch, Label* miss) {
1578 Label same_contexts;
1579
1580 DCHECK(!holder_reg.is(scratch));
1581 DCHECK(!holder_reg.is(ip));
1582 DCHECK(!scratch.is(ip));
1583
Ben Murdochda12d292016-06-02 14:46:10 +01001584 // Load current lexical context from the active StandardFrame, which
1585 // may require crawling past STUB frames.
1586 Label load_context;
1587 Label has_context;
1588 DCHECK(!ip.is(scratch));
1589 mr(ip, fp);
1590 bind(&load_context);
1591 LoadP(scratch,
1592 MemOperand(ip, CommonFrameConstants::kContextOrFrameTypeOffset));
1593 JumpIfNotSmi(scratch, &has_context);
1594 LoadP(ip, MemOperand(ip, CommonFrameConstants::kCallerFPOffset));
1595 b(&load_context);
1596 bind(&has_context);
1597
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001598// In debug mode, make sure the lexical context is set.
1599#ifdef DEBUG
1600 cmpi(scratch, Operand::Zero());
1601 Check(ne, kWeShouldNotHaveAnEmptyLexicalContext);
1602#endif
1603
1604 // Load the native context of the current context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001605 LoadP(scratch, ContextMemOperand(scratch, Context::NATIVE_CONTEXT_INDEX));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001606
1607 // Check the context is a native context.
1608 if (emit_debug_code()) {
1609 // Cannot use ip as a temporary in this verification code. Due to the fact
1610 // that ip is clobbered as part of cmp with an object Operand.
1611 push(holder_reg); // Temporarily save holder on the stack.
1612 // Read the first word and compare to the native_context_map.
1613 LoadP(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset));
1614 LoadRoot(ip, Heap::kNativeContextMapRootIndex);
1615 cmp(holder_reg, ip);
1616 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext);
1617 pop(holder_reg); // Restore holder.
1618 }
1619
1620 // Check if both contexts are the same.
1621 LoadP(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
1622 cmp(scratch, ip);
1623 beq(&same_contexts);
1624
1625 // Check the context is a native context.
1626 if (emit_debug_code()) {
1627 // Cannot use ip as a temporary in this verification code. Due to the fact
1628 // that ip is clobbered as part of cmp with an object Operand.
1629 push(holder_reg); // Temporarily save holder on the stack.
1630 mr(holder_reg, ip); // Move ip to its holding place.
1631 LoadRoot(ip, Heap::kNullValueRootIndex);
1632 cmp(holder_reg, ip);
1633 Check(ne, kJSGlobalProxyContextShouldNotBeNull);
1634
1635 LoadP(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset));
1636 LoadRoot(ip, Heap::kNativeContextMapRootIndex);
1637 cmp(holder_reg, ip);
1638 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext);
1639 // Restore ip is not needed. ip is reloaded below.
1640 pop(holder_reg); // Restore holder.
1641 // Restore ip to holder's context.
1642 LoadP(ip, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
1643 }
1644
1645 // Check that the security token in the calling global object is
1646 // compatible with the security token in the receiving global
1647 // object.
1648 int token_offset =
1649 Context::kHeaderSize + Context::SECURITY_TOKEN_INDEX * kPointerSize;
1650
1651 LoadP(scratch, FieldMemOperand(scratch, token_offset));
1652 LoadP(ip, FieldMemOperand(ip, token_offset));
1653 cmp(scratch, ip);
1654 bne(miss);
1655
1656 bind(&same_contexts);
1657}
1658
1659
1660// Compute the hash code from the untagged key. This must be kept in sync with
1661// ComputeIntegerHash in utils.h and KeyedLoadGenericStub in
1662// code-stub-hydrogen.cc
1663void MacroAssembler::GetNumberHash(Register t0, Register scratch) {
1664 // First of all we assign the hash seed to scratch.
1665 LoadRoot(scratch, Heap::kHashSeedRootIndex);
1666 SmiUntag(scratch);
1667
1668 // Xor original key with a seed.
1669 xor_(t0, t0, scratch);
1670
1671 // Compute the hash code from the untagged key. This must be kept in sync
1672 // with ComputeIntegerHash in utils.h.
1673 //
1674 // hash = ~hash + (hash << 15);
1675 notx(scratch, t0);
1676 slwi(t0, t0, Operand(15));
1677 add(t0, scratch, t0);
1678 // hash = hash ^ (hash >> 12);
1679 srwi(scratch, t0, Operand(12));
1680 xor_(t0, t0, scratch);
1681 // hash = hash + (hash << 2);
1682 slwi(scratch, t0, Operand(2));
1683 add(t0, t0, scratch);
1684 // hash = hash ^ (hash >> 4);
1685 srwi(scratch, t0, Operand(4));
1686 xor_(t0, t0, scratch);
1687 // hash = hash * 2057;
1688 mr(r0, t0);
1689 slwi(scratch, t0, Operand(3));
1690 add(t0, t0, scratch);
1691 slwi(scratch, r0, Operand(11));
1692 add(t0, t0, scratch);
1693 // hash = hash ^ (hash >> 16);
1694 srwi(scratch, t0, Operand(16));
1695 xor_(t0, t0, scratch);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001696 // hash & 0x3fffffff
1697 ExtractBitRange(t0, t0, 29, 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001698}
1699
1700
1701void MacroAssembler::LoadFromNumberDictionary(Label* miss, Register elements,
1702 Register key, Register result,
1703 Register t0, Register t1,
1704 Register t2) {
1705 // Register use:
1706 //
1707 // elements - holds the slow-case elements of the receiver on entry.
1708 // Unchanged unless 'result' is the same register.
1709 //
1710 // key - holds the smi key on entry.
1711 // Unchanged unless 'result' is the same register.
1712 //
1713 // result - holds the result on exit if the load succeeded.
1714 // Allowed to be the same as 'key' or 'result'.
1715 // Unchanged on bailout so 'key' or 'result' can be used
1716 // in further computation.
1717 //
1718 // Scratch registers:
1719 //
1720 // t0 - holds the untagged key on entry and holds the hash once computed.
1721 //
1722 // t1 - used to hold the capacity mask of the dictionary
1723 //
1724 // t2 - used for the index into the dictionary.
1725 Label done;
1726
1727 GetNumberHash(t0, t1);
1728
1729 // Compute the capacity mask.
1730 LoadP(t1, FieldMemOperand(elements, SeededNumberDictionary::kCapacityOffset));
1731 SmiUntag(t1);
1732 subi(t1, t1, Operand(1));
1733
1734 // Generate an unrolled loop that performs a few probes before giving up.
1735 for (int i = 0; i < kNumberDictionaryProbes; i++) {
1736 // Use t2 for index calculations and keep the hash intact in t0.
1737 mr(t2, t0);
1738 // Compute the masked index: (hash + i + i * i) & mask.
1739 if (i > 0) {
1740 addi(t2, t2, Operand(SeededNumberDictionary::GetProbeOffset(i)));
1741 }
1742 and_(t2, t2, t1);
1743
1744 // Scale the index by multiplying by the element size.
1745 DCHECK(SeededNumberDictionary::kEntrySize == 3);
1746 slwi(ip, t2, Operand(1));
1747 add(t2, t2, ip); // t2 = t2 * 3
1748
1749 // Check if the key is identical to the name.
1750 slwi(t2, t2, Operand(kPointerSizeLog2));
1751 add(t2, elements, t2);
1752 LoadP(ip,
1753 FieldMemOperand(t2, SeededNumberDictionary::kElementsStartOffset));
1754 cmp(key, ip);
1755 if (i != kNumberDictionaryProbes - 1) {
1756 beq(&done);
1757 } else {
1758 bne(miss);
1759 }
1760 }
1761
1762 bind(&done);
1763 // Check that the value is a field property.
1764 // t2: elements + (index * kPointerSize)
1765 const int kDetailsOffset =
1766 SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
1767 LoadP(t1, FieldMemOperand(t2, kDetailsOffset));
1768 LoadSmiLiteral(ip, Smi::FromInt(PropertyDetails::TypeField::kMask));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001769 DCHECK_EQ(DATA, 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001770 and_(r0, t1, ip, SetRC);
1771 bne(miss, cr0);
1772
1773 // Get the value at the masked, scaled index and return.
1774 const int kValueOffset =
1775 SeededNumberDictionary::kElementsStartOffset + kPointerSize;
1776 LoadP(result, FieldMemOperand(t2, kValueOffset));
1777}
1778
1779
1780void MacroAssembler::Allocate(int object_size, Register result,
1781 Register scratch1, Register scratch2,
1782 Label* gc_required, AllocationFlags flags) {
1783 DCHECK(object_size <= Page::kMaxRegularHeapObjectSize);
Ben Murdochc5610432016-08-08 18:44:38 +01001784 DCHECK((flags & ALLOCATION_FOLDED) == 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001785 if (!FLAG_inline_new) {
1786 if (emit_debug_code()) {
1787 // Trash the registers to simulate an allocation failure.
1788 li(result, Operand(0x7091));
1789 li(scratch1, Operand(0x7191));
1790 li(scratch2, Operand(0x7291));
1791 }
1792 b(gc_required);
1793 return;
1794 }
1795
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001796 DCHECK(!AreAliased(result, scratch1, scratch2, ip));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001797
1798 // Make object size into bytes.
1799 if ((flags & SIZE_IN_WORDS) != 0) {
1800 object_size *= kPointerSize;
1801 }
1802 DCHECK_EQ(0, static_cast<int>(object_size & kObjectAlignmentMask));
1803
1804 // Check relative positions of allocation top and limit addresses.
1805 ExternalReference allocation_top =
1806 AllocationUtils::GetAllocationTopReference(isolate(), flags);
1807 ExternalReference allocation_limit =
1808 AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1809
1810 intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address());
1811 intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address());
1812 DCHECK((limit - top) == kPointerSize);
1813
1814 // Set up allocation top address register.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001815 Register top_address = scratch1;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001816 // This code stores a temporary value in ip. This is OK, as the code below
1817 // does not need ip for implicit literal generation.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001818 Register alloc_limit = ip;
1819 Register result_end = scratch2;
1820 mov(top_address, Operand(allocation_top));
1821
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001822 if ((flags & RESULT_CONTAINS_TOP) == 0) {
1823 // Load allocation top into result and allocation limit into ip.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001824 LoadP(result, MemOperand(top_address));
1825 LoadP(alloc_limit, MemOperand(top_address, kPointerSize));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001826 } else {
1827 if (emit_debug_code()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001828 // Assert that result actually contains top on entry.
1829 LoadP(alloc_limit, MemOperand(top_address));
1830 cmp(result, alloc_limit);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001831 Check(eq, kUnexpectedAllocationTop);
1832 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001833 // Load allocation limit. Result already contains allocation top.
1834 LoadP(alloc_limit, MemOperand(top_address, limit - top));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001835 }
1836
1837 if ((flags & DOUBLE_ALIGNMENT) != 0) {
1838 // Align the next allocation. Storing the filler map without checking top is
1839 // safe in new-space because the limit of the heap is aligned there.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001840#if V8_TARGET_ARCH_PPC64
1841 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
1842#else
1843 STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001844 andi(result_end, result, Operand(kDoubleAlignmentMask));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001845 Label aligned;
1846 beq(&aligned, cr0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001847 if ((flags & PRETENURE) != 0) {
1848 cmpl(result, alloc_limit);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001849 bge(gc_required);
1850 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001851 mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
1852 stw(result_end, MemOperand(result));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001853 addi(result, result, Operand(kDoubleSize / 2));
1854 bind(&aligned);
1855#endif
1856 }
1857
1858 // Calculate new top and bail out if new space is exhausted. Use result
1859 // to calculate the new top.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001860 sub(r0, alloc_limit, result);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001861 if (is_int16(object_size)) {
1862 cmpi(r0, Operand(object_size));
1863 blt(gc_required);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001864 addi(result_end, result, Operand(object_size));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001865 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001866 Cmpi(r0, Operand(object_size), result_end);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001867 blt(gc_required);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001868 add(result_end, result, result_end);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001869 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001870
Ben Murdochc5610432016-08-08 18:44:38 +01001871 if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) {
1872 // The top pointer is not updated for allocation folding dominators.
1873 StoreP(result_end, MemOperand(top_address));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001874 }
Ben Murdochc5610432016-08-08 18:44:38 +01001875
1876 // Tag object.
1877 addi(result, result, Operand(kHeapObjectTag));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001878}
1879
1880
1881void MacroAssembler::Allocate(Register object_size, Register result,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001882 Register result_end, Register scratch,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001883 Label* gc_required, AllocationFlags flags) {
Ben Murdochc5610432016-08-08 18:44:38 +01001884 DCHECK((flags & ALLOCATION_FOLDED) == 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001885 if (!FLAG_inline_new) {
1886 if (emit_debug_code()) {
1887 // Trash the registers to simulate an allocation failure.
1888 li(result, Operand(0x7091));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001889 li(scratch, Operand(0x7191));
1890 li(result_end, Operand(0x7291));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001891 }
1892 b(gc_required);
1893 return;
1894 }
1895
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001896 // |object_size| and |result_end| may overlap if the DOUBLE_ALIGNMENT flag
1897 // is not specified. Other registers must not overlap.
1898 DCHECK(!AreAliased(object_size, result, scratch, ip));
1899 DCHECK(!AreAliased(result_end, result, scratch, ip));
1900 DCHECK((flags & DOUBLE_ALIGNMENT) == 0 || !object_size.is(result_end));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001901
1902 // Check relative positions of allocation top and limit addresses.
1903 ExternalReference allocation_top =
1904 AllocationUtils::GetAllocationTopReference(isolate(), flags);
1905 ExternalReference allocation_limit =
1906 AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1907 intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address());
1908 intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address());
1909 DCHECK((limit - top) == kPointerSize);
1910
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001911 // Set up allocation top address and allocation limit registers.
1912 Register top_address = scratch;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001913 // This code stores a temporary value in ip. This is OK, as the code below
1914 // does not need ip for implicit literal generation.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001915 Register alloc_limit = ip;
1916 mov(top_address, Operand(allocation_top));
1917
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001918 if ((flags & RESULT_CONTAINS_TOP) == 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001919 // Load allocation top into result and allocation limit into alloc_limit..
1920 LoadP(result, MemOperand(top_address));
1921 LoadP(alloc_limit, MemOperand(top_address, kPointerSize));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001922 } else {
1923 if (emit_debug_code()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001924 // Assert that result actually contains top on entry.
1925 LoadP(alloc_limit, MemOperand(top_address));
1926 cmp(result, alloc_limit);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001927 Check(eq, kUnexpectedAllocationTop);
1928 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001929 // Load allocation limit. Result already contains allocation top.
1930 LoadP(alloc_limit, MemOperand(top_address, limit - top));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001931 }
1932
1933 if ((flags & DOUBLE_ALIGNMENT) != 0) {
1934 // Align the next allocation. Storing the filler map without checking top is
1935 // safe in new-space because the limit of the heap is aligned there.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001936#if V8_TARGET_ARCH_PPC64
1937 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
1938#else
1939 STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001940 andi(result_end, result, Operand(kDoubleAlignmentMask));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001941 Label aligned;
1942 beq(&aligned, cr0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001943 if ((flags & PRETENURE) != 0) {
1944 cmpl(result, alloc_limit);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001945 bge(gc_required);
1946 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001947 mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
1948 stw(result_end, MemOperand(result));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001949 addi(result, result, Operand(kDoubleSize / 2));
1950 bind(&aligned);
1951#endif
1952 }
1953
1954 // Calculate new top and bail out if new space is exhausted. Use result
1955 // to calculate the new top. Object size may be in words so a shift is
1956 // required to get the number of bytes.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001957 sub(r0, alloc_limit, result);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001958 if ((flags & SIZE_IN_WORDS) != 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001959 ShiftLeftImm(result_end, object_size, Operand(kPointerSizeLog2));
1960 cmp(r0, result_end);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001961 blt(gc_required);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001962 add(result_end, result, result_end);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001963 } else {
1964 cmp(r0, object_size);
1965 blt(gc_required);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001966 add(result_end, result, object_size);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001967 }
1968
1969 // Update allocation top. result temporarily holds the new top.
1970 if (emit_debug_code()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001971 andi(r0, result_end, Operand(kObjectAlignmentMask));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001972 Check(eq, kUnalignedAllocationInNewSpace, cr0);
1973 }
Ben Murdochc5610432016-08-08 18:44:38 +01001974 if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) {
1975 // The top pointer is not updated for allocation folding dominators.
1976 StoreP(result_end, MemOperand(top_address));
1977 }
1978
1979 // Tag object.
1980 addi(result, result, Operand(kHeapObjectTag));
1981}
1982
1983void MacroAssembler::FastAllocate(Register object_size, Register result,
1984 Register result_end, Register scratch,
1985 AllocationFlags flags) {
1986 // |object_size| and |result_end| may overlap if the DOUBLE_ALIGNMENT flag
1987 // is not specified. Other registers must not overlap.
1988 DCHECK(!AreAliased(object_size, result, scratch, ip));
1989 DCHECK(!AreAliased(result_end, result, scratch, ip));
1990 DCHECK((flags & DOUBLE_ALIGNMENT) == 0 || !object_size.is(result_end));
1991
1992 ExternalReference allocation_top =
1993 AllocationUtils::GetAllocationTopReference(isolate(), flags);
1994
1995 Register top_address = scratch;
1996 mov(top_address, Operand(allocation_top));
1997 LoadP(result, MemOperand(top_address));
1998
1999 if ((flags & DOUBLE_ALIGNMENT) != 0) {
2000 // Align the next allocation. Storing the filler map without checking top is
2001 // safe in new-space because the limit of the heap is aligned there.
2002#if V8_TARGET_ARCH_PPC64
2003 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
2004#else
2005 DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
2006 andi(result_end, result, Operand(kDoubleAlignmentMask));
2007 Label aligned;
2008 beq(&aligned);
2009 mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
2010 stw(result_end, MemOperand(result));
2011 addi(result, result, Operand(kDoubleSize / 2));
2012 bind(&aligned);
2013#endif
2014 }
2015
2016 // Calculate new top using result. Object size may be in words so a shift is
2017 // required to get the number of bytes.
2018 if ((flags & SIZE_IN_WORDS) != 0) {
2019 ShiftLeftImm(result_end, object_size, Operand(kPointerSizeLog2));
2020 add(result_end, result, result_end);
2021 } else {
2022 add(result_end, result, object_size);
2023 }
2024
2025 // Update allocation top. result temporarily holds the new top.
2026 if (emit_debug_code()) {
2027 andi(r0, result_end, Operand(kObjectAlignmentMask));
2028 Check(eq, kUnalignedAllocationInNewSpace, cr0);
2029 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002030 StoreP(result_end, MemOperand(top_address));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002031
Ben Murdochc5610432016-08-08 18:44:38 +01002032 // Tag object.
2033 addi(result, result, Operand(kHeapObjectTag));
2034}
2035
2036void MacroAssembler::FastAllocate(int object_size, Register result,
2037 Register scratch1, Register scratch2,
2038 AllocationFlags flags) {
2039 DCHECK(object_size <= Page::kMaxRegularHeapObjectSize);
2040 DCHECK(!AreAliased(result, scratch1, scratch2, ip));
2041
2042 // Make object size into bytes.
2043 if ((flags & SIZE_IN_WORDS) != 0) {
2044 object_size *= kPointerSize;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002045 }
Ben Murdochc5610432016-08-08 18:44:38 +01002046 DCHECK_EQ(0, object_size & kObjectAlignmentMask);
2047
2048 ExternalReference allocation_top =
2049 AllocationUtils::GetAllocationTopReference(isolate(), flags);
2050
2051 // Set up allocation top address register.
2052 Register top_address = scratch1;
2053 Register result_end = scratch2;
2054 mov(top_address, Operand(allocation_top));
2055 LoadP(result, MemOperand(top_address));
2056
2057 if ((flags & DOUBLE_ALIGNMENT) != 0) {
2058 // Align the next allocation. Storing the filler map without checking top is
2059 // safe in new-space because the limit of the heap is aligned there.
2060#if V8_TARGET_ARCH_PPC64
2061 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
2062#else
2063 DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
2064 andi(result_end, result, Operand(kDoubleAlignmentMask));
2065 Label aligned;
2066 beq(&aligned);
2067 mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
2068 stw(result_end, MemOperand(result));
2069 addi(result, result, Operand(kDoubleSize / 2));
2070 bind(&aligned);
2071#endif
2072 }
2073
2074 // Calculate new top using result.
2075 Add(result_end, result, object_size, r0);
2076
2077 // The top pointer is not updated for allocation folding dominators.
2078 StoreP(result_end, MemOperand(top_address));
2079
2080 // Tag object.
2081 addi(result, result, Operand(kHeapObjectTag));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002082}
2083
2084
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002085void MacroAssembler::AllocateTwoByteString(Register result, Register length,
2086 Register scratch1, Register scratch2,
2087 Register scratch3,
2088 Label* gc_required) {
2089 // Calculate the number of bytes needed for the characters in the string while
2090 // observing object alignment.
2091 DCHECK((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
2092 slwi(scratch1, length, Operand(1)); // Length in bytes, not chars.
2093 addi(scratch1, scratch1,
2094 Operand(kObjectAlignmentMask + SeqTwoByteString::kHeaderSize));
2095 mov(r0, Operand(~kObjectAlignmentMask));
2096 and_(scratch1, scratch1, r0);
2097
2098 // Allocate two-byte string in new space.
Ben Murdochc5610432016-08-08 18:44:38 +01002099 Allocate(scratch1, result, scratch2, scratch3, gc_required,
2100 NO_ALLOCATION_FLAGS);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002101
2102 // Set the map, length and hash field.
2103 InitializeNewString(result, length, Heap::kStringMapRootIndex, scratch1,
2104 scratch2);
2105}
2106
2107
2108void MacroAssembler::AllocateOneByteString(Register result, Register length,
2109 Register scratch1, Register scratch2,
2110 Register scratch3,
2111 Label* gc_required) {
2112 // Calculate the number of bytes needed for the characters in the string while
2113 // observing object alignment.
2114 DCHECK((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
2115 DCHECK(kCharSize == 1);
2116 addi(scratch1, length,
2117 Operand(kObjectAlignmentMask + SeqOneByteString::kHeaderSize));
2118 li(r0, Operand(~kObjectAlignmentMask));
2119 and_(scratch1, scratch1, r0);
2120
2121 // Allocate one-byte string in new space.
Ben Murdochc5610432016-08-08 18:44:38 +01002122 Allocate(scratch1, result, scratch2, scratch3, gc_required,
2123 NO_ALLOCATION_FLAGS);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002124
2125 // Set the map, length and hash field.
2126 InitializeNewString(result, length, Heap::kOneByteStringMapRootIndex,
2127 scratch1, scratch2);
2128}
2129
2130
2131void MacroAssembler::AllocateTwoByteConsString(Register result, Register length,
2132 Register scratch1,
2133 Register scratch2,
2134 Label* gc_required) {
2135 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
Ben Murdochc5610432016-08-08 18:44:38 +01002136 NO_ALLOCATION_FLAGS);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002137
2138 InitializeNewString(result, length, Heap::kConsStringMapRootIndex, scratch1,
2139 scratch2);
2140}
2141
2142
2143void MacroAssembler::AllocateOneByteConsString(Register result, Register length,
2144 Register scratch1,
2145 Register scratch2,
2146 Label* gc_required) {
2147 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
Ben Murdochc5610432016-08-08 18:44:38 +01002148 NO_ALLOCATION_FLAGS);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002149
2150 InitializeNewString(result, length, Heap::kConsOneByteStringMapRootIndex,
2151 scratch1, scratch2);
2152}
2153
2154
2155void MacroAssembler::AllocateTwoByteSlicedString(Register result,
2156 Register length,
2157 Register scratch1,
2158 Register scratch2,
2159 Label* gc_required) {
2160 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
Ben Murdochc5610432016-08-08 18:44:38 +01002161 NO_ALLOCATION_FLAGS);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002162
2163 InitializeNewString(result, length, Heap::kSlicedStringMapRootIndex, scratch1,
2164 scratch2);
2165}
2166
2167
2168void MacroAssembler::AllocateOneByteSlicedString(Register result,
2169 Register length,
2170 Register scratch1,
2171 Register scratch2,
2172 Label* gc_required) {
2173 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
Ben Murdochc5610432016-08-08 18:44:38 +01002174 NO_ALLOCATION_FLAGS);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002175
2176 InitializeNewString(result, length, Heap::kSlicedOneByteStringMapRootIndex,
2177 scratch1, scratch2);
2178}
2179
2180
2181void MacroAssembler::CompareObjectType(Register object, Register map,
2182 Register type_reg, InstanceType type) {
2183 const Register temp = type_reg.is(no_reg) ? r0 : type_reg;
2184
2185 LoadP(map, FieldMemOperand(object, HeapObject::kMapOffset));
2186 CompareInstanceType(map, temp, type);
2187}
2188
2189
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002190void MacroAssembler::CompareInstanceType(Register map, Register type_reg,
2191 InstanceType type) {
2192 STATIC_ASSERT(Map::kInstanceTypeOffset < 4096);
2193 STATIC_ASSERT(LAST_TYPE < 256);
2194 lbz(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
2195 cmpi(type_reg, Operand(type));
2196}
2197
2198
2199void MacroAssembler::CompareRoot(Register obj, Heap::RootListIndex index) {
2200 DCHECK(!obj.is(r0));
2201 LoadRoot(r0, index);
2202 cmp(obj, r0);
2203}
2204
2205
2206void MacroAssembler::CheckFastElements(Register map, Register scratch,
2207 Label* fail) {
2208 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
2209 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
2210 STATIC_ASSERT(FAST_ELEMENTS == 2);
2211 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
2212 lbz(scratch, FieldMemOperand(map, Map::kBitField2Offset));
2213 STATIC_ASSERT(Map::kMaximumBitField2FastHoleyElementValue < 0x8000);
2214 cmpli(scratch, Operand(Map::kMaximumBitField2FastHoleyElementValue));
2215 bgt(fail);
2216}
2217
2218
2219void MacroAssembler::CheckFastObjectElements(Register map, Register scratch,
2220 Label* fail) {
2221 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
2222 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
2223 STATIC_ASSERT(FAST_ELEMENTS == 2);
2224 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
2225 lbz(scratch, FieldMemOperand(map, Map::kBitField2Offset));
2226 cmpli(scratch, Operand(Map::kMaximumBitField2FastHoleySmiElementValue));
2227 ble(fail);
2228 cmpli(scratch, Operand(Map::kMaximumBitField2FastHoleyElementValue));
2229 bgt(fail);
2230}
2231
2232
2233void MacroAssembler::CheckFastSmiElements(Register map, Register scratch,
2234 Label* fail) {
2235 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
2236 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
2237 lbz(scratch, FieldMemOperand(map, Map::kBitField2Offset));
2238 cmpli(scratch, Operand(Map::kMaximumBitField2FastHoleySmiElementValue));
2239 bgt(fail);
2240}
2241
2242
2243void MacroAssembler::StoreNumberToDoubleElements(
2244 Register value_reg, Register key_reg, Register elements_reg,
2245 Register scratch1, DoubleRegister double_scratch, Label* fail,
2246 int elements_offset) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002247 DCHECK(!AreAliased(value_reg, key_reg, elements_reg, scratch1));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002248 Label smi_value, store;
2249
2250 // Handle smi values specially.
2251 JumpIfSmi(value_reg, &smi_value);
2252
2253 // Ensure that the object is a heap number
2254 CheckMap(value_reg, scratch1, isolate()->factory()->heap_number_map(), fail,
2255 DONT_DO_SMI_CHECK);
2256
2257 lfd(double_scratch, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002258 // Double value, turn potential sNaN into qNaN.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002259 CanonicalizeNaN(double_scratch);
2260 b(&store);
2261
2262 bind(&smi_value);
2263 SmiToDouble(double_scratch, value_reg);
2264
2265 bind(&store);
2266 SmiToDoubleArrayOffset(scratch1, key_reg);
2267 add(scratch1, elements_reg, scratch1);
2268 stfd(double_scratch, FieldMemOperand(scratch1, FixedDoubleArray::kHeaderSize -
2269 elements_offset));
2270}
2271
2272
2273void MacroAssembler::AddAndCheckForOverflow(Register dst, Register left,
2274 Register right,
2275 Register overflow_dst,
2276 Register scratch) {
2277 DCHECK(!dst.is(overflow_dst));
2278 DCHECK(!dst.is(scratch));
2279 DCHECK(!overflow_dst.is(scratch));
2280 DCHECK(!overflow_dst.is(left));
2281 DCHECK(!overflow_dst.is(right));
2282
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002283 bool left_is_right = left.is(right);
2284 RCBit xorRC = left_is_right ? SetRC : LeaveRC;
2285
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002286 // C = A+B; C overflows if A/B have same sign and C has diff sign than A
2287 if (dst.is(left)) {
2288 mr(scratch, left); // Preserve left.
2289 add(dst, left, right); // Left is overwritten.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002290 xor_(overflow_dst, dst, scratch, xorRC); // Original left.
2291 if (!left_is_right) xor_(scratch, dst, right);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002292 } else if (dst.is(right)) {
2293 mr(scratch, right); // Preserve right.
2294 add(dst, left, right); // Right is overwritten.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002295 xor_(overflow_dst, dst, left, xorRC);
2296 if (!left_is_right) xor_(scratch, dst, scratch); // Original right.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002297 } else {
2298 add(dst, left, right);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002299 xor_(overflow_dst, dst, left, xorRC);
2300 if (!left_is_right) xor_(scratch, dst, right);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002301 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002302 if (!left_is_right) and_(overflow_dst, scratch, overflow_dst, SetRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002303}
2304
2305
2306void MacroAssembler::AddAndCheckForOverflow(Register dst, Register left,
2307 intptr_t right,
2308 Register overflow_dst,
2309 Register scratch) {
2310 Register original_left = left;
2311 DCHECK(!dst.is(overflow_dst));
2312 DCHECK(!dst.is(scratch));
2313 DCHECK(!overflow_dst.is(scratch));
2314 DCHECK(!overflow_dst.is(left));
2315
2316 // C = A+B; C overflows if A/B have same sign and C has diff sign than A
2317 if (dst.is(left)) {
2318 // Preserve left.
2319 original_left = overflow_dst;
2320 mr(original_left, left);
2321 }
2322 Add(dst, left, right, scratch);
2323 xor_(overflow_dst, dst, original_left);
2324 if (right >= 0) {
2325 and_(overflow_dst, overflow_dst, dst, SetRC);
2326 } else {
2327 andc(overflow_dst, overflow_dst, dst, SetRC);
2328 }
2329}
2330
2331
2332void MacroAssembler::SubAndCheckForOverflow(Register dst, Register left,
2333 Register right,
2334 Register overflow_dst,
2335 Register scratch) {
2336 DCHECK(!dst.is(overflow_dst));
2337 DCHECK(!dst.is(scratch));
2338 DCHECK(!overflow_dst.is(scratch));
2339 DCHECK(!overflow_dst.is(left));
2340 DCHECK(!overflow_dst.is(right));
2341
2342 // C = A-B; C overflows if A/B have diff signs and C has diff sign than A
2343 if (dst.is(left)) {
2344 mr(scratch, left); // Preserve left.
2345 sub(dst, left, right); // Left is overwritten.
2346 xor_(overflow_dst, dst, scratch);
2347 xor_(scratch, scratch, right);
2348 and_(overflow_dst, overflow_dst, scratch, SetRC);
2349 } else if (dst.is(right)) {
2350 mr(scratch, right); // Preserve right.
2351 sub(dst, left, right); // Right is overwritten.
2352 xor_(overflow_dst, dst, left);
2353 xor_(scratch, left, scratch);
2354 and_(overflow_dst, overflow_dst, scratch, SetRC);
2355 } else {
2356 sub(dst, left, right);
2357 xor_(overflow_dst, dst, left);
2358 xor_(scratch, left, right);
2359 and_(overflow_dst, scratch, overflow_dst, SetRC);
2360 }
2361}
2362
2363
2364void MacroAssembler::CompareMap(Register obj, Register scratch, Handle<Map> map,
2365 Label* early_success) {
2366 LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
2367 CompareMap(scratch, map, early_success);
2368}
2369
2370
2371void MacroAssembler::CompareMap(Register obj_map, Handle<Map> map,
2372 Label* early_success) {
2373 mov(r0, Operand(map));
2374 cmp(obj_map, r0);
2375}
2376
2377
2378void MacroAssembler::CheckMap(Register obj, Register scratch, Handle<Map> map,
2379 Label* fail, SmiCheckType smi_check_type) {
2380 if (smi_check_type == DO_SMI_CHECK) {
2381 JumpIfSmi(obj, fail);
2382 }
2383
2384 Label success;
2385 CompareMap(obj, scratch, map, &success);
2386 bne(fail);
2387 bind(&success);
2388}
2389
2390
2391void MacroAssembler::CheckMap(Register obj, Register scratch,
2392 Heap::RootListIndex index, Label* fail,
2393 SmiCheckType smi_check_type) {
2394 if (smi_check_type == DO_SMI_CHECK) {
2395 JumpIfSmi(obj, fail);
2396 }
2397 LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
2398 LoadRoot(r0, index);
2399 cmp(scratch, r0);
2400 bne(fail);
2401}
2402
2403
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002404void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1,
2405 Register scratch2, Handle<WeakCell> cell,
2406 Handle<Code> success,
2407 SmiCheckType smi_check_type) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002408 Label fail;
2409 if (smi_check_type == DO_SMI_CHECK) {
2410 JumpIfSmi(obj, &fail);
2411 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002412 LoadP(scratch1, FieldMemOperand(obj, HeapObject::kMapOffset));
2413 CmpWeakValue(scratch1, cell, scratch2);
2414 Jump(success, RelocInfo::CODE_TARGET, eq);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002415 bind(&fail);
2416}
2417
2418
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002419void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell,
2420 Register scratch, CRegister cr) {
2421 mov(scratch, Operand(cell));
2422 LoadP(scratch, FieldMemOperand(scratch, WeakCell::kValueOffset));
2423 cmp(value, scratch, cr);
2424}
2425
2426
2427void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) {
2428 mov(value, Operand(cell));
2429 LoadP(value, FieldMemOperand(value, WeakCell::kValueOffset));
2430}
2431
2432
2433void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
2434 Label* miss) {
2435 GetWeakValue(value, cell);
2436 JumpIfSmi(value, miss);
2437}
2438
2439
2440void MacroAssembler::GetMapConstructor(Register result, Register map,
2441 Register temp, Register temp2) {
2442 Label done, loop;
2443 LoadP(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset));
2444 bind(&loop);
2445 JumpIfSmi(result, &done);
2446 CompareObjectType(result, temp, temp2, MAP_TYPE);
2447 bne(&done);
2448 LoadP(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset));
2449 b(&loop);
2450 bind(&done);
2451}
2452
2453
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002454void MacroAssembler::TryGetFunctionPrototype(Register function, Register result,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002455 Register scratch, Label* miss) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002456 // Get the prototype or initial map from the function.
2457 LoadP(result,
2458 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2459
2460 // If the prototype or initial map is the hole, don't return it and
2461 // simply miss the cache instead. This will allow us to allocate a
2462 // prototype object on-demand in the runtime system.
2463 LoadRoot(r0, Heap::kTheHoleValueRootIndex);
2464 cmp(result, r0);
2465 beq(miss);
2466
2467 // If the function does not have an initial map, we're done.
2468 Label done;
2469 CompareObjectType(result, scratch, scratch, MAP_TYPE);
2470 bne(&done);
2471
2472 // Get the prototype from the initial map.
2473 LoadP(result, FieldMemOperand(result, Map::kPrototypeOffset));
2474
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002475 // All done.
2476 bind(&done);
2477}
2478
2479
2480void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id,
2481 Condition cond) {
2482 DCHECK(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs.
2483 Call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id, cond);
2484}
2485
2486
2487void MacroAssembler::TailCallStub(CodeStub* stub, Condition cond) {
2488 Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond);
2489}
2490
2491
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002492bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
2493 return has_frame_ || !stub->SometimesSetsUpAFrame();
2494}
2495
2496
2497void MacroAssembler::IndexFromHash(Register hash, Register index) {
2498 // If the hash field contains an array index pick it out. The assert checks
2499 // that the constants for the maximum number of digits for an array index
2500 // cached in the hash field and the number of bits reserved for it does not
2501 // conflict.
2502 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
2503 (1 << String::kArrayIndexValueBits));
2504 DecodeFieldToSmi<String::ArrayIndexValueBits>(index, hash);
2505}
2506
2507
2508void MacroAssembler::SmiToDouble(DoubleRegister value, Register smi) {
2509 SmiUntag(ip, smi);
2510 ConvertIntToDouble(ip, value);
2511}
2512
2513
2514void MacroAssembler::TestDoubleIsInt32(DoubleRegister double_input,
2515 Register scratch1, Register scratch2,
2516 DoubleRegister double_scratch) {
2517 TryDoubleToInt32Exact(scratch1, double_input, scratch2, double_scratch);
2518}
2519
Ben Murdoch097c5b22016-05-18 11:27:45 +01002520void MacroAssembler::TestDoubleIsMinusZero(DoubleRegister input,
2521 Register scratch1,
2522 Register scratch2) {
2523#if V8_TARGET_ARCH_PPC64
2524 MovDoubleToInt64(scratch1, input);
2525 rotldi(scratch1, scratch1, 1);
2526 cmpi(scratch1, Operand(1));
2527#else
2528 MovDoubleToInt64(scratch1, scratch2, input);
2529 Label done;
2530 cmpi(scratch2, Operand::Zero());
2531 bne(&done);
2532 lis(scratch2, Operand(SIGN_EXT_IMM16(0x8000)));
2533 cmp(scratch1, scratch2);
2534 bind(&done);
2535#endif
2536}
2537
2538void MacroAssembler::TestDoubleSign(DoubleRegister input, Register scratch) {
2539#if V8_TARGET_ARCH_PPC64
2540 MovDoubleToInt64(scratch, input);
2541#else
2542 MovDoubleHighToInt(scratch, input);
2543#endif
2544 cmpi(scratch, Operand::Zero());
2545}
2546
2547void MacroAssembler::TestHeapNumberSign(Register input, Register scratch) {
2548#if V8_TARGET_ARCH_PPC64
2549 LoadP(scratch, FieldMemOperand(input, HeapNumber::kValueOffset));
2550#else
2551 lwz(scratch, FieldMemOperand(input, HeapNumber::kExponentOffset));
2552#endif
2553 cmpi(scratch, Operand::Zero());
2554}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002555
2556void MacroAssembler::TryDoubleToInt32Exact(Register result,
2557 DoubleRegister double_input,
2558 Register scratch,
2559 DoubleRegister double_scratch) {
2560 Label done;
2561 DCHECK(!double_input.is(double_scratch));
2562
2563 ConvertDoubleToInt64(double_input,
2564#if !V8_TARGET_ARCH_PPC64
2565 scratch,
2566#endif
2567 result, double_scratch);
2568
2569#if V8_TARGET_ARCH_PPC64
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002570 TestIfInt32(result, r0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002571#else
2572 TestIfInt32(scratch, result, r0);
2573#endif
2574 bne(&done);
2575
2576 // convert back and compare
2577 fcfid(double_scratch, double_scratch);
2578 fcmpu(double_scratch, double_input);
2579 bind(&done);
2580}
2581
2582
2583void MacroAssembler::TryInt32Floor(Register result, DoubleRegister double_input,
2584 Register input_high, Register scratch,
2585 DoubleRegister double_scratch, Label* done,
2586 Label* exact) {
2587 DCHECK(!result.is(input_high));
2588 DCHECK(!double_input.is(double_scratch));
2589 Label exception;
2590
2591 MovDoubleHighToInt(input_high, double_input);
2592
2593 // Test for NaN/Inf
2594 ExtractBitMask(result, input_high, HeapNumber::kExponentMask);
2595 cmpli(result, Operand(0x7ff));
2596 beq(&exception);
2597
2598 // Convert (rounding to -Inf)
2599 ConvertDoubleToInt64(double_input,
2600#if !V8_TARGET_ARCH_PPC64
2601 scratch,
2602#endif
2603 result, double_scratch, kRoundToMinusInf);
2604
2605// Test for overflow
2606#if V8_TARGET_ARCH_PPC64
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002607 TestIfInt32(result, r0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002608#else
2609 TestIfInt32(scratch, result, r0);
2610#endif
2611 bne(&exception);
2612
2613 // Test for exactness
2614 fcfid(double_scratch, double_scratch);
2615 fcmpu(double_scratch, double_input);
2616 beq(exact);
2617 b(done);
2618
2619 bind(&exception);
2620}
2621
2622
2623void MacroAssembler::TryInlineTruncateDoubleToI(Register result,
2624 DoubleRegister double_input,
2625 Label* done) {
2626 DoubleRegister double_scratch = kScratchDoubleReg;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002627#if !V8_TARGET_ARCH_PPC64
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002628 Register scratch = ip;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002629#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002630
2631 ConvertDoubleToInt64(double_input,
2632#if !V8_TARGET_ARCH_PPC64
2633 scratch,
2634#endif
2635 result, double_scratch);
2636
2637// Test for overflow
2638#if V8_TARGET_ARCH_PPC64
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002639 TestIfInt32(result, r0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002640#else
2641 TestIfInt32(scratch, result, r0);
2642#endif
2643 beq(done);
2644}
2645
2646
2647void MacroAssembler::TruncateDoubleToI(Register result,
2648 DoubleRegister double_input) {
2649 Label done;
2650
2651 TryInlineTruncateDoubleToI(result, double_input, &done);
2652
2653 // If we fell through then inline version didn't succeed - call stub instead.
2654 mflr(r0);
2655 push(r0);
2656 // Put input on stack.
2657 stfdu(double_input, MemOperand(sp, -kDoubleSize));
2658
2659 DoubleToIStub stub(isolate(), sp, result, 0, true, true);
2660 CallStub(&stub);
2661
2662 addi(sp, sp, Operand(kDoubleSize));
2663 pop(r0);
2664 mtlr(r0);
2665
2666 bind(&done);
2667}
2668
2669
2670void MacroAssembler::TruncateHeapNumberToI(Register result, Register object) {
2671 Label done;
2672 DoubleRegister double_scratch = kScratchDoubleReg;
2673 DCHECK(!result.is(object));
2674
2675 lfd(double_scratch, FieldMemOperand(object, HeapNumber::kValueOffset));
2676 TryInlineTruncateDoubleToI(result, double_scratch, &done);
2677
2678 // If we fell through then inline version didn't succeed - call stub instead.
2679 mflr(r0);
2680 push(r0);
2681 DoubleToIStub stub(isolate(), object, result,
2682 HeapNumber::kValueOffset - kHeapObjectTag, true, true);
2683 CallStub(&stub);
2684 pop(r0);
2685 mtlr(r0);
2686
2687 bind(&done);
2688}
2689
2690
2691void MacroAssembler::TruncateNumberToI(Register object, Register result,
2692 Register heap_number_map,
2693 Register scratch1, Label* not_number) {
2694 Label done;
2695 DCHECK(!result.is(object));
2696
2697 UntagAndJumpIfSmi(result, object, &done);
2698 JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number);
2699 TruncateHeapNumberToI(result, object);
2700
2701 bind(&done);
2702}
2703
2704
2705void MacroAssembler::GetLeastBitsFromSmi(Register dst, Register src,
2706 int num_least_bits) {
2707#if V8_TARGET_ARCH_PPC64
2708 rldicl(dst, src, kBitsPerPointer - kSmiShift,
2709 kBitsPerPointer - num_least_bits);
2710#else
2711 rlwinm(dst, src, kBitsPerPointer - kSmiShift,
2712 kBitsPerPointer - num_least_bits, 31);
2713#endif
2714}
2715
2716
2717void MacroAssembler::GetLeastBitsFromInt32(Register dst, Register src,
2718 int num_least_bits) {
2719 rlwinm(dst, src, 0, 32 - num_least_bits, 31);
2720}
2721
2722
2723void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments,
2724 SaveFPRegsMode save_doubles) {
2725 // All parameters are on the stack. r3 has the return value after call.
2726
2727 // If the expected number of arguments of the runtime function is
2728 // constant, we check that the actual number of arguments match the
2729 // expectation.
2730 CHECK(f->nargs < 0 || f->nargs == num_arguments);
2731
2732 // TODO(1236192): Most runtime routines don't need the number of
2733 // arguments passed in because it is constant. At some point we
2734 // should remove this need and make the runtime routine entry code
2735 // smarter.
2736 mov(r3, Operand(num_arguments));
2737 mov(r4, Operand(ExternalReference(f, isolate())));
2738 CEntryStub stub(isolate(),
2739#if V8_TARGET_ARCH_PPC64
2740 f->result_size,
2741#else
2742 1,
2743#endif
2744 save_doubles);
2745 CallStub(&stub);
2746}
2747
2748
2749void MacroAssembler::CallExternalReference(const ExternalReference& ext,
2750 int num_arguments) {
2751 mov(r3, Operand(num_arguments));
2752 mov(r4, Operand(ext));
2753
2754 CEntryStub stub(isolate(), 1);
2755 CallStub(&stub);
2756}
2757
2758
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002759void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
2760 const Runtime::Function* function = Runtime::FunctionForId(fid);
2761 DCHECK_EQ(1, function->result_size);
2762 if (function->nargs >= 0) {
2763 mov(r3, Operand(function->nargs));
2764 }
2765 JumpToExternalReference(ExternalReference(fid, isolate()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002766}
2767
2768
2769void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin) {
2770 mov(r4, Operand(builtin));
2771 CEntryStub stub(isolate(), 1);
2772 Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
2773}
2774
2775
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002776void MacroAssembler::SetCounter(StatsCounter* counter, int value,
2777 Register scratch1, Register scratch2) {
2778 if (FLAG_native_code_counters && counter->Enabled()) {
2779 mov(scratch1, Operand(value));
2780 mov(scratch2, Operand(ExternalReference(counter)));
2781 stw(scratch1, MemOperand(scratch2));
2782 }
2783}
2784
2785
2786void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
2787 Register scratch1, Register scratch2) {
2788 DCHECK(value > 0);
2789 if (FLAG_native_code_counters && counter->Enabled()) {
2790 mov(scratch2, Operand(ExternalReference(counter)));
2791 lwz(scratch1, MemOperand(scratch2));
2792 addi(scratch1, scratch1, Operand(value));
2793 stw(scratch1, MemOperand(scratch2));
2794 }
2795}
2796
2797
2798void MacroAssembler::DecrementCounter(StatsCounter* counter, int value,
2799 Register scratch1, Register scratch2) {
2800 DCHECK(value > 0);
2801 if (FLAG_native_code_counters && counter->Enabled()) {
2802 mov(scratch2, Operand(ExternalReference(counter)));
2803 lwz(scratch1, MemOperand(scratch2));
2804 subi(scratch1, scratch1, Operand(value));
2805 stw(scratch1, MemOperand(scratch2));
2806 }
2807}
2808
2809
2810void MacroAssembler::Assert(Condition cond, BailoutReason reason,
2811 CRegister cr) {
2812 if (emit_debug_code()) Check(cond, reason, cr);
2813}
2814
2815
2816void MacroAssembler::AssertFastElements(Register elements) {
2817 if (emit_debug_code()) {
2818 DCHECK(!elements.is(r0));
2819 Label ok;
2820 push(elements);
2821 LoadP(elements, FieldMemOperand(elements, HeapObject::kMapOffset));
2822 LoadRoot(r0, Heap::kFixedArrayMapRootIndex);
2823 cmp(elements, r0);
2824 beq(&ok);
2825 LoadRoot(r0, Heap::kFixedDoubleArrayMapRootIndex);
2826 cmp(elements, r0);
2827 beq(&ok);
2828 LoadRoot(r0, Heap::kFixedCOWArrayMapRootIndex);
2829 cmp(elements, r0);
2830 beq(&ok);
2831 Abort(kJSObjectWithFastElementsMapHasSlowElements);
2832 bind(&ok);
2833 pop(elements);
2834 }
2835}
2836
2837
2838void MacroAssembler::Check(Condition cond, BailoutReason reason, CRegister cr) {
2839 Label L;
2840 b(cond, &L, cr);
2841 Abort(reason);
2842 // will not return here
2843 bind(&L);
2844}
2845
2846
2847void MacroAssembler::Abort(BailoutReason reason) {
2848 Label abort_start;
2849 bind(&abort_start);
2850#ifdef DEBUG
2851 const char* msg = GetBailoutReason(reason);
2852 if (msg != NULL) {
2853 RecordComment("Abort message: ");
2854 RecordComment(msg);
2855 }
2856
2857 if (FLAG_trap_on_abort) {
2858 stop(msg);
2859 return;
2860 }
2861#endif
2862
2863 LoadSmiLiteral(r0, Smi::FromInt(reason));
2864 push(r0);
2865 // Disable stub call restrictions to always allow calls to abort.
2866 if (!has_frame_) {
2867 // We don't actually want to generate a pile of code for this, so just
2868 // claim there is a stack frame, without generating one.
2869 FrameScope scope(this, StackFrame::NONE);
Ben Murdoch097c5b22016-05-18 11:27:45 +01002870 CallRuntime(Runtime::kAbort);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002871 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002872 CallRuntime(Runtime::kAbort);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002873 }
2874 // will not return here
2875}
2876
2877
2878void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
2879 if (context_chain_length > 0) {
2880 // Move up the chain of contexts to the context containing the slot.
2881 LoadP(dst, MemOperand(cp, Context::SlotOffset(Context::PREVIOUS_INDEX)));
2882 for (int i = 1; i < context_chain_length; i++) {
2883 LoadP(dst, MemOperand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX)));
2884 }
2885 } else {
2886 // Slot is in the current function context. Move it into the
2887 // destination register in case we store into it (the write barrier
2888 // cannot be allowed to destroy the context in esi).
2889 mr(dst, cp);
2890 }
2891}
2892
2893
2894void MacroAssembler::LoadTransitionedArrayMapConditional(
2895 ElementsKind expected_kind, ElementsKind transitioned_kind,
2896 Register map_in_out, Register scratch, Label* no_map_match) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002897 DCHECK(IsFastElementsKind(expected_kind));
2898 DCHECK(IsFastElementsKind(transitioned_kind));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002899
2900 // Check that the function's map is the same as the expected cached map.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002901 LoadP(scratch, NativeContextMemOperand());
2902 LoadP(ip, ContextMemOperand(scratch, Context::ArrayMapIndex(expected_kind)));
2903 cmp(map_in_out, ip);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002904 bne(no_map_match);
2905
2906 // Use the transitioned cached map.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002907 LoadP(map_in_out,
2908 ContextMemOperand(scratch, Context::ArrayMapIndex(transitioned_kind)));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002909}
2910
2911
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002912void MacroAssembler::LoadNativeContextSlot(int index, Register dst) {
2913 LoadP(dst, NativeContextMemOperand());
2914 LoadP(dst, ContextMemOperand(dst, index));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002915}
2916
2917
2918void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
2919 Register map,
2920 Register scratch) {
2921 // Load the initial map. The global functions all have initial maps.
2922 LoadP(map,
2923 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2924 if (emit_debug_code()) {
2925 Label ok, fail;
2926 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK);
2927 b(&ok);
2928 bind(&fail);
2929 Abort(kGlobalFunctionsMustHaveInitialMap);
2930 bind(&ok);
2931 }
2932}
2933
2934
2935void MacroAssembler::JumpIfNotPowerOfTwoOrZero(
2936 Register reg, Register scratch, Label* not_power_of_two_or_zero) {
2937 subi(scratch, reg, Operand(1));
2938 cmpi(scratch, Operand::Zero());
2939 blt(not_power_of_two_or_zero);
2940 and_(r0, scratch, reg, SetRC);
2941 bne(not_power_of_two_or_zero, cr0);
2942}
2943
2944
2945void MacroAssembler::JumpIfNotPowerOfTwoOrZeroAndNeg(Register reg,
2946 Register scratch,
2947 Label* zero_and_neg,
2948 Label* not_power_of_two) {
2949 subi(scratch, reg, Operand(1));
2950 cmpi(scratch, Operand::Zero());
2951 blt(zero_and_neg);
2952 and_(r0, scratch, reg, SetRC);
2953 bne(not_power_of_two, cr0);
2954}
2955
2956#if !V8_TARGET_ARCH_PPC64
2957void MacroAssembler::SmiTagCheckOverflow(Register reg, Register overflow) {
2958 DCHECK(!reg.is(overflow));
2959 mr(overflow, reg); // Save original value.
2960 SmiTag(reg);
2961 xor_(overflow, overflow, reg, SetRC); // Overflow if (value ^ 2 * value) < 0.
2962}
2963
2964
2965void MacroAssembler::SmiTagCheckOverflow(Register dst, Register src,
2966 Register overflow) {
2967 if (dst.is(src)) {
2968 // Fall back to slower case.
2969 SmiTagCheckOverflow(dst, overflow);
2970 } else {
2971 DCHECK(!dst.is(src));
2972 DCHECK(!dst.is(overflow));
2973 DCHECK(!src.is(overflow));
2974 SmiTag(dst, src);
2975 xor_(overflow, dst, src, SetRC); // Overflow if (value ^ 2 * value) < 0.
2976 }
2977}
2978#endif
2979
2980void MacroAssembler::JumpIfNotBothSmi(Register reg1, Register reg2,
2981 Label* on_not_both_smi) {
2982 STATIC_ASSERT(kSmiTag == 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002983 orx(r0, reg1, reg2, LeaveRC);
2984 JumpIfNotSmi(r0, on_not_both_smi);
2985}
2986
2987
2988void MacroAssembler::UntagAndJumpIfSmi(Register dst, Register src,
2989 Label* smi_case) {
2990 STATIC_ASSERT(kSmiTag == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002991 TestBitRange(src, kSmiTagSize - 1, 0, r0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002992 SmiUntag(dst, src);
2993 beq(smi_case, cr0);
2994}
2995
2996
2997void MacroAssembler::UntagAndJumpIfNotSmi(Register dst, Register src,
2998 Label* non_smi_case) {
2999 STATIC_ASSERT(kSmiTag == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003000 TestBitRange(src, kSmiTagSize - 1, 0, r0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003001 SmiUntag(dst, src);
3002 bne(non_smi_case, cr0);
3003}
3004
3005
3006void MacroAssembler::JumpIfEitherSmi(Register reg1, Register reg2,
3007 Label* on_either_smi) {
3008 STATIC_ASSERT(kSmiTag == 0);
3009 JumpIfSmi(reg1, on_either_smi);
3010 JumpIfSmi(reg2, on_either_smi);
3011}
3012
Ben Murdochda12d292016-06-02 14:46:10 +01003013void MacroAssembler::AssertNotNumber(Register object) {
3014 if (emit_debug_code()) {
3015 STATIC_ASSERT(kSmiTag == 0);
3016 TestIfSmi(object, r0);
3017 Check(ne, kOperandIsANumber, cr0);
3018 push(object);
3019 CompareObjectType(object, object, object, HEAP_NUMBER_TYPE);
3020 pop(object);
3021 Check(ne, kOperandIsANumber);
3022 }
3023}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003024
3025void MacroAssembler::AssertNotSmi(Register object) {
3026 if (emit_debug_code()) {
3027 STATIC_ASSERT(kSmiTag == 0);
3028 TestIfSmi(object, r0);
3029 Check(ne, kOperandIsASmi, cr0);
3030 }
3031}
3032
3033
3034void MacroAssembler::AssertSmi(Register object) {
3035 if (emit_debug_code()) {
3036 STATIC_ASSERT(kSmiTag == 0);
3037 TestIfSmi(object, r0);
3038 Check(eq, kOperandIsNotSmi, cr0);
3039 }
3040}
3041
3042
3043void MacroAssembler::AssertString(Register object) {
3044 if (emit_debug_code()) {
3045 STATIC_ASSERT(kSmiTag == 0);
3046 TestIfSmi(object, r0);
3047 Check(ne, kOperandIsASmiAndNotAString, cr0);
3048 push(object);
3049 LoadP(object, FieldMemOperand(object, HeapObject::kMapOffset));
3050 CompareInstanceType(object, object, FIRST_NONSTRING_TYPE);
3051 pop(object);
3052 Check(lt, kOperandIsNotAString);
3053 }
3054}
3055
3056
3057void MacroAssembler::AssertName(Register object) {
3058 if (emit_debug_code()) {
3059 STATIC_ASSERT(kSmiTag == 0);
3060 TestIfSmi(object, r0);
3061 Check(ne, kOperandIsASmiAndNotAName, cr0);
3062 push(object);
3063 LoadP(object, FieldMemOperand(object, HeapObject::kMapOffset));
3064 CompareInstanceType(object, object, LAST_NAME_TYPE);
3065 pop(object);
3066 Check(le, kOperandIsNotAName);
3067 }
3068}
3069
3070
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003071void MacroAssembler::AssertFunction(Register object) {
3072 if (emit_debug_code()) {
3073 STATIC_ASSERT(kSmiTag == 0);
3074 TestIfSmi(object, r0);
3075 Check(ne, kOperandIsASmiAndNotAFunction, cr0);
3076 push(object);
3077 CompareObjectType(object, object, object, JS_FUNCTION_TYPE);
3078 pop(object);
3079 Check(eq, kOperandIsNotAFunction);
3080 }
3081}
3082
3083
3084void MacroAssembler::AssertBoundFunction(Register object) {
3085 if (emit_debug_code()) {
3086 STATIC_ASSERT(kSmiTag == 0);
3087 TestIfSmi(object, r0);
3088 Check(ne, kOperandIsASmiAndNotABoundFunction, cr0);
3089 push(object);
3090 CompareObjectType(object, object, object, JS_BOUND_FUNCTION_TYPE);
3091 pop(object);
3092 Check(eq, kOperandIsNotABoundFunction);
3093 }
3094}
3095
Ben Murdochc5610432016-08-08 18:44:38 +01003096void MacroAssembler::AssertGeneratorObject(Register object) {
3097 if (emit_debug_code()) {
3098 STATIC_ASSERT(kSmiTag == 0);
3099 TestIfSmi(object, r0);
3100 Check(ne, kOperandIsASmiAndNotAGeneratorObject, cr0);
3101 push(object);
3102 CompareObjectType(object, object, object, JS_GENERATOR_OBJECT_TYPE);
3103 pop(object);
3104 Check(eq, kOperandIsNotAGeneratorObject);
3105 }
3106}
3107
Ben Murdoch097c5b22016-05-18 11:27:45 +01003108void MacroAssembler::AssertReceiver(Register object) {
3109 if (emit_debug_code()) {
3110 STATIC_ASSERT(kSmiTag == 0);
3111 TestIfSmi(object, r0);
3112 Check(ne, kOperandIsASmiAndNotAReceiver, cr0);
3113 push(object);
3114 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
3115 CompareObjectType(object, object, object, FIRST_JS_RECEIVER_TYPE);
3116 pop(object);
3117 Check(ge, kOperandIsNotAReceiver);
3118 }
3119}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003120
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003121void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
3122 Register scratch) {
3123 if (emit_debug_code()) {
3124 Label done_checking;
3125 AssertNotSmi(object);
3126 CompareRoot(object, Heap::kUndefinedValueRootIndex);
3127 beq(&done_checking);
3128 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
3129 CompareRoot(scratch, Heap::kAllocationSiteMapRootIndex);
3130 Assert(eq, kExpectedUndefinedOrCell);
3131 bind(&done_checking);
3132 }
3133}
3134
3135
3136void MacroAssembler::AssertIsRoot(Register reg, Heap::RootListIndex index) {
3137 if (emit_debug_code()) {
3138 CompareRoot(reg, index);
3139 Check(eq, kHeapNumberMapRegisterClobbered);
3140 }
3141}
3142
3143
3144void MacroAssembler::JumpIfNotHeapNumber(Register object,
3145 Register heap_number_map,
3146 Register scratch,
3147 Label* on_not_heap_number) {
3148 LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
3149 AssertIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
3150 cmp(scratch, heap_number_map);
3151 bne(on_not_heap_number);
3152}
3153
3154
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003155void MacroAssembler::JumpIfNonSmisNotBothSequentialOneByteStrings(
3156 Register first, Register second, Register scratch1, Register scratch2,
3157 Label* failure) {
3158 // Test that both first and second are sequential one-byte strings.
3159 // Assume that they are non-smis.
3160 LoadP(scratch1, FieldMemOperand(first, HeapObject::kMapOffset));
3161 LoadP(scratch2, FieldMemOperand(second, HeapObject::kMapOffset));
3162 lbz(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
3163 lbz(scratch2, FieldMemOperand(scratch2, Map::kInstanceTypeOffset));
3164
3165 JumpIfBothInstanceTypesAreNotSequentialOneByte(scratch1, scratch2, scratch1,
3166 scratch2, failure);
3167}
3168
3169void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register first,
3170 Register second,
3171 Register scratch1,
3172 Register scratch2,
3173 Label* failure) {
3174 // Check that neither is a smi.
3175 and_(scratch1, first, second);
3176 JumpIfSmi(scratch1, failure);
3177 JumpIfNonSmisNotBothSequentialOneByteStrings(first, second, scratch1,
3178 scratch2, failure);
3179}
3180
3181
3182void MacroAssembler::JumpIfNotUniqueNameInstanceType(Register reg,
3183 Label* not_unique_name) {
3184 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
3185 Label succeed;
3186 andi(r0, reg, Operand(kIsNotStringMask | kIsNotInternalizedMask));
3187 beq(&succeed, cr0);
3188 cmpi(reg, Operand(SYMBOL_TYPE));
3189 bne(not_unique_name);
3190
3191 bind(&succeed);
3192}
3193
3194
3195// Allocates a heap number or jumps to the need_gc label if the young space
3196// is full and a scavenge is needed.
3197void MacroAssembler::AllocateHeapNumber(Register result, Register scratch1,
3198 Register scratch2,
3199 Register heap_number_map,
3200 Label* gc_required,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003201 MutableMode mode) {
3202 // Allocate an object in the heap for the heap number and tag it as a heap
3203 // object.
3204 Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required,
Ben Murdochc5610432016-08-08 18:44:38 +01003205 NO_ALLOCATION_FLAGS);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003206
3207 Heap::RootListIndex map_index = mode == MUTABLE
3208 ? Heap::kMutableHeapNumberMapRootIndex
3209 : Heap::kHeapNumberMapRootIndex;
3210 AssertIsRoot(heap_number_map, map_index);
3211
3212 // Store heap number map in the allocated object.
Ben Murdochc5610432016-08-08 18:44:38 +01003213 StoreP(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset),
3214 r0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003215}
3216
3217
3218void MacroAssembler::AllocateHeapNumberWithValue(
3219 Register result, DoubleRegister value, Register scratch1, Register scratch2,
3220 Register heap_number_map, Label* gc_required) {
3221 AllocateHeapNumber(result, scratch1, scratch2, heap_number_map, gc_required);
3222 stfd(value, FieldMemOperand(result, HeapNumber::kValueOffset));
3223}
3224
3225
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003226void MacroAssembler::AllocateJSValue(Register result, Register constructor,
3227 Register value, Register scratch1,
3228 Register scratch2, Label* gc_required) {
3229 DCHECK(!result.is(constructor));
3230 DCHECK(!result.is(scratch1));
3231 DCHECK(!result.is(scratch2));
3232 DCHECK(!result.is(value));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003233
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003234 // Allocate JSValue in new space.
Ben Murdochc5610432016-08-08 18:44:38 +01003235 Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required,
3236 NO_ALLOCATION_FLAGS);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003237
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003238 // Initialize the JSValue.
3239 LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2);
3240 StoreP(scratch1, FieldMemOperand(result, HeapObject::kMapOffset), r0);
3241 LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex);
3242 StoreP(scratch1, FieldMemOperand(result, JSObject::kPropertiesOffset), r0);
3243 StoreP(scratch1, FieldMemOperand(result, JSObject::kElementsOffset), r0);
3244 StoreP(value, FieldMemOperand(result, JSValue::kValueOffset), r0);
3245 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003246}
3247
3248
3249void MacroAssembler::CopyBytes(Register src, Register dst, Register length,
3250 Register scratch) {
3251 Label align_loop, aligned, word_loop, byte_loop, byte_loop_1, done;
3252
3253 DCHECK(!scratch.is(r0));
3254
3255 cmpi(length, Operand::Zero());
3256 beq(&done);
3257
3258 // Check src alignment and length to see whether word_loop is possible
3259 andi(scratch, src, Operand(kPointerSize - 1));
3260 beq(&aligned, cr0);
3261 subfic(scratch, scratch, Operand(kPointerSize * 2));
3262 cmp(length, scratch);
3263 blt(&byte_loop);
3264
3265 // Align src before copying in word size chunks.
3266 subi(scratch, scratch, Operand(kPointerSize));
3267 mtctr(scratch);
3268 bind(&align_loop);
3269 lbz(scratch, MemOperand(src));
3270 addi(src, src, Operand(1));
3271 subi(length, length, Operand(1));
3272 stb(scratch, MemOperand(dst));
3273 addi(dst, dst, Operand(1));
3274 bdnz(&align_loop);
3275
3276 bind(&aligned);
3277
3278 // Copy bytes in word size chunks.
3279 if (emit_debug_code()) {
3280 andi(r0, src, Operand(kPointerSize - 1));
3281 Assert(eq, kExpectingAlignmentForCopyBytes, cr0);
3282 }
3283
3284 ShiftRightImm(scratch, length, Operand(kPointerSizeLog2));
3285 cmpi(scratch, Operand::Zero());
3286 beq(&byte_loop);
3287
3288 mtctr(scratch);
3289 bind(&word_loop);
3290 LoadP(scratch, MemOperand(src));
3291 addi(src, src, Operand(kPointerSize));
3292 subi(length, length, Operand(kPointerSize));
3293 if (CpuFeatures::IsSupported(UNALIGNED_ACCESSES)) {
3294 // currently false for PPC - but possible future opt
3295 StoreP(scratch, MemOperand(dst));
3296 addi(dst, dst, Operand(kPointerSize));
3297 } else {
3298#if V8_TARGET_LITTLE_ENDIAN
3299 stb(scratch, MemOperand(dst, 0));
3300 ShiftRightImm(scratch, scratch, Operand(8));
3301 stb(scratch, MemOperand(dst, 1));
3302 ShiftRightImm(scratch, scratch, Operand(8));
3303 stb(scratch, MemOperand(dst, 2));
3304 ShiftRightImm(scratch, scratch, Operand(8));
3305 stb(scratch, MemOperand(dst, 3));
3306#if V8_TARGET_ARCH_PPC64
3307 ShiftRightImm(scratch, scratch, Operand(8));
3308 stb(scratch, MemOperand(dst, 4));
3309 ShiftRightImm(scratch, scratch, Operand(8));
3310 stb(scratch, MemOperand(dst, 5));
3311 ShiftRightImm(scratch, scratch, Operand(8));
3312 stb(scratch, MemOperand(dst, 6));
3313 ShiftRightImm(scratch, scratch, Operand(8));
3314 stb(scratch, MemOperand(dst, 7));
3315#endif
3316#else
3317#if V8_TARGET_ARCH_PPC64
3318 stb(scratch, MemOperand(dst, 7));
3319 ShiftRightImm(scratch, scratch, Operand(8));
3320 stb(scratch, MemOperand(dst, 6));
3321 ShiftRightImm(scratch, scratch, Operand(8));
3322 stb(scratch, MemOperand(dst, 5));
3323 ShiftRightImm(scratch, scratch, Operand(8));
3324 stb(scratch, MemOperand(dst, 4));
3325 ShiftRightImm(scratch, scratch, Operand(8));
3326#endif
3327 stb(scratch, MemOperand(dst, 3));
3328 ShiftRightImm(scratch, scratch, Operand(8));
3329 stb(scratch, MemOperand(dst, 2));
3330 ShiftRightImm(scratch, scratch, Operand(8));
3331 stb(scratch, MemOperand(dst, 1));
3332 ShiftRightImm(scratch, scratch, Operand(8));
3333 stb(scratch, MemOperand(dst, 0));
3334#endif
3335 addi(dst, dst, Operand(kPointerSize));
3336 }
3337 bdnz(&word_loop);
3338
3339 // Copy the last bytes if any left.
3340 cmpi(length, Operand::Zero());
3341 beq(&done);
3342
3343 bind(&byte_loop);
3344 mtctr(length);
3345 bind(&byte_loop_1);
3346 lbz(scratch, MemOperand(src));
3347 addi(src, src, Operand(1));
3348 stb(scratch, MemOperand(dst));
3349 addi(dst, dst, Operand(1));
3350 bdnz(&byte_loop_1);
3351
3352 bind(&done);
3353}
3354
3355
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003356void MacroAssembler::InitializeNFieldsWithFiller(Register current_address,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003357 Register count,
3358 Register filler) {
3359 Label loop;
3360 mtctr(count);
3361 bind(&loop);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003362 StoreP(filler, MemOperand(current_address));
3363 addi(current_address, current_address, Operand(kPointerSize));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003364 bdnz(&loop);
3365}
3366
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003367void MacroAssembler::InitializeFieldsWithFiller(Register current_address,
3368 Register end_address,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003369 Register filler) {
3370 Label done;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003371 sub(r0, end_address, current_address, LeaveOE, SetRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003372 beq(&done, cr0);
3373 ShiftRightImm(r0, r0, Operand(kPointerSizeLog2));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003374 InitializeNFieldsWithFiller(current_address, r0, filler);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003375 bind(&done);
3376}
3377
3378
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003379void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialOneByte(
3380 Register first, Register second, Register scratch1, Register scratch2,
3381 Label* failure) {
3382 const int kFlatOneByteStringMask =
3383 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
3384 const int kFlatOneByteStringTag =
3385 kStringTag | kOneByteStringTag | kSeqStringTag;
3386 andi(scratch1, first, Operand(kFlatOneByteStringMask));
3387 andi(scratch2, second, Operand(kFlatOneByteStringMask));
3388 cmpi(scratch1, Operand(kFlatOneByteStringTag));
3389 bne(failure);
3390 cmpi(scratch2, Operand(kFlatOneByteStringTag));
3391 bne(failure);
3392}
3393
3394
3395void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte(Register type,
3396 Register scratch,
3397 Label* failure) {
3398 const int kFlatOneByteStringMask =
3399 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
3400 const int kFlatOneByteStringTag =
3401 kStringTag | kOneByteStringTag | kSeqStringTag;
3402 andi(scratch, type, Operand(kFlatOneByteStringMask));
3403 cmpi(scratch, Operand(kFlatOneByteStringTag));
3404 bne(failure);
3405}
3406
3407static const int kRegisterPassedArguments = 8;
3408
3409
3410int MacroAssembler::CalculateStackPassedWords(int num_reg_arguments,
3411 int num_double_arguments) {
3412 int stack_passed_words = 0;
3413 if (num_double_arguments > DoubleRegister::kNumRegisters) {
3414 stack_passed_words +=
3415 2 * (num_double_arguments - DoubleRegister::kNumRegisters);
3416 }
3417 // Up to 8 simple arguments are passed in registers r3..r10.
3418 if (num_reg_arguments > kRegisterPassedArguments) {
3419 stack_passed_words += num_reg_arguments - kRegisterPassedArguments;
3420 }
3421 return stack_passed_words;
3422}
3423
3424
3425void MacroAssembler::EmitSeqStringSetCharCheck(Register string, Register index,
3426 Register value,
3427 uint32_t encoding_mask) {
3428 Label is_object;
3429 TestIfSmi(string, r0);
3430 Check(ne, kNonObject, cr0);
3431
3432 LoadP(ip, FieldMemOperand(string, HeapObject::kMapOffset));
3433 lbz(ip, FieldMemOperand(ip, Map::kInstanceTypeOffset));
3434
3435 andi(ip, ip, Operand(kStringRepresentationMask | kStringEncodingMask));
3436 cmpi(ip, Operand(encoding_mask));
3437 Check(eq, kUnexpectedStringType);
3438
3439// The index is assumed to be untagged coming in, tag it to compare with the
3440// string length without using a temp register, it is restored at the end of
3441// this function.
3442#if !V8_TARGET_ARCH_PPC64
3443 Label index_tag_ok, index_tag_bad;
3444 JumpIfNotSmiCandidate(index, r0, &index_tag_bad);
3445#endif
3446 SmiTag(index, index);
3447#if !V8_TARGET_ARCH_PPC64
3448 b(&index_tag_ok);
3449 bind(&index_tag_bad);
3450 Abort(kIndexIsTooLarge);
3451 bind(&index_tag_ok);
3452#endif
3453
3454 LoadP(ip, FieldMemOperand(string, String::kLengthOffset));
3455 cmp(index, ip);
3456 Check(lt, kIndexIsTooLarge);
3457
3458 DCHECK(Smi::FromInt(0) == 0);
3459 cmpi(index, Operand::Zero());
3460 Check(ge, kIndexIsNegative);
3461
3462 SmiUntag(index, index);
3463}
3464
3465
3466void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
3467 int num_double_arguments,
3468 Register scratch) {
3469 int frame_alignment = ActivationFrameAlignment();
3470 int stack_passed_arguments =
3471 CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
3472 int stack_space = kNumRequiredStackFrameSlots;
3473
3474 if (frame_alignment > kPointerSize) {
3475 // Make stack end at alignment and make room for stack arguments
3476 // -- preserving original value of sp.
3477 mr(scratch, sp);
3478 addi(sp, sp, Operand(-(stack_passed_arguments + 1) * kPointerSize));
3479 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
3480 ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
3481 StoreP(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
3482 } else {
3483 // Make room for stack arguments
3484 stack_space += stack_passed_arguments;
3485 }
3486
3487 // Allocate frame with required slots to make ABI work.
3488 li(r0, Operand::Zero());
3489 StorePU(r0, MemOperand(sp, -stack_space * kPointerSize));
3490}
3491
3492
3493void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
3494 Register scratch) {
3495 PrepareCallCFunction(num_reg_arguments, 0, scratch);
3496}
3497
3498
3499void MacroAssembler::MovToFloatParameter(DoubleRegister src) { Move(d1, src); }
3500
3501
3502void MacroAssembler::MovToFloatResult(DoubleRegister src) { Move(d1, src); }
3503
3504
3505void MacroAssembler::MovToFloatParameters(DoubleRegister src1,
3506 DoubleRegister src2) {
3507 if (src2.is(d1)) {
3508 DCHECK(!src1.is(d2));
3509 Move(d2, src2);
3510 Move(d1, src1);
3511 } else {
3512 Move(d1, src1);
3513 Move(d2, src2);
3514 }
3515}
3516
3517
3518void MacroAssembler::CallCFunction(ExternalReference function,
3519 int num_reg_arguments,
3520 int num_double_arguments) {
3521 mov(ip, Operand(function));
3522 CallCFunctionHelper(ip, num_reg_arguments, num_double_arguments);
3523}
3524
3525
3526void MacroAssembler::CallCFunction(Register function, int num_reg_arguments,
3527 int num_double_arguments) {
3528 CallCFunctionHelper(function, num_reg_arguments, num_double_arguments);
3529}
3530
3531
3532void MacroAssembler::CallCFunction(ExternalReference function,
3533 int num_arguments) {
3534 CallCFunction(function, num_arguments, 0);
3535}
3536
3537
3538void MacroAssembler::CallCFunction(Register function, int num_arguments) {
3539 CallCFunction(function, num_arguments, 0);
3540}
3541
3542
3543void MacroAssembler::CallCFunctionHelper(Register function,
3544 int num_reg_arguments,
3545 int num_double_arguments) {
3546 DCHECK(has_frame());
Ben Murdoch097c5b22016-05-18 11:27:45 +01003547
3548 // Just call directly. The function called cannot cause a GC, or
3549 // allow preemption, so the return address in the link register
3550 // stays correct.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003551 Register dest = function;
Ben Murdoch097c5b22016-05-18 11:27:45 +01003552 if (ABI_USES_FUNCTION_DESCRIPTORS) {
3553 // AIX/PPC64BE Linux uses a function descriptor. When calling C code be
3554 // aware of this descriptor and pick up values from it
3555 LoadP(ToRegister(ABI_TOC_REGISTER), MemOperand(function, kPointerSize));
3556 LoadP(ip, MemOperand(function, 0));
3557 dest = ip;
3558 } else if (ABI_CALL_VIA_IP) {
3559 Move(ip, function);
3560 dest = ip;
3561 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003562
3563 Call(dest);
3564
3565 // Remove frame bought in PrepareCallCFunction
3566 int stack_passed_arguments =
3567 CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
3568 int stack_space = kNumRequiredStackFrameSlots + stack_passed_arguments;
3569 if (ActivationFrameAlignment() > kPointerSize) {
3570 LoadP(sp, MemOperand(sp, stack_space * kPointerSize));
3571 } else {
3572 addi(sp, sp, Operand(stack_space * kPointerSize));
3573 }
3574}
3575
3576
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003577void MacroAssembler::DecodeConstantPoolOffset(Register result,
3578 Register location) {
3579 Label overflow_access, done;
3580 DCHECK(!AreAliased(result, location, r0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003581
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003582 // Determine constant pool access type
3583 // Caller has already placed the instruction word at location in result.
3584 ExtractBitRange(r0, result, 31, 26);
3585 cmpi(r0, Operand(ADDIS >> 26));
3586 beq(&overflow_access);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003587
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003588 // Regular constant pool access
3589 // extract the load offset
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003590 andi(result, result, Operand(kImm16Mask));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003591 b(&done);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003592
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003593 bind(&overflow_access);
3594 // Overflow constant pool access
3595 // shift addis immediate
3596 slwi(r0, result, Operand(16));
3597 // sign-extend and add the load offset
3598 lwz(result, MemOperand(location, kInstrSize));
3599 extsh(result, result);
3600 add(result, r0, result);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003601
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003602 bind(&done);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003603}
3604
3605
3606void MacroAssembler::CheckPageFlag(
3607 Register object,
3608 Register scratch, // scratch may be same register as object
3609 int mask, Condition cc, Label* condition_met) {
3610 DCHECK(cc == ne || cc == eq);
3611 ClearRightImm(scratch, object, Operand(kPageSizeBits));
3612 LoadP(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset));
3613
3614 And(r0, scratch, Operand(mask), SetRC);
3615
3616 if (cc == ne) {
3617 bne(condition_met, cr0);
3618 }
3619 if (cc == eq) {
3620 beq(condition_met, cr0);
3621 }
3622}
3623
3624
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003625void MacroAssembler::JumpIfBlack(Register object, Register scratch0,
3626 Register scratch1, Label* on_black) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003627 HasColor(object, scratch0, scratch1, on_black, 1, 1); // kBlackBitPattern.
3628 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003629}
3630
3631
3632void MacroAssembler::HasColor(Register object, Register bitmap_scratch,
3633 Register mask_scratch, Label* has_color,
3634 int first_bit, int second_bit) {
3635 DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, no_reg));
3636
3637 GetMarkBits(object, bitmap_scratch, mask_scratch);
3638
3639 Label other_color, word_boundary;
3640 lwz(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
3641 // Test the first bit
3642 and_(r0, ip, mask_scratch, SetRC);
3643 b(first_bit == 1 ? eq : ne, &other_color, cr0);
3644 // Shift left 1
3645 // May need to load the next cell
3646 slwi(mask_scratch, mask_scratch, Operand(1), SetRC);
3647 beq(&word_boundary, cr0);
3648 // Test the second bit
3649 and_(r0, ip, mask_scratch, SetRC);
3650 b(second_bit == 1 ? ne : eq, has_color, cr0);
3651 b(&other_color);
3652
3653 bind(&word_boundary);
3654 lwz(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize + kIntSize));
3655 andi(r0, ip, Operand(1));
3656 b(second_bit == 1 ? ne : eq, has_color, cr0);
3657 bind(&other_color);
3658}
3659
3660
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003661void MacroAssembler::GetMarkBits(Register addr_reg, Register bitmap_reg,
3662 Register mask_reg) {
3663 DCHECK(!AreAliased(addr_reg, bitmap_reg, mask_reg, no_reg));
3664 DCHECK((~Page::kPageAlignmentMask & 0xffff) == 0);
3665 lis(r0, Operand((~Page::kPageAlignmentMask >> 16)));
3666 and_(bitmap_reg, addr_reg, r0);
3667 const int kLowBits = kPointerSizeLog2 + Bitmap::kBitsPerCellLog2;
3668 ExtractBitRange(mask_reg, addr_reg, kLowBits - 1, kPointerSizeLog2);
3669 ExtractBitRange(ip, addr_reg, kPageSizeBits - 1, kLowBits);
3670 ShiftLeftImm(ip, ip, Operand(Bitmap::kBytesPerCellLog2));
3671 add(bitmap_reg, bitmap_reg, ip);
3672 li(ip, Operand(1));
3673 slw(mask_reg, ip, mask_reg);
3674}
3675
3676
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003677void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch,
3678 Register mask_scratch, Register load_scratch,
3679 Label* value_is_white) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003680 DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, ip));
3681 GetMarkBits(value, bitmap_scratch, mask_scratch);
3682
3683 // If the value is black or grey we don't need to do anything.
3684 DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003685 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
3686 DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003687 DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
3688
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003689 // Since both black and grey have a 1 in the first position and white does
3690 // not have a 1 there we only need to check one bit.
3691 lwz(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
3692 and_(r0, mask_scratch, load_scratch, SetRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003693 beq(value_is_white, cr0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003694}
3695
3696
3697// Saturate a value into 8-bit unsigned integer
3698// if input_value < 0, output_value is 0
3699// if input_value > 255, output_value is 255
3700// otherwise output_value is the input_value
3701void MacroAssembler::ClampUint8(Register output_reg, Register input_reg) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003702 int satval = (1 << 8) - 1;
3703
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003704 if (CpuFeatures::IsSupported(ISELECT)) {
3705 // set to 0 if negative
3706 cmpi(input_reg, Operand::Zero());
3707 isel(lt, output_reg, r0, input_reg);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003708
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003709 // set to satval if > satval
3710 li(r0, Operand(satval));
3711 cmpi(output_reg, Operand(satval));
3712 isel(lt, output_reg, output_reg, r0);
3713 } else {
3714 Label done, negative_label, overflow_label;
3715 cmpi(input_reg, Operand::Zero());
3716 blt(&negative_label);
3717
3718 cmpi(input_reg, Operand(satval));
3719 bgt(&overflow_label);
3720 if (!output_reg.is(input_reg)) {
3721 mr(output_reg, input_reg);
3722 }
3723 b(&done);
3724
3725 bind(&negative_label);
3726 li(output_reg, Operand::Zero()); // set to 0 if negative
3727 b(&done);
3728
3729 bind(&overflow_label); // set to satval if > satval
3730 li(output_reg, Operand(satval));
3731
3732 bind(&done);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003733 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003734}
3735
3736
3737void MacroAssembler::SetRoundingMode(FPRoundingMode RN) { mtfsfi(7, RN); }
3738
3739
3740void MacroAssembler::ResetRoundingMode() {
3741 mtfsfi(7, kRoundToNearest); // reset (default is kRoundToNearest)
3742}
3743
3744
3745void MacroAssembler::ClampDoubleToUint8(Register result_reg,
3746 DoubleRegister input_reg,
3747 DoubleRegister double_scratch) {
3748 Label above_zero;
3749 Label done;
3750 Label in_bounds;
3751
3752 LoadDoubleLiteral(double_scratch, 0.0, result_reg);
3753 fcmpu(input_reg, double_scratch);
3754 bgt(&above_zero);
3755
3756 // Double value is less than zero, NaN or Inf, return 0.
3757 LoadIntLiteral(result_reg, 0);
3758 b(&done);
3759
3760 // Double value is >= 255, return 255.
3761 bind(&above_zero);
3762 LoadDoubleLiteral(double_scratch, 255.0, result_reg);
3763 fcmpu(input_reg, double_scratch);
3764 ble(&in_bounds);
3765 LoadIntLiteral(result_reg, 255);
3766 b(&done);
3767
3768 // In 0-255 range, round and truncate.
3769 bind(&in_bounds);
3770
3771 // round to nearest (default rounding mode)
3772 fctiw(double_scratch, input_reg);
3773 MovDoubleLowToInt(result_reg, double_scratch);
3774 bind(&done);
3775}
3776
3777
3778void MacroAssembler::LoadInstanceDescriptors(Register map,
3779 Register descriptors) {
3780 LoadP(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset));
3781}
3782
3783
3784void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) {
3785 lwz(dst, FieldMemOperand(map, Map::kBitField3Offset));
3786 DecodeField<Map::NumberOfOwnDescriptorsBits>(dst);
3787}
3788
3789
3790void MacroAssembler::EnumLength(Register dst, Register map) {
3791 STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
3792 lwz(dst, FieldMemOperand(map, Map::kBitField3Offset));
3793 ExtractBitMask(dst, dst, Map::EnumLengthBits::kMask);
3794 SmiTag(dst);
3795}
3796
3797
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003798void MacroAssembler::LoadAccessor(Register dst, Register holder,
3799 int accessor_index,
3800 AccessorComponent accessor) {
3801 LoadP(dst, FieldMemOperand(holder, HeapObject::kMapOffset));
3802 LoadInstanceDescriptors(dst, dst);
3803 LoadP(dst,
3804 FieldMemOperand(dst, DescriptorArray::GetValueOffset(accessor_index)));
3805 const int getterOffset = AccessorPair::kGetterOffset;
3806 const int setterOffset = AccessorPair::kSetterOffset;
3807 int offset = ((accessor == ACCESSOR_GETTER) ? getterOffset : setterOffset);
3808 LoadP(dst, FieldMemOperand(dst, offset));
3809}
3810
3811
Ben Murdoch097c5b22016-05-18 11:27:45 +01003812void MacroAssembler::CheckEnumCache(Label* call_runtime) {
3813 Register null_value = r8;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003814 Register empty_fixed_array_value = r9;
3815 LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
3816 Label next, start;
3817 mr(r5, r3);
3818
3819 // Check if the enum length field is properly initialized, indicating that
3820 // there is an enum cache.
3821 LoadP(r4, FieldMemOperand(r5, HeapObject::kMapOffset));
3822
3823 EnumLength(r6, r4);
3824 CmpSmiLiteral(r6, Smi::FromInt(kInvalidEnumCacheSentinel), r0);
3825 beq(call_runtime);
3826
Ben Murdoch097c5b22016-05-18 11:27:45 +01003827 LoadRoot(null_value, Heap::kNullValueRootIndex);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003828 b(&start);
3829
3830 bind(&next);
3831 LoadP(r4, FieldMemOperand(r5, HeapObject::kMapOffset));
3832
3833 // For all objects but the receiver, check that the cache is empty.
3834 EnumLength(r6, r4);
3835 CmpSmiLiteral(r6, Smi::FromInt(0), r0);
3836 bne(call_runtime);
3837
3838 bind(&start);
3839
3840 // Check that there are no elements. Register r5 contains the current JS
3841 // object we've reached through the prototype chain.
3842 Label no_elements;
3843 LoadP(r5, FieldMemOperand(r5, JSObject::kElementsOffset));
3844 cmp(r5, empty_fixed_array_value);
3845 beq(&no_elements);
3846
3847 // Second chance, the object may be using the empty slow element dictionary.
3848 CompareRoot(r5, Heap::kEmptySlowElementDictionaryRootIndex);
3849 bne(call_runtime);
3850
3851 bind(&no_elements);
3852 LoadP(r5, FieldMemOperand(r4, Map::kPrototypeOffset));
3853 cmp(r5, null_value);
3854 bne(&next);
3855}
3856
3857
3858////////////////////////////////////////////////////////////////////////////////
3859//
3860// New MacroAssembler Interfaces added for PPC
3861//
3862////////////////////////////////////////////////////////////////////////////////
3863void MacroAssembler::LoadIntLiteral(Register dst, int value) {
3864 mov(dst, Operand(value));
3865}
3866
3867
3868void MacroAssembler::LoadSmiLiteral(Register dst, Smi* smi) {
3869 mov(dst, Operand(smi));
3870}
3871
3872
3873void MacroAssembler::LoadDoubleLiteral(DoubleRegister result, double value,
3874 Register scratch) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003875 if (FLAG_enable_embedded_constant_pool && is_constant_pool_available() &&
3876 !(scratch.is(r0) && ConstantPoolAccessIsInOverflow())) {
3877 ConstantPoolEntry::Access access = ConstantPoolAddEntry(value);
3878 if (access == ConstantPoolEntry::OVERFLOWED) {
3879 addis(scratch, kConstantPoolRegister, Operand::Zero());
3880 lfd(result, MemOperand(scratch, 0));
3881 } else {
3882 lfd(result, MemOperand(kConstantPoolRegister, 0));
3883 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003884 return;
3885 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003886
3887 // avoid gcc strict aliasing error using union cast
3888 union {
3889 double dval;
3890#if V8_TARGET_ARCH_PPC64
3891 intptr_t ival;
3892#else
3893 intptr_t ival[2];
3894#endif
3895 } litVal;
3896
3897 litVal.dval = value;
3898
3899#if V8_TARGET_ARCH_PPC64
3900 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
3901 mov(scratch, Operand(litVal.ival));
3902 mtfprd(result, scratch);
3903 return;
3904 }
3905#endif
3906
3907 addi(sp, sp, Operand(-kDoubleSize));
3908#if V8_TARGET_ARCH_PPC64
3909 mov(scratch, Operand(litVal.ival));
3910 std(scratch, MemOperand(sp));
3911#else
3912 LoadIntLiteral(scratch, litVal.ival[0]);
3913 stw(scratch, MemOperand(sp, 0));
3914 LoadIntLiteral(scratch, litVal.ival[1]);
3915 stw(scratch, MemOperand(sp, 4));
3916#endif
3917 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
3918 lfd(result, MemOperand(sp, 0));
3919 addi(sp, sp, Operand(kDoubleSize));
3920}
3921
3922
3923void MacroAssembler::MovIntToDouble(DoubleRegister dst, Register src,
3924 Register scratch) {
3925// sign-extend src to 64-bit
3926#if V8_TARGET_ARCH_PPC64
3927 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
3928 mtfprwa(dst, src);
3929 return;
3930 }
3931#endif
3932
3933 DCHECK(!src.is(scratch));
3934 subi(sp, sp, Operand(kDoubleSize));
3935#if V8_TARGET_ARCH_PPC64
3936 extsw(scratch, src);
3937 std(scratch, MemOperand(sp, 0));
3938#else
3939 srawi(scratch, src, 31);
3940 stw(scratch, MemOperand(sp, Register::kExponentOffset));
3941 stw(src, MemOperand(sp, Register::kMantissaOffset));
3942#endif
3943 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
3944 lfd(dst, MemOperand(sp, 0));
3945 addi(sp, sp, Operand(kDoubleSize));
3946}
3947
3948
3949void MacroAssembler::MovUnsignedIntToDouble(DoubleRegister dst, Register src,
3950 Register scratch) {
3951// zero-extend src to 64-bit
3952#if V8_TARGET_ARCH_PPC64
3953 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
3954 mtfprwz(dst, src);
3955 return;
3956 }
3957#endif
3958
3959 DCHECK(!src.is(scratch));
3960 subi(sp, sp, Operand(kDoubleSize));
3961#if V8_TARGET_ARCH_PPC64
3962 clrldi(scratch, src, Operand(32));
3963 std(scratch, MemOperand(sp, 0));
3964#else
3965 li(scratch, Operand::Zero());
3966 stw(scratch, MemOperand(sp, Register::kExponentOffset));
3967 stw(src, MemOperand(sp, Register::kMantissaOffset));
3968#endif
3969 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
3970 lfd(dst, MemOperand(sp, 0));
3971 addi(sp, sp, Operand(kDoubleSize));
3972}
3973
3974
3975void MacroAssembler::MovInt64ToDouble(DoubleRegister dst,
3976#if !V8_TARGET_ARCH_PPC64
3977 Register src_hi,
3978#endif
3979 Register src) {
3980#if V8_TARGET_ARCH_PPC64
3981 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
3982 mtfprd(dst, src);
3983 return;
3984 }
3985#endif
3986
3987 subi(sp, sp, Operand(kDoubleSize));
3988#if V8_TARGET_ARCH_PPC64
3989 std(src, MemOperand(sp, 0));
3990#else
3991 stw(src_hi, MemOperand(sp, Register::kExponentOffset));
3992 stw(src, MemOperand(sp, Register::kMantissaOffset));
3993#endif
3994 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
3995 lfd(dst, MemOperand(sp, 0));
3996 addi(sp, sp, Operand(kDoubleSize));
3997}
3998
3999
4000#if V8_TARGET_ARCH_PPC64
4001void MacroAssembler::MovInt64ComponentsToDouble(DoubleRegister dst,
4002 Register src_hi,
4003 Register src_lo,
4004 Register scratch) {
4005 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
4006 sldi(scratch, src_hi, Operand(32));
4007 rldimi(scratch, src_lo, 0, 32);
4008 mtfprd(dst, scratch);
4009 return;
4010 }
4011
4012 subi(sp, sp, Operand(kDoubleSize));
4013 stw(src_hi, MemOperand(sp, Register::kExponentOffset));
4014 stw(src_lo, MemOperand(sp, Register::kMantissaOffset));
4015 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
4016 lfd(dst, MemOperand(sp));
4017 addi(sp, sp, Operand(kDoubleSize));
4018}
4019#endif
4020
4021
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004022void MacroAssembler::InsertDoubleLow(DoubleRegister dst, Register src,
4023 Register scratch) {
4024#if V8_TARGET_ARCH_PPC64
4025 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
4026 mffprd(scratch, dst);
4027 rldimi(scratch, src, 0, 32);
4028 mtfprd(dst, scratch);
4029 return;
4030 }
4031#endif
4032
4033 subi(sp, sp, Operand(kDoubleSize));
4034 stfd(dst, MemOperand(sp));
4035 stw(src, MemOperand(sp, Register::kMantissaOffset));
4036 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
4037 lfd(dst, MemOperand(sp));
4038 addi(sp, sp, Operand(kDoubleSize));
4039}
4040
4041
4042void MacroAssembler::InsertDoubleHigh(DoubleRegister dst, Register src,
4043 Register scratch) {
4044#if V8_TARGET_ARCH_PPC64
4045 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
4046 mffprd(scratch, dst);
4047 rldimi(scratch, src, 32, 0);
4048 mtfprd(dst, scratch);
4049 return;
4050 }
4051#endif
4052
4053 subi(sp, sp, Operand(kDoubleSize));
4054 stfd(dst, MemOperand(sp));
4055 stw(src, MemOperand(sp, Register::kExponentOffset));
4056 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
4057 lfd(dst, MemOperand(sp));
4058 addi(sp, sp, Operand(kDoubleSize));
4059}
4060
4061
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004062void MacroAssembler::MovDoubleLowToInt(Register dst, DoubleRegister src) {
4063#if V8_TARGET_ARCH_PPC64
4064 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
4065 mffprwz(dst, src);
4066 return;
4067 }
4068#endif
4069
4070 subi(sp, sp, Operand(kDoubleSize));
4071 stfd(src, MemOperand(sp));
4072 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
4073 lwz(dst, MemOperand(sp, Register::kMantissaOffset));
4074 addi(sp, sp, Operand(kDoubleSize));
4075}
4076
4077
4078void MacroAssembler::MovDoubleHighToInt(Register dst, DoubleRegister src) {
4079#if V8_TARGET_ARCH_PPC64
4080 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
4081 mffprd(dst, src);
4082 srdi(dst, dst, Operand(32));
4083 return;
4084 }
4085#endif
4086
4087 subi(sp, sp, Operand(kDoubleSize));
4088 stfd(src, MemOperand(sp));
4089 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
4090 lwz(dst, MemOperand(sp, Register::kExponentOffset));
4091 addi(sp, sp, Operand(kDoubleSize));
4092}
4093
4094
4095void MacroAssembler::MovDoubleToInt64(
4096#if !V8_TARGET_ARCH_PPC64
4097 Register dst_hi,
4098#endif
4099 Register dst, DoubleRegister src) {
4100#if V8_TARGET_ARCH_PPC64
4101 if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
4102 mffprd(dst, src);
4103 return;
4104 }
4105#endif
4106
4107 subi(sp, sp, Operand(kDoubleSize));
4108 stfd(src, MemOperand(sp));
4109 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
4110#if V8_TARGET_ARCH_PPC64
4111 ld(dst, MemOperand(sp, 0));
4112#else
4113 lwz(dst_hi, MemOperand(sp, Register::kExponentOffset));
4114 lwz(dst, MemOperand(sp, Register::kMantissaOffset));
4115#endif
4116 addi(sp, sp, Operand(kDoubleSize));
4117}
4118
4119
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004120void MacroAssembler::MovIntToFloat(DoubleRegister dst, Register src) {
4121 subi(sp, sp, Operand(kFloatSize));
4122 stw(src, MemOperand(sp, 0));
4123 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
4124 lfs(dst, MemOperand(sp, 0));
4125 addi(sp, sp, Operand(kFloatSize));
4126}
4127
4128
4129void MacroAssembler::MovFloatToInt(Register dst, DoubleRegister src) {
4130 subi(sp, sp, Operand(kFloatSize));
4131 frsp(src, src);
4132 stfs(src, MemOperand(sp, 0));
4133 nop(GROUP_ENDING_NOP); // LHS/RAW optimization
4134 lwz(dst, MemOperand(sp, 0));
4135 addi(sp, sp, Operand(kFloatSize));
4136}
4137
4138
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004139void MacroAssembler::Add(Register dst, Register src, intptr_t value,
4140 Register scratch) {
4141 if (is_int16(value)) {
4142 addi(dst, src, Operand(value));
4143 } else {
4144 mov(scratch, Operand(value));
4145 add(dst, src, scratch);
4146 }
4147}
4148
4149
4150void MacroAssembler::Cmpi(Register src1, const Operand& src2, Register scratch,
4151 CRegister cr) {
4152 intptr_t value = src2.immediate();
4153 if (is_int16(value)) {
4154 cmpi(src1, src2, cr);
4155 } else {
4156 mov(scratch, src2);
4157 cmp(src1, scratch, cr);
4158 }
4159}
4160
4161
4162void MacroAssembler::Cmpli(Register src1, const Operand& src2, Register scratch,
4163 CRegister cr) {
4164 intptr_t value = src2.immediate();
4165 if (is_uint16(value)) {
4166 cmpli(src1, src2, cr);
4167 } else {
4168 mov(scratch, src2);
4169 cmpl(src1, scratch, cr);
4170 }
4171}
4172
4173
4174void MacroAssembler::Cmpwi(Register src1, const Operand& src2, Register scratch,
4175 CRegister cr) {
4176 intptr_t value = src2.immediate();
4177 if (is_int16(value)) {
4178 cmpwi(src1, src2, cr);
4179 } else {
4180 mov(scratch, src2);
4181 cmpw(src1, scratch, cr);
4182 }
4183}
4184
4185
4186void MacroAssembler::Cmplwi(Register src1, const Operand& src2,
4187 Register scratch, CRegister cr) {
4188 intptr_t value = src2.immediate();
4189 if (is_uint16(value)) {
4190 cmplwi(src1, src2, cr);
4191 } else {
4192 mov(scratch, src2);
4193 cmplw(src1, scratch, cr);
4194 }
4195}
4196
4197
4198void MacroAssembler::And(Register ra, Register rs, const Operand& rb,
4199 RCBit rc) {
4200 if (rb.is_reg()) {
4201 and_(ra, rs, rb.rm(), rc);
4202 } else {
4203 if (is_uint16(rb.imm_) && RelocInfo::IsNone(rb.rmode_) && rc == SetRC) {
4204 andi(ra, rs, rb);
4205 } else {
4206 // mov handles the relocation.
4207 DCHECK(!rs.is(r0));
4208 mov(r0, rb);
4209 and_(ra, rs, r0, rc);
4210 }
4211 }
4212}
4213
4214
4215void MacroAssembler::Or(Register ra, Register rs, const Operand& rb, RCBit rc) {
4216 if (rb.is_reg()) {
4217 orx(ra, rs, rb.rm(), rc);
4218 } else {
4219 if (is_uint16(rb.imm_) && RelocInfo::IsNone(rb.rmode_) && rc == LeaveRC) {
4220 ori(ra, rs, rb);
4221 } else {
4222 // mov handles the relocation.
4223 DCHECK(!rs.is(r0));
4224 mov(r0, rb);
4225 orx(ra, rs, r0, rc);
4226 }
4227 }
4228}
4229
4230
4231void MacroAssembler::Xor(Register ra, Register rs, const Operand& rb,
4232 RCBit rc) {
4233 if (rb.is_reg()) {
4234 xor_(ra, rs, rb.rm(), rc);
4235 } else {
4236 if (is_uint16(rb.imm_) && RelocInfo::IsNone(rb.rmode_) && rc == LeaveRC) {
4237 xori(ra, rs, rb);
4238 } else {
4239 // mov handles the relocation.
4240 DCHECK(!rs.is(r0));
4241 mov(r0, rb);
4242 xor_(ra, rs, r0, rc);
4243 }
4244 }
4245}
4246
4247
4248void MacroAssembler::CmpSmiLiteral(Register src1, Smi* smi, Register scratch,
4249 CRegister cr) {
4250#if V8_TARGET_ARCH_PPC64
4251 LoadSmiLiteral(scratch, smi);
4252 cmp(src1, scratch, cr);
4253#else
4254 Cmpi(src1, Operand(smi), scratch, cr);
4255#endif
4256}
4257
4258
4259void MacroAssembler::CmplSmiLiteral(Register src1, Smi* smi, Register scratch,
4260 CRegister cr) {
4261#if V8_TARGET_ARCH_PPC64
4262 LoadSmiLiteral(scratch, smi);
4263 cmpl(src1, scratch, cr);
4264#else
4265 Cmpli(src1, Operand(smi), scratch, cr);
4266#endif
4267}
4268
4269
4270void MacroAssembler::AddSmiLiteral(Register dst, Register src, Smi* smi,
4271 Register scratch) {
4272#if V8_TARGET_ARCH_PPC64
4273 LoadSmiLiteral(scratch, smi);
4274 add(dst, src, scratch);
4275#else
4276 Add(dst, src, reinterpret_cast<intptr_t>(smi), scratch);
4277#endif
4278}
4279
4280
4281void MacroAssembler::SubSmiLiteral(Register dst, Register src, Smi* smi,
4282 Register scratch) {
4283#if V8_TARGET_ARCH_PPC64
4284 LoadSmiLiteral(scratch, smi);
4285 sub(dst, src, scratch);
4286#else
4287 Add(dst, src, -(reinterpret_cast<intptr_t>(smi)), scratch);
4288#endif
4289}
4290
4291
4292void MacroAssembler::AndSmiLiteral(Register dst, Register src, Smi* smi,
4293 Register scratch, RCBit rc) {
4294#if V8_TARGET_ARCH_PPC64
4295 LoadSmiLiteral(scratch, smi);
4296 and_(dst, src, scratch, rc);
4297#else
4298 And(dst, src, Operand(smi), rc);
4299#endif
4300}
4301
4302
4303// Load a "pointer" sized value from the memory location
4304void MacroAssembler::LoadP(Register dst, const MemOperand& mem,
4305 Register scratch) {
4306 int offset = mem.offset();
4307
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004308 if (!is_int16(offset)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004309 /* cannot use d-form */
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004310 DCHECK(!scratch.is(no_reg));
4311 mov(scratch, Operand(offset));
Ben Murdochc5610432016-08-08 18:44:38 +01004312 LoadPX(dst, MemOperand(mem.ra(), scratch));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004313 } else {
4314#if V8_TARGET_ARCH_PPC64
4315 int misaligned = (offset & 3);
4316 if (misaligned) {
4317 // adjust base to conform to offset alignment requirements
4318 // Todo: enhance to use scratch if dst is unsuitable
4319 DCHECK(!dst.is(r0));
4320 addi(dst, mem.ra(), Operand((offset & 3) - 4));
4321 ld(dst, MemOperand(dst, (offset & ~3) + 4));
4322 } else {
4323 ld(dst, mem);
4324 }
4325#else
4326 lwz(dst, mem);
4327#endif
4328 }
4329}
4330
Ben Murdochc5610432016-08-08 18:44:38 +01004331void MacroAssembler::LoadPU(Register dst, const MemOperand& mem,
4332 Register scratch) {
4333 int offset = mem.offset();
4334
4335 if (!is_int16(offset)) {
4336 /* cannot use d-form */
4337 DCHECK(!scratch.is(no_reg));
4338 mov(scratch, Operand(offset));
4339 LoadPUX(dst, MemOperand(mem.ra(), scratch));
4340 } else {
4341#if V8_TARGET_ARCH_PPC64
4342 ldu(dst, mem);
4343#else
4344 lwzu(dst, mem);
4345#endif
4346 }
4347}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004348
4349// Store a "pointer" sized value to the memory location
4350void MacroAssembler::StoreP(Register src, const MemOperand& mem,
4351 Register scratch) {
4352 int offset = mem.offset();
4353
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004354 if (!is_int16(offset)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004355 /* cannot use d-form */
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004356 DCHECK(!scratch.is(no_reg));
4357 mov(scratch, Operand(offset));
Ben Murdochc5610432016-08-08 18:44:38 +01004358 StorePX(src, MemOperand(mem.ra(), scratch));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004359 } else {
4360#if V8_TARGET_ARCH_PPC64
4361 int misaligned = (offset & 3);
4362 if (misaligned) {
4363 // adjust base to conform to offset alignment requirements
4364 // a suitable scratch is required here
4365 DCHECK(!scratch.is(no_reg));
4366 if (scratch.is(r0)) {
4367 LoadIntLiteral(scratch, offset);
4368 stdx(src, MemOperand(mem.ra(), scratch));
4369 } else {
4370 addi(scratch, mem.ra(), Operand((offset & 3) - 4));
4371 std(src, MemOperand(scratch, (offset & ~3) + 4));
4372 }
4373 } else {
4374 std(src, mem);
4375 }
4376#else
4377 stw(src, mem);
4378#endif
4379 }
4380}
4381
Ben Murdochc5610432016-08-08 18:44:38 +01004382void MacroAssembler::StorePU(Register src, const MemOperand& mem,
4383 Register scratch) {
4384 int offset = mem.offset();
4385
4386 if (!is_int16(offset)) {
4387 /* cannot use d-form */
4388 DCHECK(!scratch.is(no_reg));
4389 mov(scratch, Operand(offset));
4390 StorePUX(src, MemOperand(mem.ra(), scratch));
4391 } else {
4392#if V8_TARGET_ARCH_PPC64
4393 stdu(src, mem);
4394#else
4395 stwu(src, mem);
4396#endif
4397 }
4398}
4399
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004400void MacroAssembler::LoadWordArith(Register dst, const MemOperand& mem,
4401 Register scratch) {
4402 int offset = mem.offset();
4403
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004404 if (!is_int16(offset)) {
4405 DCHECK(!scratch.is(no_reg));
4406 mov(scratch, Operand(offset));
4407 lwax(dst, MemOperand(mem.ra(), scratch));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004408 } else {
4409#if V8_TARGET_ARCH_PPC64
4410 int misaligned = (offset & 3);
4411 if (misaligned) {
4412 // adjust base to conform to offset alignment requirements
4413 // Todo: enhance to use scratch if dst is unsuitable
4414 DCHECK(!dst.is(r0));
4415 addi(dst, mem.ra(), Operand((offset & 3) - 4));
4416 lwa(dst, MemOperand(dst, (offset & ~3) + 4));
4417 } else {
4418 lwa(dst, mem);
4419 }
4420#else
4421 lwz(dst, mem);
4422#endif
4423 }
4424}
4425
4426
4427// Variable length depending on whether offset fits into immediate field
4428// MemOperand currently only supports d-form
4429void MacroAssembler::LoadWord(Register dst, const MemOperand& mem,
4430 Register scratch) {
4431 Register base = mem.ra();
4432 int offset = mem.offset();
4433
4434 if (!is_int16(offset)) {
4435 LoadIntLiteral(scratch, offset);
4436 lwzx(dst, MemOperand(base, scratch));
4437 } else {
4438 lwz(dst, mem);
4439 }
4440}
4441
4442
4443// Variable length depending on whether offset fits into immediate field
4444// MemOperand current only supports d-form
4445void MacroAssembler::StoreWord(Register src, const MemOperand& mem,
4446 Register scratch) {
4447 Register base = mem.ra();
4448 int offset = mem.offset();
4449
4450 if (!is_int16(offset)) {
4451 LoadIntLiteral(scratch, offset);
4452 stwx(src, MemOperand(base, scratch));
4453 } else {
4454 stw(src, mem);
4455 }
4456}
4457
4458
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004459void MacroAssembler::LoadHalfWordArith(Register dst, const MemOperand& mem,
4460 Register scratch) {
4461 int offset = mem.offset();
4462
4463 if (!is_int16(offset)) {
4464 DCHECK(!scratch.is(no_reg));
4465 mov(scratch, Operand(offset));
4466 lhax(dst, MemOperand(mem.ra(), scratch));
4467 } else {
4468 lha(dst, mem);
4469 }
4470}
4471
4472
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004473// Variable length depending on whether offset fits into immediate field
4474// MemOperand currently only supports d-form
4475void MacroAssembler::LoadHalfWord(Register dst, const MemOperand& mem,
4476 Register scratch) {
4477 Register base = mem.ra();
4478 int offset = mem.offset();
4479
4480 if (!is_int16(offset)) {
4481 LoadIntLiteral(scratch, offset);
4482 lhzx(dst, MemOperand(base, scratch));
4483 } else {
4484 lhz(dst, mem);
4485 }
4486}
4487
4488
4489// Variable length depending on whether offset fits into immediate field
4490// MemOperand current only supports d-form
4491void MacroAssembler::StoreHalfWord(Register src, const MemOperand& mem,
4492 Register scratch) {
4493 Register base = mem.ra();
4494 int offset = mem.offset();
4495
4496 if (!is_int16(offset)) {
4497 LoadIntLiteral(scratch, offset);
4498 sthx(src, MemOperand(base, scratch));
4499 } else {
4500 sth(src, mem);
4501 }
4502}
4503
4504
4505// Variable length depending on whether offset fits into immediate field
4506// MemOperand currently only supports d-form
4507void MacroAssembler::LoadByte(Register dst, const MemOperand& mem,
4508 Register scratch) {
4509 Register base = mem.ra();
4510 int offset = mem.offset();
4511
4512 if (!is_int16(offset)) {
4513 LoadIntLiteral(scratch, offset);
4514 lbzx(dst, MemOperand(base, scratch));
4515 } else {
4516 lbz(dst, mem);
4517 }
4518}
4519
4520
4521// Variable length depending on whether offset fits into immediate field
4522// MemOperand current only supports d-form
4523void MacroAssembler::StoreByte(Register src, const MemOperand& mem,
4524 Register scratch) {
4525 Register base = mem.ra();
4526 int offset = mem.offset();
4527
4528 if (!is_int16(offset)) {
4529 LoadIntLiteral(scratch, offset);
4530 stbx(src, MemOperand(base, scratch));
4531 } else {
4532 stb(src, mem);
4533 }
4534}
4535
4536
4537void MacroAssembler::LoadRepresentation(Register dst, const MemOperand& mem,
4538 Representation r, Register scratch) {
4539 DCHECK(!r.IsDouble());
4540 if (r.IsInteger8()) {
4541 LoadByte(dst, mem, scratch);
4542 extsb(dst, dst);
4543 } else if (r.IsUInteger8()) {
4544 LoadByte(dst, mem, scratch);
4545 } else if (r.IsInteger16()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004546 LoadHalfWordArith(dst, mem, scratch);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004547 } else if (r.IsUInteger16()) {
4548 LoadHalfWord(dst, mem, scratch);
4549#if V8_TARGET_ARCH_PPC64
4550 } else if (r.IsInteger32()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004551 LoadWordArith(dst, mem, scratch);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004552#endif
4553 } else {
4554 LoadP(dst, mem, scratch);
4555 }
4556}
4557
4558
4559void MacroAssembler::StoreRepresentation(Register src, const MemOperand& mem,
4560 Representation r, Register scratch) {
4561 DCHECK(!r.IsDouble());
4562 if (r.IsInteger8() || r.IsUInteger8()) {
4563 StoreByte(src, mem, scratch);
4564 } else if (r.IsInteger16() || r.IsUInteger16()) {
4565 StoreHalfWord(src, mem, scratch);
4566#if V8_TARGET_ARCH_PPC64
4567 } else if (r.IsInteger32()) {
4568 StoreWord(src, mem, scratch);
4569#endif
4570 } else {
4571 if (r.IsHeapObject()) {
4572 AssertNotSmi(src);
4573 } else if (r.IsSmi()) {
4574 AssertSmi(src);
4575 }
4576 StoreP(src, mem, scratch);
4577 }
4578}
4579
4580
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004581void MacroAssembler::LoadDouble(DoubleRegister dst, const MemOperand& mem,
4582 Register scratch) {
4583 Register base = mem.ra();
4584 int offset = mem.offset();
4585
4586 if (!is_int16(offset)) {
4587 mov(scratch, Operand(offset));
4588 lfdx(dst, MemOperand(base, scratch));
4589 } else {
4590 lfd(dst, mem);
4591 }
4592}
4593
Ben Murdochc5610432016-08-08 18:44:38 +01004594void MacroAssembler::LoadDoubleU(DoubleRegister dst, const MemOperand& mem,
4595 Register scratch) {
4596 Register base = mem.ra();
4597 int offset = mem.offset();
4598
4599 if (!is_int16(offset)) {
4600 mov(scratch, Operand(offset));
4601 lfdux(dst, MemOperand(base, scratch));
4602 } else {
4603 lfdu(dst, mem);
4604 }
4605}
4606
4607void MacroAssembler::LoadSingle(DoubleRegister dst, const MemOperand& mem,
4608 Register scratch) {
4609 Register base = mem.ra();
4610 int offset = mem.offset();
4611
4612 if (!is_int16(offset)) {
4613 mov(scratch, Operand(offset));
4614 lfsx(dst, MemOperand(base, scratch));
4615 } else {
4616 lfs(dst, mem);
4617 }
4618}
4619
4620void MacroAssembler::LoadSingleU(DoubleRegister dst, const MemOperand& mem,
4621 Register scratch) {
4622 Register base = mem.ra();
4623 int offset = mem.offset();
4624
4625 if (!is_int16(offset)) {
4626 mov(scratch, Operand(offset));
4627 lfsux(dst, MemOperand(base, scratch));
4628 } else {
4629 lfsu(dst, mem);
4630 }
4631}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004632
4633void MacroAssembler::StoreDouble(DoubleRegister src, const MemOperand& mem,
4634 Register scratch) {
4635 Register base = mem.ra();
4636 int offset = mem.offset();
4637
4638 if (!is_int16(offset)) {
4639 mov(scratch, Operand(offset));
4640 stfdx(src, MemOperand(base, scratch));
4641 } else {
4642 stfd(src, mem);
4643 }
4644}
4645
Ben Murdochc5610432016-08-08 18:44:38 +01004646void MacroAssembler::StoreDoubleU(DoubleRegister src, const MemOperand& mem,
4647 Register scratch) {
4648 Register base = mem.ra();
4649 int offset = mem.offset();
4650
4651 if (!is_int16(offset)) {
4652 mov(scratch, Operand(offset));
4653 stfdux(src, MemOperand(base, scratch));
4654 } else {
4655 stfdu(src, mem);
4656 }
4657}
4658
4659void MacroAssembler::StoreSingle(DoubleRegister src, const MemOperand& mem,
4660 Register scratch) {
4661 Register base = mem.ra();
4662 int offset = mem.offset();
4663
4664 if (!is_int16(offset)) {
4665 mov(scratch, Operand(offset));
4666 stfsx(src, MemOperand(base, scratch));
4667 } else {
4668 stfs(src, mem);
4669 }
4670}
4671
4672void MacroAssembler::StoreSingleU(DoubleRegister src, const MemOperand& mem,
4673 Register scratch) {
4674 Register base = mem.ra();
4675 int offset = mem.offset();
4676
4677 if (!is_int16(offset)) {
4678 mov(scratch, Operand(offset));
4679 stfsux(src, MemOperand(base, scratch));
4680 } else {
4681 stfsu(src, mem);
4682 }
4683}
4684
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004685void MacroAssembler::TestJSArrayForAllocationMemento(Register receiver_reg,
4686 Register scratch_reg,
Ben Murdochda12d292016-06-02 14:46:10 +01004687 Register scratch2_reg,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004688 Label* no_memento_found) {
Ben Murdochda12d292016-06-02 14:46:10 +01004689 Label map_check;
4690 Label top_check;
Ben Murdochc5610432016-08-08 18:44:38 +01004691 ExternalReference new_space_allocation_top_adr =
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004692 ExternalReference::new_space_allocation_top_address(isolate());
Ben Murdochda12d292016-06-02 14:46:10 +01004693 const int kMementoMapOffset = JSArray::kSize - kHeapObjectTag;
4694 const int kMementoEndOffset = kMementoMapOffset + AllocationMemento::kSize;
4695 Register mask = scratch2_reg;
4696
4697 DCHECK(!AreAliased(receiver_reg, scratch_reg, mask));
4698
4699 // Bail out if the object is not in new space.
4700 JumpIfNotInNewSpace(receiver_reg, scratch_reg, no_memento_found);
4701
4702 DCHECK((~Page::kPageAlignmentMask & 0xffff) == 0);
4703 lis(mask, Operand((~Page::kPageAlignmentMask >> 16)));
4704 addi(scratch_reg, receiver_reg, Operand(kMementoEndOffset));
4705
4706 // If the object is in new space, we need to check whether it is on the same
4707 // page as the current top.
Ben Murdochc5610432016-08-08 18:44:38 +01004708 mov(ip, Operand(new_space_allocation_top_adr));
4709 LoadP(ip, MemOperand(ip));
4710 Xor(r0, scratch_reg, Operand(ip));
Ben Murdochda12d292016-06-02 14:46:10 +01004711 and_(r0, r0, mask, SetRC);
4712 beq(&top_check, cr0);
4713 // The object is on a different page than allocation top. Bail out if the
4714 // object sits on the page boundary as no memento can follow and we cannot
4715 // touch the memory following it.
4716 xor_(r0, scratch_reg, receiver_reg);
4717 and_(r0, r0, mask, SetRC);
4718 bne(no_memento_found, cr0);
4719 // Continue with the actual map check.
4720 b(&map_check);
4721 // If top is on the same page as the current object, we need to check whether
4722 // we are below top.
4723 bind(&top_check);
Ben Murdochc5610432016-08-08 18:44:38 +01004724 cmp(scratch_reg, ip);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004725 bgt(no_memento_found);
Ben Murdochda12d292016-06-02 14:46:10 +01004726 // Memento map check.
4727 bind(&map_check);
4728 LoadP(scratch_reg, MemOperand(receiver_reg, kMementoMapOffset));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004729 Cmpi(scratch_reg, Operand(isolate()->factory()->allocation_memento_map()),
4730 r0);
4731}
4732
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004733Register GetRegisterThatIsNotOneOf(Register reg1, Register reg2, Register reg3,
4734 Register reg4, Register reg5,
4735 Register reg6) {
4736 RegList regs = 0;
4737 if (reg1.is_valid()) regs |= reg1.bit();
4738 if (reg2.is_valid()) regs |= reg2.bit();
4739 if (reg3.is_valid()) regs |= reg3.bit();
4740 if (reg4.is_valid()) regs |= reg4.bit();
4741 if (reg5.is_valid()) regs |= reg5.bit();
4742 if (reg6.is_valid()) regs |= reg6.bit();
4743
Ben Murdoch61f157c2016-09-16 13:49:30 +01004744 const RegisterConfiguration* config = RegisterConfiguration::Crankshaft();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004745 for (int i = 0; i < config->num_allocatable_general_registers(); ++i) {
4746 int code = config->GetAllocatableGeneralCode(i);
4747 Register candidate = Register::from_code(code);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004748 if (regs & candidate.bit()) continue;
4749 return candidate;
4750 }
4751 UNREACHABLE();
4752 return no_reg;
4753}
4754
4755
4756void MacroAssembler::JumpIfDictionaryInPrototypeChain(Register object,
4757 Register scratch0,
4758 Register scratch1,
4759 Label* found) {
4760 DCHECK(!scratch1.is(scratch0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004761 Register current = scratch0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004762 Label loop_again, end;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004763
4764 // scratch contained elements pointer.
4765 mr(current, object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004766 LoadP(current, FieldMemOperand(current, HeapObject::kMapOffset));
4767 LoadP(current, FieldMemOperand(current, Map::kPrototypeOffset));
4768 CompareRoot(current, Heap::kNullValueRootIndex);
4769 beq(&end);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004770
4771 // Loop based on the map going up the prototype chain.
4772 bind(&loop_again);
4773 LoadP(current, FieldMemOperand(current, HeapObject::kMapOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004774
4775 STATIC_ASSERT(JS_PROXY_TYPE < JS_OBJECT_TYPE);
4776 STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE);
4777 lbz(scratch1, FieldMemOperand(current, Map::kInstanceTypeOffset));
4778 cmpi(scratch1, Operand(JS_OBJECT_TYPE));
4779 blt(found);
4780
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004781 lbz(scratch1, FieldMemOperand(current, Map::kBitField2Offset));
4782 DecodeField<Map::ElementsKindBits>(scratch1);
4783 cmpi(scratch1, Operand(DICTIONARY_ELEMENTS));
4784 beq(found);
4785 LoadP(current, FieldMemOperand(current, Map::kPrototypeOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004786 CompareRoot(current, Heap::kNullValueRootIndex);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004787 bne(&loop_again);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004788
4789 bind(&end);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004790}
4791
4792
4793#ifdef DEBUG
4794bool AreAliased(Register reg1, Register reg2, Register reg3, Register reg4,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004795 Register reg5, Register reg6, Register reg7, Register reg8,
4796 Register reg9, Register reg10) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004797 int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() + reg3.is_valid() +
4798 reg4.is_valid() + reg5.is_valid() + reg6.is_valid() +
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004799 reg7.is_valid() + reg8.is_valid() + reg9.is_valid() +
4800 reg10.is_valid();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004801
4802 RegList regs = 0;
4803 if (reg1.is_valid()) regs |= reg1.bit();
4804 if (reg2.is_valid()) regs |= reg2.bit();
4805 if (reg3.is_valid()) regs |= reg3.bit();
4806 if (reg4.is_valid()) regs |= reg4.bit();
4807 if (reg5.is_valid()) regs |= reg5.bit();
4808 if (reg6.is_valid()) regs |= reg6.bit();
4809 if (reg7.is_valid()) regs |= reg7.bit();
4810 if (reg8.is_valid()) regs |= reg8.bit();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004811 if (reg9.is_valid()) regs |= reg9.bit();
4812 if (reg10.is_valid()) regs |= reg10.bit();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004813 int n_of_non_aliasing_regs = NumRegs(regs);
4814
4815 return n_of_valid_regs != n_of_non_aliasing_regs;
4816}
4817#endif
4818
4819
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004820CodePatcher::CodePatcher(Isolate* isolate, byte* address, int instructions,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004821 FlushICache flush_cache)
4822 : address_(address),
4823 size_(instructions * Assembler::kInstrSize),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004824 masm_(isolate, address, size_ + Assembler::kGap, CodeObjectRequired::kNo),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004825 flush_cache_(flush_cache) {
4826 // Create a new macro assembler pointing to the address of the code to patch.
4827 // The size is adjusted with kGap on order for the assembler to generate size
4828 // bytes of instructions without failing with buffer size constraints.
4829 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
4830}
4831
4832
4833CodePatcher::~CodePatcher() {
4834 // Indicate that code has changed.
4835 if (flush_cache_ == FLUSH) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004836 Assembler::FlushICache(masm_.isolate(), address_, size_);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004837 }
4838
4839 // Check that the code was patched as expected.
4840 DCHECK(masm_.pc_ == address_ + size_);
4841 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
4842}
4843
4844
4845void CodePatcher::Emit(Instr instr) { masm()->emit(instr); }
4846
4847
4848void CodePatcher::EmitCondition(Condition cond) {
4849 Instr instr = Assembler::instr_at(masm_.pc_);
4850 switch (cond) {
4851 case eq:
4852 instr = (instr & ~kCondMask) | BT;
4853 break;
4854 case ne:
4855 instr = (instr & ~kCondMask) | BF;
4856 break;
4857 default:
4858 UNIMPLEMENTED();
4859 }
4860 masm_.emit(instr);
4861}
4862
4863
4864void MacroAssembler::TruncatingDiv(Register result, Register dividend,
4865 int32_t divisor) {
4866 DCHECK(!dividend.is(result));
4867 DCHECK(!dividend.is(r0));
4868 DCHECK(!result.is(r0));
4869 base::MagicNumbersForDivision<uint32_t> mag =
4870 base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
4871 mov(r0, Operand(mag.multiplier));
4872 mulhw(result, dividend, r0);
4873 bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
4874 if (divisor > 0 && neg) {
4875 add(result, result, dividend);
4876 }
4877 if (divisor < 0 && !neg && mag.multiplier > 0) {
4878 sub(result, result, dividend);
4879 }
4880 if (mag.shift > 0) srawi(result, result, mag.shift);
4881 ExtractBit(r0, dividend, 31);
4882 add(result, result, r0);
4883}
4884
4885} // namespace internal
4886} // namespace v8
4887
4888#endif // V8_TARGET_ARCH_PPC