1 // 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 #ifndef INCLUDED_FROM_MACRO_ASSEMBLER_H
6 #error This header must be included via macro-assembler.h
7 #endif
8
9 #ifndef V8_CODEGEN_PPC_MACRO_ASSEMBLER_PPC_H_
10 #define V8_CODEGEN_PPC_MACRO_ASSEMBLER_PPC_H_
11
12 #include "src/base/numbers/double.h"
13 #include "src/codegen/bailout-reason.h"
14 #include "src/codegen/ppc/assembler-ppc.h"
15 #include "src/common/globals.h"
16 #include "src/objects/contexts.h"
17
18 namespace v8 {
19 namespace internal {
20
21 enum class StackLimitKind { kInterruptStackLimit, kRealStackLimit };
22
23 // ----------------------------------------------------------------------------
24 // Static helper functions
25
26 // Generate a MemOperand for loading a field from an object.
FieldMemOperand(Register object,int offset)27 inline MemOperand FieldMemOperand(Register object, int offset) {
28 return MemOperand(object, offset - kHeapObjectTag);
29 }
30
31 enum LinkRegisterStatus { kLRHasNotBeenSaved, kLRHasBeenSaved };
32
33 Register GetRegisterThatIsNotOneOf(Register reg1, Register reg2 = no_reg,
34 Register reg3 = no_reg,
35 Register reg4 = no_reg,
36 Register reg5 = no_reg,
37 Register reg6 = no_reg);
38
39 // These exist to provide portability between 32 and 64bit
40 #if V8_TARGET_ARCH_PPC64
41 #define ClearLeftImm clrldi
42 #define ClearRightImm clrrdi
43 #else
44 #define ClearLeftImm clrlwi
45 #define ClearRightImm clrrwi
46 #endif
47
48 class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
49 public:
50 using TurboAssemblerBase::TurboAssemblerBase;
51
52 void CallBuiltin(Builtin builtin, Condition cond);
53 void TailCallBuiltin(Builtin builtin);
54 void Popcnt32(Register dst, Register src);
55 void Popcnt64(Register dst, Register src);
56 // Converts the integer (untagged smi) in |src| to a double, storing
57 // the result to |dst|
58 void ConvertIntToDouble(Register src, DoubleRegister dst);
59
60 // Converts the unsigned integer (untagged smi) in |src| to
61 // a double, storing the result to |dst|
62 void ConvertUnsignedIntToDouble(Register src, DoubleRegister dst);
63
64 // Converts the integer (untagged smi) in |src| to
65 // a float, storing the result in |dst|
66 void ConvertIntToFloat(Register src, DoubleRegister dst);
67
68 // Converts the unsigned integer (untagged smi) in |src| to
69 // a float, storing the result in |dst|
70 void ConvertUnsignedIntToFloat(Register src, DoubleRegister dst);
71
72 #if V8_TARGET_ARCH_PPC64
73 void ConvertInt64ToFloat(Register src, DoubleRegister double_dst);
74 void ConvertInt64ToDouble(Register src, DoubleRegister double_dst);
75 void ConvertUnsignedInt64ToFloat(Register src, DoubleRegister double_dst);
76 void ConvertUnsignedInt64ToDouble(Register src, DoubleRegister double_dst);
77 #endif
78
79 // Converts the double_input to an integer. Note that, upon return,
80 // the contents of double_dst will also hold the fixed point representation.
81 void ConvertDoubleToInt64(const DoubleRegister double_input,
82 #if !V8_TARGET_ARCH_PPC64
83 const Register dst_hi,
84 #endif
85 const Register dst, const DoubleRegister double_dst,
86 FPRoundingMode rounding_mode = kRoundToZero);
87
88 #if V8_TARGET_ARCH_PPC64
89 // Converts the double_input to an unsigned integer. Note that, upon return,
90 // the contents of double_dst will also hold the fixed point representation.
91 void ConvertDoubleToUnsignedInt64(
92 const DoubleRegister double_input, const Register dst,
93 const DoubleRegister double_dst,
94 FPRoundingMode rounding_mode = kRoundToZero);
95 #endif
96
97 // Activation support.
98 void EnterFrame(StackFrame::Type type,
99 bool load_constant_pool_pointer_reg = false);
100
101 // Returns the pc offset at which the frame ends.
102 int LeaveFrame(StackFrame::Type type, int stack_adjustment = 0);
103
AllocateStackSpace(int bytes)104 void AllocateStackSpace(int bytes) {
105 DCHECK_GE(bytes, 0);
106 if (bytes == 0) return;
107 AddS64(sp, sp, Operand(-bytes), r0);
108 }
109
AllocateStackSpace(Register bytes)110 void AllocateStackSpace(Register bytes) { sub(sp, sp, bytes); }
111
112 // Push a fixed frame, consisting of lr, fp, constant pool.
113 void PushCommonFrame(Register marker_reg = no_reg);
114
115 // Generates function and stub prologue code.
116 void StubPrologue(StackFrame::Type type);
117 void Prologue();
118
119 enum ArgumentsCountMode { kCountIncludesReceiver, kCountExcludesReceiver };
120 enum ArgumentsCountType { kCountIsInteger, kCountIsSmi, kCountIsBytes };
121 void DropArguments(Register count, ArgumentsCountType type,
122 ArgumentsCountMode mode);
123 void DropArgumentsAndPushNewReceiver(Register argc, Register receiver,
124 ArgumentsCountType type,
125 ArgumentsCountMode mode);
126
127 // Push a standard frame, consisting of lr, fp, constant pool,
128 // context and JS function
129 void PushStandardFrame(Register function_reg);
130
131 // Restore caller's frame pointer and return address prior to being
132 // overwritten by tail call stack preparation.
133 void RestoreFrameStateForTailCall();
134
135 // Get the actual activation frame alignment for target environment.
136 static int ActivationFrameAlignment();
137
InitializeRootRegister()138 void InitializeRootRegister() {
139 ExternalReference isolate_root = ExternalReference::isolate_root(isolate());
140 mov(kRootRegister, Operand(isolate_root));
141 }
142
143 void LoadDoubleLiteral(DoubleRegister result, base::Double value,
144 Register scratch);
145 void LoadSimd128(Simd128Register dst, const MemOperand& mem);
146
147 // load a literal signed int value <value> to GPR <dst>
148 void LoadIntLiteral(Register dst, int value);
149 // load an SMI value <value> to GPR <dst>
150 void LoadSmiLiteral(Register dst, Smi smi);
151
152 void LoadPC(Register dst);
153 void ComputeCodeStartAddress(Register dst);
154
155 void CmpS64(Register src1, const Operand& src2, Register scratch,
156 CRegister cr = cr7);
157 void CmpS64(Register src1, Register src2, CRegister cr = cr7);
158 void CmpU64(Register src1, const Operand& src2, Register scratch,
159 CRegister cr = cr7);
160 void CmpU64(Register src1, Register src2, CRegister cr = cr7);
161 void CmpS32(Register src1, const Operand& src2, Register scratch,
162 CRegister cr = cr7);
163 void CmpS32(Register src1, Register src2, CRegister cr = cr7);
164 void CmpU32(Register src1, const Operand& src2, Register scratch,
165 CRegister cr = cr7);
166 void CmpU32(Register src1, Register src2, CRegister cr = cr7);
167 void CompareTagged(Register src1, Register src2, CRegister cr = cr7) {
168 if (COMPRESS_POINTERS_BOOL) {
169 CmpS32(src1, src2, cr);
170 } else {
171 CmpS64(src1, src2, cr);
172 }
173 }
174
175 void MinF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
176 DoubleRegister scratch = kScratchDoubleReg);
177 void MaxF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
178 DoubleRegister scratch = kScratchDoubleReg);
179
180 // Set new rounding mode RN to FPSCR
181 void SetRoundingMode(FPRoundingMode RN);
182
183 // reset rounding mode to default (kRoundToNearest)
184 void ResetRoundingMode();
185
186 void AddS64(Register dst, Register src, const Operand& value,
187 Register scratch = r0, OEBit s = LeaveOE, RCBit r = LeaveRC);
188 void AddS64(Register dst, Register src, Register value, OEBit s = LeaveOE,
189 RCBit r = LeaveRC);
190 void SubS64(Register dst, Register src, const Operand& value,
191 Register scratch = r0, OEBit s = LeaveOE, RCBit r = LeaveRC);
192 void SubS64(Register dst, Register src, Register value, OEBit s = LeaveOE,
193 RCBit r = LeaveRC);
194 void AddS32(Register dst, Register src, const Operand& value,
195 Register scratch = r0, RCBit r = LeaveRC);
196 void AddS32(Register dst, Register src, Register value, RCBit r = LeaveRC);
197 void SubS32(Register dst, Register src, const Operand& value,
198 Register scratch = r0, RCBit r = LeaveRC);
199 void SubS32(Register dst, Register src, Register value, RCBit r = LeaveRC);
200 void MulS64(Register dst, Register src, const Operand& value,
201 Register scratch = r0, OEBit s = LeaveOE, RCBit r = LeaveRC);
202 void MulS64(Register dst, Register src, Register value, OEBit s = LeaveOE,
203 RCBit r = LeaveRC);
204 void MulS32(Register dst, Register src, const Operand& value,
205 Register scratch = r0, OEBit s = LeaveOE, RCBit r = LeaveRC);
206 void MulS32(Register dst, Register src, Register value, OEBit s = LeaveOE,
207 RCBit r = LeaveRC);
208 void DivS64(Register dst, Register src, Register value, OEBit s = LeaveOE,
209 RCBit r = LeaveRC);
210 void DivU64(Register dst, Register src, Register value, OEBit s = LeaveOE,
211 RCBit r = LeaveRC);
212 void DivS32(Register dst, Register src, Register value, OEBit s = LeaveOE,
213 RCBit r = LeaveRC);
214 void DivU32(Register dst, Register src, Register value, OEBit s = LeaveOE,
215 RCBit r = LeaveRC);
216 void ModS64(Register dst, Register src, Register value);
217 void ModU64(Register dst, Register src, Register value);
218 void ModS32(Register dst, Register src, Register value);
219 void ModU32(Register dst, Register src, Register value);
220
221 void AndU64(Register dst, Register src, const Operand& value,
222 Register scratch = r0, RCBit r = SetRC);
223 void AndU64(Register dst, Register src, Register value, RCBit r = SetRC);
224 void OrU64(Register dst, Register src, const Operand& value,
225 Register scratch = r0, RCBit r = SetRC);
226 void OrU64(Register dst, Register src, Register value, RCBit r = LeaveRC);
227 void XorU64(Register dst, Register src, const Operand& value,
228 Register scratch = r0, RCBit r = SetRC);
229 void XorU64(Register dst, Register src, Register value, RCBit r = LeaveRC);
230 void AndU32(Register dst, Register src, const Operand& value,
231 Register scratch = r0, RCBit r = SetRC);
232 void AndU32(Register dst, Register src, Register value, RCBit r = SetRC);
233 void OrU32(Register dst, Register src, const Operand& value,
234 Register scratch = r0, RCBit r = SetRC);
235 void OrU32(Register dst, Register src, Register value, RCBit r = LeaveRC);
236 void XorU32(Register dst, Register src, const Operand& value,
237 Register scratch = r0, RCBit r = SetRC);
238 void XorU32(Register dst, Register src, Register value, RCBit r = LeaveRC);
239
240 void ShiftLeftU64(Register dst, Register src, const Operand& value,
241 RCBit r = LeaveRC);
242 void ShiftRightU64(Register dst, Register src, const Operand& value,
243 RCBit r = LeaveRC);
244 void ShiftRightS64(Register dst, Register src, const Operand& value,
245 RCBit r = LeaveRC);
246 void ShiftLeftU32(Register dst, Register src, const Operand& value,
247 RCBit r = LeaveRC);
248 void ShiftRightU32(Register dst, Register src, const Operand& value,
249 RCBit r = LeaveRC);
250 void ShiftRightS32(Register dst, Register src, const Operand& value,
251 RCBit r = LeaveRC);
252 void ShiftLeftU64(Register dst, Register src, Register value,
253 RCBit r = LeaveRC);
254 void ShiftRightU64(Register dst, Register src, Register value,
255 RCBit r = LeaveRC);
256 void ShiftRightS64(Register dst, Register src, Register value,
257 RCBit r = LeaveRC);
258 void ShiftLeftU32(Register dst, Register src, Register value,
259 RCBit r = LeaveRC);
260 void ShiftRightU32(Register dst, Register src, Register value,
261 RCBit r = LeaveRC);
262 void ShiftRightS32(Register dst, Register src, Register value,
263 RCBit r = LeaveRC);
264
265 void CountLeadingZerosU32(Register dst, Register src, RCBit r = LeaveRC);
266 void CountLeadingZerosU64(Register dst, Register src, RCBit r = LeaveRC);
267 void CountTrailingZerosU32(Register dst, Register src, Register scratch1 = ip,
268 Register scratch2 = r0, RCBit r = LeaveRC);
269 void CountTrailingZerosU64(Register dst, Register src, Register scratch1 = ip,
270 Register scratch2 = r0, RCBit r = LeaveRC);
271
272 void ClearByteU64(Register dst, int byte_idx);
273 void ReverseBitsU64(Register dst, Register src, Register scratch1,
274 Register scratch2);
275 void ReverseBitsU32(Register dst, Register src, Register scratch1,
276 Register scratch2);
277 void ReverseBitsInSingleByteU64(Register dst, Register src,
278 Register scratch1, Register scratch2,
279 int byte_idx);
280
281 void AddF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
282 RCBit r = LeaveRC);
283 void SubF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
284 RCBit r = LeaveRC);
285 void MulF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
286 RCBit r = LeaveRC);
287 void DivF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
288 RCBit r = LeaveRC);
289 void AddF32(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
290 RCBit r = LeaveRC);
291 void SubF32(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
292 RCBit r = LeaveRC);
293 void MulF32(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
294 RCBit r = LeaveRC);
295 void DivF32(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
296 RCBit r = LeaveRC);
297 void CopySignF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs,
298 RCBit r = LeaveRC);
299
300 template <class _type>
SignedExtend(Register dst,Register value)301 void SignedExtend(Register dst, Register value) {
302 switch (sizeof(_type)) {
303 case 1:
304 extsb(dst, value);
305 break;
306 case 2:
307 extsh(dst, value);
308 break;
309 case 4:
310 extsw(dst, value);
311 break;
312 case 8:
313 if (dst != value) mr(dst, value);
314 break;
315 default:
316 UNREACHABLE();
317 }
318 }
319
320 template <class _type>
ZeroExtend(Register dst,Register value)321 void ZeroExtend(Register dst, Register value) {
322 switch (sizeof(_type)) {
323 case 1:
324 ZeroExtByte(dst, value);
325 break;
326 case 2:
327 ZeroExtHalfWord(dst, value);
328 break;
329 case 4:
330 ZeroExtWord32(dst, value);
331 break;
332 case 8:
333 if (dst != value) mr(dst, value);
334 break;
335 default:
336 UNREACHABLE();
337 }
338 }
339 template <class _type>
ExtendValue(Register dst,Register value)340 void ExtendValue(Register dst, Register value) {
341 if (std::is_signed<_type>::value) {
342 SignedExtend<_type>(dst, value);
343 } else {
344 ZeroExtend<_type>(dst, value);
345 }
346 }
347
348 template <class _type>
LoadReserve(Register output,MemOperand dst)349 void LoadReserve(Register output, MemOperand dst) {
350 switch (sizeof(_type)) {
351 case 1:
352 lbarx(output, dst);
353 break;
354 case 2:
355 lharx(output, dst);
356 break;
357 case 4:
358 lwarx(output, dst);
359 break;
360 case 8:
361 ldarx(output, dst);
362 break;
363 default:
364 UNREACHABLE();
365 }
366 if (std::is_signed<_type>::value) {
367 SignedExtend<_type>(output, output);
368 }
369 }
370
371 template <class _type>
StoreConditional(Register value,MemOperand dst)372 void StoreConditional(Register value, MemOperand dst) {
373 switch (sizeof(_type)) {
374 case 1:
375 stbcx(value, dst);
376 break;
377 case 2:
378 sthcx(value, dst);
379 break;
380 case 4:
381 stwcx(value, dst);
382 break;
383 case 8:
384 stdcx(value, dst);
385 break;
386 default:
387 UNREACHABLE();
388 }
389 }
390
391 template <class _type>
AtomicCompareExchange(MemOperand dst,Register old_value,Register new_value,Register output,Register scratch)392 void AtomicCompareExchange(MemOperand dst, Register old_value,
393 Register new_value, Register output,
394 Register scratch) {
395 Label loop;
396 Label exit;
397 if (sizeof(_type) != 8) {
398 ExtendValue<_type>(scratch, old_value);
399 old_value = scratch;
400 }
401 lwsync();
402 bind(&loop);
403 LoadReserve<_type>(output, dst);
404 cmp(output, old_value, cr0);
405 bne(&exit, cr0);
406 StoreConditional<_type>(new_value, dst);
407 bne(&loop, cr0);
408 bind(&exit);
409 sync();
410 }
411
412 template <class _type>
AtomicExchange(MemOperand dst,Register new_value,Register output)413 void AtomicExchange(MemOperand dst, Register new_value, Register output) {
414 Label exchange;
415 lwsync();
416 bind(&exchange);
417 LoadReserve<_type>(output, dst);
418 StoreConditional<_type>(new_value, dst);
419 bne(&exchange, cr0);
420 sync();
421 }
422
423 template <class _type, class bin_op>
AtomicOps(MemOperand dst,Register value,Register output,Register result,bin_op op)424 void AtomicOps(MemOperand dst, Register value, Register output,
425 Register result, bin_op op) {
426 Label binop;
427 lwsync();
428 bind(&binop);
429 switch (sizeof(_type)) {
430 case 1:
431 lbarx(output, dst);
432 break;
433 case 2:
434 lharx(output, dst);
435 break;
436 case 4:
437 lwarx(output, dst);
438 break;
439 case 8:
440 ldarx(output, dst);
441 break;
442 default:
443 UNREACHABLE();
444 }
445 op(result, output, value);
446 switch (sizeof(_type)) {
447 case 1:
448 stbcx(result, dst);
449 break;
450 case 2:
451 sthcx(result, dst);
452 break;
453 case 4:
454 stwcx(result, dst);
455 break;
456 case 8:
457 stdcx(result, dst);
458 break;
459 default:
460 UNREACHABLE();
461 }
462 bne(&binop, cr0);
463 sync();
464 }
465
Push(Register src)466 void Push(Register src) { push(src); }
467 // Push a handle.
468 void Push(Handle<HeapObject> handle);
469 void Push(Smi smi);
470
471 // Push two registers. Pushes leftmost register first (to highest address).
Push(Register src1,Register src2)472 void Push(Register src1, Register src2) {
473 StoreU64WithUpdate(src2, MemOperand(sp, -2 * kSystemPointerSize));
474 StoreU64(src1, MemOperand(sp, kSystemPointerSize));
475 }
476
477 // Push three registers. Pushes leftmost register first (to highest address).
Push(Register src1,Register src2,Register src3)478 void Push(Register src1, Register src2, Register src3) {
479 StoreU64WithUpdate(src3, MemOperand(sp, -3 * kSystemPointerSize));
480 StoreU64(src2, MemOperand(sp, kSystemPointerSize));
481 StoreU64(src1, MemOperand(sp, 2 * kSystemPointerSize));
482 }
483
484 // Push four registers. Pushes leftmost register first (to highest address).
Push(Register src1,Register src2,Register src3,Register src4)485 void Push(Register src1, Register src2, Register src3, Register src4) {
486 StoreU64WithUpdate(src4, MemOperand(sp, -4 * kSystemPointerSize));
487 StoreU64(src3, MemOperand(sp, kSystemPointerSize));
488 StoreU64(src2, MemOperand(sp, 2 * kSystemPointerSize));
489 StoreU64(src1, MemOperand(sp, 3 * kSystemPointerSize));
490 }
491
492 // Push five registers. Pushes leftmost register first (to highest address).
Push(Register src1,Register src2,Register src3,Register src4,Register src5)493 void Push(Register src1, Register src2, Register src3, Register src4,
494 Register src5) {
495 StoreU64WithUpdate(src5, MemOperand(sp, -5 * kSystemPointerSize));
496 StoreU64(src4, MemOperand(sp, kSystemPointerSize));
497 StoreU64(src3, MemOperand(sp, 2 * kSystemPointerSize));
498 StoreU64(src2, MemOperand(sp, 3 * kSystemPointerSize));
499 StoreU64(src1, MemOperand(sp, 4 * kSystemPointerSize));
500 }
501
502 enum PushArrayOrder { kNormal, kReverse };
503 void PushArray(Register array, Register size, Register scratch,
504 Register scratch2, PushArrayOrder order = kNormal);
505
Pop(Register dst)506 void Pop(Register dst) { pop(dst); }
507
508 // Pop two registers. Pops rightmost register first (from lower address).
Pop(Register src1,Register src2)509 void Pop(Register src1, Register src2) {
510 LoadU64(src2, MemOperand(sp, 0));
511 LoadU64(src1, MemOperand(sp, kSystemPointerSize));
512 addi(sp, sp, Operand(2 * kSystemPointerSize));
513 }
514
515 // Pop three registers. Pops rightmost register first (from lower address).
Pop(Register src1,Register src2,Register src3)516 void Pop(Register src1, Register src2, Register src3) {
517 LoadU64(src3, MemOperand(sp, 0));
518 LoadU64(src2, MemOperand(sp, kSystemPointerSize));
519 LoadU64(src1, MemOperand(sp, 2 * kSystemPointerSize));
520 addi(sp, sp, Operand(3 * kSystemPointerSize));
521 }
522
523 // Pop four registers. Pops rightmost register first (from lower address).
Pop(Register src1,Register src2,Register src3,Register src4)524 void Pop(Register src1, Register src2, Register src3, Register src4) {
525 LoadU64(src4, MemOperand(sp, 0));
526 LoadU64(src3, MemOperand(sp, kSystemPointerSize));
527 LoadU64(src2, MemOperand(sp, 2 * kSystemPointerSize));
528 LoadU64(src1, MemOperand(sp, 3 * kSystemPointerSize));
529 addi(sp, sp, Operand(4 * kSystemPointerSize));
530 }
531
532 // Pop five registers. Pops rightmost register first (from lower address).
Pop(Register src1,Register src2,Register src3,Register src4,Register src5)533 void Pop(Register src1, Register src2, Register src3, Register src4,
534 Register src5) {
535 LoadU64(src5, MemOperand(sp, 0));
536 LoadU64(src4, MemOperand(sp, kSystemPointerSize));
537 LoadU64(src3, MemOperand(sp, 2 * kSystemPointerSize));
538 LoadU64(src2, MemOperand(sp, 3 * kSystemPointerSize));
539 LoadU64(src1, MemOperand(sp, 4 * kSystemPointerSize));
540 addi(sp, sp, Operand(5 * kSystemPointerSize));
541 }
542
543 void MaybeSaveRegisters(RegList registers);
544 void MaybeRestoreRegisters(RegList registers);
545
546 void CallEphemeronKeyBarrier(Register object, Register slot_address,
547 SaveFPRegsMode fp_mode);
548
549 void CallRecordWriteStubSaveRegisters(
550 Register object, Register slot_address,
551 RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode,
552 StubCallMode mode = StubCallMode::kCallBuiltinPointer);
553 void CallRecordWriteStub(
554 Register object, Register slot_address,
555 RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode,
556 StubCallMode mode = StubCallMode::kCallBuiltinPointer);
557
558 void MultiPush(RegList regs, Register location = sp);
559 void MultiPop(RegList regs, Register location = sp);
560
561 void MultiPushDoubles(DoubleRegList dregs, Register location = sp);
562 void MultiPopDoubles(DoubleRegList dregs, Register location = sp);
563
564 void MultiPushV128(Simd128RegList dregs, Register location = sp);
565 void MultiPopV128(Simd128RegList dregs, Register location = sp);
566
567 void MultiPushF64AndV128(DoubleRegList dregs, Simd128RegList simd_regs,
568 Register location = sp);
569 void MultiPopF64AndV128(DoubleRegList dregs, Simd128RegList simd_regs,
570 Register location = sp);
571
572 // Calculate how much stack space (in bytes) are required to store caller
573 // registers excluding those specified in the arguments.
574 int RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode,
575 Register exclusion1 = no_reg,
576 Register exclusion2 = no_reg,
577 Register exclusion3 = no_reg) const;
578
579 // Push caller saved registers on the stack, and return the number of bytes
580 // stack pointer is adjusted.
581 int PushCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg,
582 Register exclusion2 = no_reg,
583 Register exclusion3 = no_reg);
584 // Restore caller saved registers from the stack, and return the number of
585 // bytes stack pointer is adjusted.
586 int PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg,
587 Register exclusion2 = no_reg,
588 Register exclusion3 = no_reg);
589
590 // Load an object from the root table.
LoadRoot(Register destination,RootIndex index)591 void LoadRoot(Register destination, RootIndex index) final {
592 LoadRoot(destination, index, al);
593 }
594 void LoadRoot(Register destination, RootIndex index, Condition cond);
595
596 void SwapP(Register src, Register dst, Register scratch);
597 void SwapP(Register src, MemOperand dst, Register scratch);
598 void SwapP(MemOperand src, MemOperand dst, Register scratch_0,
599 Register scratch_1);
600 void SwapFloat32(DoubleRegister src, DoubleRegister dst,
601 DoubleRegister scratch);
602 void SwapFloat32(DoubleRegister src, MemOperand dst, DoubleRegister scratch);
603 void SwapFloat32(MemOperand src, MemOperand dst, DoubleRegister scratch_0,
604 DoubleRegister scratch_1);
605 void SwapDouble(DoubleRegister src, DoubleRegister dst,
606 DoubleRegister scratch);
607 void SwapDouble(DoubleRegister src, MemOperand dst, DoubleRegister scratch);
608 void SwapDouble(MemOperand src, MemOperand dst, DoubleRegister scratch_0,
609 DoubleRegister scratch_1);
610 void SwapSimd128(Simd128Register src, Simd128Register dst,
611 Simd128Register scratch);
612 void SwapSimd128(Simd128Register src, MemOperand dst,
613 Simd128Register scratch);
614 void SwapSimd128(MemOperand src, MemOperand dst, Simd128Register scratch);
615
616 void ByteReverseU16(Register dst, Register val, Register scratch);
617 void ByteReverseU32(Register dst, Register val, Register scratch);
618 void ByteReverseU64(Register dst, Register val, Register = r0);
619
620 // Before calling a C-function from generated code, align arguments on stack.
621 // After aligning the frame, non-register arguments must be stored in
622 // sp[0], sp[4], etc., not pushed. The argument count assumes all arguments
623 // are word sized. If double arguments are used, this function assumes that
624 // all double arguments are stored before core registers; otherwise the
625 // correct alignment of the double values is not guaranteed.
626 // Some compilers/platforms require the stack to be aligned when calling
627 // C++ code.
628 // Needs a scratch register to do some arithmetic. This register will be
629 // trashed.
630 void PrepareCallCFunction(int num_reg_arguments, int num_double_registers,
631 Register scratch);
632 void PrepareCallCFunction(int num_reg_arguments, Register scratch);
633
634 // There are two ways of passing double arguments on ARM, depending on
635 // whether soft or hard floating point ABI is used. These functions
636 // abstract parameter passing for the three different ways we call
637 // C functions from generated code.
638 void MovToFloatParameter(DoubleRegister src);
639 void MovToFloatParameters(DoubleRegister src1, DoubleRegister src2);
640 void MovToFloatResult(DoubleRegister src);
641
642 // Calls a C function and cleans up the space for arguments allocated
643 // by PrepareCallCFunction. The called function is not allowed to trigger a
644 // garbage collection, since that might move the code and invalidate the
645 // return address (unless this is somehow accounted for by the called
646 // function).
647 void CallCFunction(ExternalReference function, int num_arguments,
648 bool has_function_descriptor = true);
649 void CallCFunction(Register function, int num_arguments,
650 bool has_function_descriptor = true);
651 void CallCFunction(ExternalReference function, int num_reg_arguments,
652 int num_double_arguments,
653 bool has_function_descriptor = true);
654 void CallCFunction(Register function, int num_reg_arguments,
655 int num_double_arguments,
656 bool has_function_descriptor = true);
657
658 void MovFromFloatParameter(DoubleRegister dst);
659 void MovFromFloatResult(DoubleRegister dst);
660
661 void Trap();
662 void DebugBreak();
663
664 // Calls Abort(msg) if the condition cond is not satisfied.
665 // Use --debug_code to enable.
666 void Assert(Condition cond, AbortReason reason, CRegister cr = cr7);
667
668 // Like Assert(), but always enabled.
669 void Check(Condition cond, AbortReason reason, CRegister cr = cr7);
670
671 // Print a message to stdout and abort execution.
672 void Abort(AbortReason reason);
673
674 #if !V8_TARGET_ARCH_PPC64
675 void ShiftLeftPair(Register dst_low, Register dst_high, Register src_low,
676 Register src_high, Register scratch, Register shift);
677 void ShiftLeftPair(Register dst_low, Register dst_high, Register src_low,
678 Register src_high, uint32_t shift);
679 void ShiftRightPair(Register dst_low, Register dst_high, Register src_low,
680 Register src_high, Register scratch, Register shift);
681 void ShiftRightPair(Register dst_low, Register dst_high, Register src_low,
682 Register src_high, uint32_t shift);
683 void ShiftRightAlgPair(Register dst_low, Register dst_high, Register src_low,
684 Register src_high, Register scratch, Register shift);
685 void ShiftRightAlgPair(Register dst_low, Register dst_high, Register src_low,
686 Register src_high, uint32_t shift);
687 #endif
688
689 void LoadFromConstantsTable(Register destination, int constant_index) final;
690 void LoadRootRegisterOffset(Register destination, intptr_t offset) final;
691 void LoadRootRelative(Register destination, int32_t offset) final;
692
693 // Jump, Call, and Ret pseudo instructions implementing inter-working.
694 void Jump(Register target);
695 void Jump(Address target, RelocInfo::Mode rmode, Condition cond = al,
696 CRegister cr = cr7);
697 void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al,
698 CRegister cr = cr7);
699 void Jump(const ExternalReference& reference);
700 void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al,
701 CRegister cr = cr7);
702 void Call(Register target);
703 void Call(Address target, RelocInfo::Mode rmode, Condition cond = al);
704 void Call(Handle<Code> code, RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
705 Condition cond = al);
706 void Call(Label* target);
707
708 // Load the builtin given by the Smi in |builtin_index| into the same
709 // register.
710 void LoadEntryFromBuiltinIndex(Register builtin_index);
711 void LoadEntryFromBuiltin(Builtin builtin, Register destination);
712 MemOperand EntryFromBuiltinAsOperand(Builtin builtin);
713 void LoadCodeObjectEntry(Register destination, Register code_object);
714 void CallCodeObject(Register code_object);
715 void JumpCodeObject(Register code_object,
716 JumpMode jump_mode = JumpMode::kJump);
717
718 void CallBuiltinByIndex(Register builtin_index);
719 void CallForDeoptimization(Builtin target, int deopt_id, Label* exit,
720 DeoptimizeKind kind, Label* ret,
721 Label* jump_deoptimization_entry_label);
722
723 // Emit code to discard a non-negative number of pointer-sized elements
724 // from the stack, clobbering only the sp register.
725 void Drop(int count);
726 void Drop(Register count, Register scratch = r0);
727
Ret()728 void Ret() { blr(); }
729 void Ret(Condition cond, CRegister cr = cr7) { bclr(cond, cr); }
Ret(int drop)730 void Ret(int drop) {
731 Drop(drop);
732 blr();
733 }
734
735 // If the value is a NaN, canonicalize the value else, do nothing.
736 void CanonicalizeNaN(const DoubleRegister dst, const DoubleRegister src);
CanonicalizeNaN(const DoubleRegister value)737 void CanonicalizeNaN(const DoubleRegister value) {
738 CanonicalizeNaN(value, value);
739 }
740 void CheckPageFlag(Register object, Register scratch, int mask, Condition cc,
741 Label* condition_met);
742
743 // Move values between integer and floating point registers.
744 void MovIntToDouble(DoubleRegister dst, Register src, Register scratch);
745 void MovUnsignedIntToDouble(DoubleRegister dst, Register src,
746 Register scratch);
747 void MovInt64ToDouble(DoubleRegister dst,
748 #if !V8_TARGET_ARCH_PPC64
749 Register src_hi,
750 #endif
751 Register src);
752 #if V8_TARGET_ARCH_PPC64
753 void MovInt64ComponentsToDouble(DoubleRegister dst, Register src_hi,
754 Register src_lo, Register scratch);
755 #endif
756 void InsertDoubleLow(DoubleRegister dst, Register src, Register scratch);
757 void InsertDoubleHigh(DoubleRegister dst, Register src, Register scratch);
758 void MovDoubleLowToInt(Register dst, DoubleRegister src);
759 void MovDoubleHighToInt(Register dst, DoubleRegister src);
760 void MovDoubleToInt64(
761 #if !V8_TARGET_ARCH_PPC64
762 Register dst_hi,
763 #endif
764 Register dst, DoubleRegister src);
765 void MovIntToFloat(DoubleRegister dst, Register src, Register scratch);
766 void MovFloatToInt(Register dst, DoubleRegister src, DoubleRegister scratch);
767 // Register move. May do nothing if the registers are identical.
Move(Register dst,Smi smi)768 void Move(Register dst, Smi smi) { LoadSmiLiteral(dst, smi); }
769 void Move(Register dst, Handle<HeapObject> value,
770 RelocInfo::Mode rmode = RelocInfo::FULL_EMBEDDED_OBJECT);
771 void Move(Register dst, ExternalReference reference);
772 void Move(Register dst, Register src, Condition cond = al);
773 void Move(DoubleRegister dst, DoubleRegister src);
Move(Register dst,const MemOperand & src)774 void Move(Register dst, const MemOperand& src) { LoadU64(dst, src); }
775
776 void SmiUntag(Register dst, const MemOperand& src, RCBit rc = LeaveRC,
777 Register scratch = no_reg);
778 void SmiUntag(Register reg, RCBit rc = LeaveRC) { SmiUntag(reg, reg, rc); }
779
780 void SmiUntag(Register dst, Register src, RCBit rc = LeaveRC) {
781 if (COMPRESS_POINTERS_BOOL) {
782 srawi(dst, src, kSmiShift, rc);
783 } else {
784 ShiftRightS64(dst, src, Operand(kSmiShift), rc);
785 }
786 }
SmiToInt32(Register smi)787 void SmiToInt32(Register smi) {
788 if (FLAG_enable_slow_asserts) {
789 AssertSmi(smi);
790 }
791 DCHECK(SmiValuesAre32Bits() || SmiValuesAre31Bits());
792 SmiUntag(smi);
793 }
794
795 // Shift left by kSmiShift
796 void SmiTag(Register reg, RCBit rc = LeaveRC) { SmiTag(reg, reg, rc); }
797 void SmiTag(Register dst, Register src, RCBit rc = LeaveRC) {
798 ShiftLeftU64(dst, src, Operand(kSmiShift), rc);
799 }
800
801 // Abort execution if argument is a smi, enabled via --debug-code.
802 void AssertNotSmi(Register object);
803 void AssertSmi(Register object);
804
805 void ZeroExtByte(Register dst, Register src);
806 void ZeroExtHalfWord(Register dst, Register src);
807 void ZeroExtWord32(Register dst, Register src);
808
809 // ---------------------------------------------------------------------------
810 // Bit testing/extraction
811 //
812 // Bit numbering is such that the least significant bit is bit 0
813 // (for consistency between 32/64-bit).
814
815 // Extract consecutive bits (defined by rangeStart - rangeEnd) from src
816 // and, if !test, shift them into the least significant bits of dst.
817 inline void ExtractBitRange(Register dst, Register src, int rangeStart,
818 int rangeEnd, RCBit rc = LeaveRC,
819 bool test = false) {
820 DCHECK(rangeStart >= rangeEnd && rangeStart < kBitsPerSystemPointer);
821 int rotate = (rangeEnd == 0) ? 0 : kBitsPerSystemPointer - rangeEnd;
822 int width = rangeStart - rangeEnd + 1;
823 if (rc == SetRC && rangeStart < 16 && (rangeEnd == 0 || test)) {
824 // Prefer faster andi when applicable.
825 andi(dst, src, Operand(((1 << width) - 1) << rangeEnd));
826 } else {
827 #if V8_TARGET_ARCH_PPC64
828 rldicl(dst, src, rotate, kBitsPerSystemPointer - width, rc);
829 #else
830 rlwinm(dst, src, rotate, kBitsPerSystemPointer - width,
831 kBitsPerSystemPointer - 1, rc);
832 #endif
833 }
834 }
835
836 inline void ExtractBit(Register dst, Register src, uint32_t bitNumber,
837 RCBit rc = LeaveRC, bool test = false) {
838 ExtractBitRange(dst, src, bitNumber, bitNumber, rc, test);
839 }
840
841 // Extract consecutive bits (defined by mask) from src and place them
842 // into the least significant bits of dst.
843 inline void ExtractBitMask(Register dst, Register src, uintptr_t mask,
844 RCBit rc = LeaveRC, bool test = false) {
845 int start = kBitsPerSystemPointer - 1;
846 int end;
847 uintptr_t bit = (1L << start);
848
849 while (bit && (mask & bit) == 0) {
850 start--;
851 bit >>= 1;
852 }
853 end = start;
854 bit >>= 1;
855
856 while (bit && (mask & bit)) {
857 end--;
858 bit >>= 1;
859 }
860
861 // 1-bits in mask must be contiguous
862 DCHECK(bit == 0 || (mask & ((bit << 1) - 1)) == 0);
863
864 ExtractBitRange(dst, src, start, end, rc, test);
865 }
866
867 // Test single bit in value.
868 inline void TestBit(Register value, int bitNumber, Register scratch = r0) {
869 ExtractBitRange(scratch, value, bitNumber, bitNumber, SetRC, true);
870 }
871
872 // Test consecutive bit range in value. Range is defined by mask.
873 inline void TestBitMask(Register value, uintptr_t mask,
874 Register scratch = r0) {
875 ExtractBitMask(scratch, value, mask, SetRC, true);
876 }
877 // Test consecutive bit range in value. Range is defined by
878 // rangeStart - rangeEnd.
879 inline void TestBitRange(Register value, int rangeStart, int rangeEnd,
880 Register scratch = r0) {
881 ExtractBitRange(scratch, value, rangeStart, rangeEnd, SetRC, true);
882 }
883
TestIfSmi(Register value,Register scratch)884 inline void TestIfSmi(Register value, Register scratch) {
885 TestBitRange(value, kSmiTagSize - 1, 0, scratch);
886 }
887 // Jump the register contains a smi.
JumpIfSmi(Register value,Label * smi_label)888 inline void JumpIfSmi(Register value, Label* smi_label) {
889 TestIfSmi(value, r0);
890 beq(smi_label, cr0); // branch if SMI
891 }
892 void JumpIfEqual(Register x, int32_t y, Label* dest);
893 void JumpIfLessThan(Register x, int32_t y, Label* dest);
894
895 void LoadMap(Register destination, Register object);
896
897 #if V8_TARGET_ARCH_PPC64
898 inline void TestIfInt32(Register value, Register scratch,
899 CRegister cr = cr7) {
900 // High bits must be identical to fit into an 32-bit integer
901 extsw(scratch, value);
902 CmpS64(scratch, value, cr);
903 }
904 #else
905 inline void TestIfInt32(Register hi_word, Register lo_word, Register scratch,
906 CRegister cr = cr7) {
907 // High bits must be identical to fit into an 32-bit integer
908 srawi(scratch, lo_word, 31);
909 CmpS64(scratch, hi_word, cr);
910 }
911 #endif
912
913 // Overflow handling functions.
914 // Usage: call the appropriate arithmetic function and then call one of the
915 // flow control functions with the corresponding label.
916
917 // Compute dst = left + right, setting condition codes. dst may be same as
918 // either left or right (or a unique register). left and right must not be
919 // the same register.
920 void AddAndCheckForOverflow(Register dst, Register left, Register right,
921 Register overflow_dst, Register scratch = r0);
922 void AddAndCheckForOverflow(Register dst, Register left, intptr_t right,
923 Register overflow_dst, Register scratch = r0);
924
925 // Compute dst = left - right, setting condition codes. dst may be same as
926 // either left or right (or a unique register). left and right must not be
927 // the same register.
928 void SubAndCheckForOverflow(Register dst, Register left, Register right,
929 Register overflow_dst, Register scratch = r0);
930
931 // Performs a truncating conversion of a floating point number as used by
932 // the JS bitwise operations. See ECMA-262 9.5: ToInt32. Goes to 'done' if it
933 // succeeds, otherwise falls through if result is saturated. On return
934 // 'result' either holds answer, or is clobbered on fall through.
935 void TryInlineTruncateDoubleToI(Register result, DoubleRegister input,
936 Label* done);
937 void TruncateDoubleToI(Isolate* isolate, Zone* zone, Register result,
938 DoubleRegister double_input, StubCallMode stub_mode);
939
940 void LoadConstantPoolPointerRegister();
941
942 // Loads the constant pool pointer (kConstantPoolRegister).
943 void LoadConstantPoolPointerRegisterFromCodeTargetAddress(
944 Register code_target_address);
AbortConstantPoolBuilding()945 void AbortConstantPoolBuilding() {
946 #ifdef DEBUG
947 // Avoid DCHECK(!is_linked()) failure in ~Label()
948 bind(ConstantPoolPosition());
949 #endif
950 }
951
952 // Generates an instruction sequence s.t. the return address points to the
953 // instruction following the call.
954 // The return address on the stack is used by frame iteration.
955 void StoreReturnAddressAndCall(Register target);
956
957 // Control-flow integrity:
958
959 // Define a function entrypoint. This doesn't emit any code for this
960 // architecture, as control-flow integrity is not supported for it.
CodeEntry()961 void CodeEntry() {}
962 // Define an exception handler.
ExceptionHandler()963 void ExceptionHandler() {}
964 // Define an exception handler and bind a label.
BindExceptionHandler(Label * label)965 void BindExceptionHandler(Label* label) { bind(label); }
966
967 // ---------------------------------------------------------------------------
968 // Pointer compression Support
969
SmiToPtrArrayOffset(Register dst,Register src)970 void SmiToPtrArrayOffset(Register dst, Register src) {
971 #if defined(V8_COMPRESS_POINTERS) || defined(V8_31BIT_SMIS_ON_64BIT_ARCH)
972 STATIC_ASSERT(kSmiTag == 0 && kSmiShift < kSystemPointerSizeLog2);
973 ShiftLeftU64(dst, src, Operand(kSystemPointerSizeLog2 - kSmiShift));
974 #else
975 STATIC_ASSERT(kSmiTag == 0 && kSmiShift > kSystemPointerSizeLog2);
976 ShiftRightS64(dst, src, Operand(kSmiShift - kSystemPointerSizeLog2));
977 #endif
978 }
979
980 // Loads a field containing a HeapObject and decompresses it if pointer
981 // compression is enabled.
982 void LoadTaggedPointerField(const Register& destination,
983 const MemOperand& field_operand,
984 const Register& scratch = no_reg);
985 void LoadTaggedSignedField(Register destination, MemOperand field_operand,
986 Register scratch);
987
988 // Loads a field containing any tagged value and decompresses it if necessary.
989 void LoadAnyTaggedField(const Register& destination,
990 const MemOperand& field_operand,
991 const Register& scratch = no_reg);
992
993 // Compresses and stores tagged value to given on-heap location.
994 void StoreTaggedField(const Register& value,
995 const MemOperand& dst_field_operand,
996 const Register& scratch = no_reg);
997
998 void DecompressTaggedSigned(Register destination, MemOperand field_operand);
999 void DecompressTaggedSigned(Register destination, Register src);
1000 void DecompressTaggedPointer(Register destination, MemOperand field_operand);
1001 void DecompressTaggedPointer(Register destination, Register source);
1002 void DecompressAnyTagged(Register destination, MemOperand field_operand);
1003 void DecompressAnyTagged(Register destination, Register source);
1004
1005 void LoadF64(DoubleRegister dst, const MemOperand& mem,
1006 Register scratch = no_reg);
1007 void LoadF32(DoubleRegister dst, const MemOperand& mem,
1008 Register scratch = no_reg);
1009
1010 void StoreF32(DoubleRegister src, const MemOperand& mem,
1011 Register scratch = no_reg);
1012 void StoreF64(DoubleRegister src, const MemOperand& mem,
1013 Register scratch = no_reg);
1014
1015 void LoadF32WithUpdate(DoubleRegister dst, const MemOperand& mem,
1016 Register scratch = no_reg);
1017 void LoadF64WithUpdate(DoubleRegister dst, const MemOperand& mem,
1018 Register scratch = no_reg);
1019
1020 void StoreF32WithUpdate(DoubleRegister src, const MemOperand& mem,
1021 Register scratch = no_reg);
1022 void StoreF64WithUpdate(DoubleRegister src, const MemOperand& mem,
1023 Register scratch = no_reg);
1024
1025 void StoreSimd128(Simd128Register src, const MemOperand& mem);
1026
1027 void LoadU64(Register dst, const MemOperand& mem, Register scratch = no_reg);
1028 void LoadU32(Register dst, const MemOperand& mem, Register scratch = no_reg);
1029 void LoadS32(Register dst, const MemOperand& mem, Register scratch = no_reg);
1030 void LoadU16(Register dst, const MemOperand& mem, Register scratch = no_reg);
1031 void LoadS16(Register dst, const MemOperand& mem, Register scratch = no_reg);
1032 void LoadU8(Register dst, const MemOperand& mem, Register scratch = no_reg);
1033 void LoadS8(Register dst, const MemOperand& mem, Register scratch = no_reg);
1034
1035 void StoreU64(Register src, const MemOperand& mem, Register scratch = no_reg);
1036 void StoreU32(Register src, const MemOperand& mem, Register scratch);
1037 void StoreU16(Register src, const MemOperand& mem, Register scratch);
1038 void StoreU8(Register src, const MemOperand& mem, Register scratch);
1039
1040 void LoadU64WithUpdate(Register dst, const MemOperand& mem,
1041 Register scratch = no_reg);
1042 void StoreU64WithUpdate(Register src, const MemOperand& mem,
1043 Register scratch = no_reg);
1044
1045 void LoadU64LE(Register dst, const MemOperand& mem, Register scratch);
1046 void LoadU32LE(Register dst, const MemOperand& mem, Register scratch);
1047 void LoadU16LE(Register dst, const MemOperand& mem, Register scratch);
1048 void StoreU64LE(Register src, const MemOperand& mem, Register scratch);
1049 void StoreU32LE(Register src, const MemOperand& mem, Register scratch);
1050 void StoreU16LE(Register src, const MemOperand& mem, Register scratch);
1051
1052 void LoadS32LE(Register dst, const MemOperand& mem, Register scratch);
1053 void LoadS16LE(Register dst, const MemOperand& mem, Register scratch);
1054
1055 void LoadF64LE(DoubleRegister dst, const MemOperand& mem, Register scratch,
1056 Register scratch2);
1057 void LoadF32LE(DoubleRegister dst, const MemOperand& mem, Register scratch,
1058 Register scratch2);
1059
1060 void StoreF32LE(DoubleRegister src, const MemOperand& mem, Register scratch,
1061 Register scratch2);
1062 void StoreF64LE(DoubleRegister src, const MemOperand& mem, Register scratch,
1063 Register scratch2);
1064
1065 private:
1066 static const int kSmiShift = kSmiTagSize + kSmiShiftSize;
1067
1068 int CalculateStackPassedWords(int num_reg_arguments,
1069 int num_double_arguments);
1070 void CallCFunctionHelper(Register function, int num_reg_arguments,
1071 int num_double_arguments,
1072 bool has_function_descriptor);
1073 };
1074
1075 // MacroAssembler implements a collection of frequently used acros.
1076 class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
1077 public:
1078 using TurboAssembler::TurboAssembler;
1079
1080 // It assumes that the arguments are located below the stack pointer.
1081 // argc is the number of arguments not including the receiver.
1082 // TODO(victorgomes): Remove this function once we stick with the reversed
1083 // arguments order.
LoadReceiver(Register dest,Register argc)1084 void LoadReceiver(Register dest, Register argc) {
1085 LoadU64(dest, MemOperand(sp, 0));
1086 }
1087
StoreReceiver(Register rec,Register argc,Register scratch)1088 void StoreReceiver(Register rec, Register argc, Register scratch) {
1089 StoreU64(rec, MemOperand(sp, 0));
1090 }
1091
1092 // ---------------------------------------------------------------------------
1093 // GC Support
1094
1095 // Notify the garbage collector that we wrote a pointer into an object.
1096 // |object| is the object being stored into, |value| is the object being
1097 // stored. value and scratch registers are clobbered by the operation.
1098 // The offset is the offset from the start of the object, not the offset from
1099 // the tagged HeapObject pointer. For use with FieldMemOperand(reg, off).
1100 void RecordWriteField(
1101 Register object, int offset, Register value, Register slot_address,
1102 LinkRegisterStatus lr_status, SaveFPRegsMode save_fp,
1103 RememberedSetAction remembered_set_action = RememberedSetAction::kEmit,
1104 SmiCheck smi_check = SmiCheck::kInline);
1105
1106 // For a given |object| notify the garbage collector that the slot |address|
1107 // has been written. |value| is the object being stored. The value and
1108 // address registers are clobbered by the operation.
1109 void RecordWrite(
1110 Register object, Register slot_address, Register value,
1111 LinkRegisterStatus lr_status, SaveFPRegsMode save_fp,
1112 RememberedSetAction remembered_set_action = RememberedSetAction::kEmit,
1113 SmiCheck smi_check = SmiCheck::kInline);
1114
1115 // Enter exit frame.
1116 // stack_space - extra stack space, used for parameters before call to C.
1117 // At least one slot (for the return address) should be provided.
1118 void EnterExitFrame(bool save_doubles, int stack_space = 1,
1119 StackFrame::Type frame_type = StackFrame::EXIT);
1120
1121 // Leave the current exit frame. Expects the return value in r0.
1122 // Expect the number of values, pushed prior to the exit frame, to
1123 // remove in a register (or no_reg, if there is nothing to remove).
1124 void LeaveExitFrame(bool save_doubles, Register argument_count,
1125 bool argument_count_is_length = false);
1126
1127 // Load the global proxy from the current context.
LoadGlobalProxy(Register dst)1128 void LoadGlobalProxy(Register dst) {
1129 LoadNativeContextSlot(dst, Context::GLOBAL_PROXY_INDEX);
1130 }
1131
1132 void LoadNativeContextSlot(Register dst, int index);
1133
1134 // ----------------------------------------------------------------
1135 // new PPC macro-assembler interfaces that are slightly higher level
1136 // than assembler-ppc and may generate variable length sequences
1137
1138 // load a literal double value <value> to FPR <result>
1139
1140 void AddSmiLiteral(Register dst, Register src, Smi smi, Register scratch);
1141 void SubSmiLiteral(Register dst, Register src, Smi smi, Register scratch);
1142 void CmpSmiLiteral(Register src1, Smi smi, Register scratch,
1143 CRegister cr = cr7);
1144 void CmplSmiLiteral(Register src1, Smi smi, Register scratch,
1145 CRegister cr = cr7);
1146 void AndSmiLiteral(Register dst, Register src, Smi smi, Register scratch,
1147 RCBit rc = LeaveRC);
1148
1149 // ---------------------------------------------------------------------------
1150 // JavaScript invokes
1151
1152 // Removes current frame and its arguments from the stack preserving
1153 // the arguments and a return address pushed to the stack for the next call.
1154 // Both |callee_args_count| and |caller_args_countg| do not include
1155 // receiver. |callee_args_count| is not modified. |caller_args_count|
1156 // is trashed.
1157
1158 // Invoke the JavaScript function code by either calling or jumping.
1159 void InvokeFunctionCode(Register function, Register new_target,
1160 Register expected_parameter_count,
1161 Register actual_parameter_count, InvokeType type);
1162
1163 // On function call, call into the debugger if necessary.
1164 void CheckDebugHook(Register fun, Register new_target,
1165 Register expected_parameter_count,
1166 Register actual_parameter_count);
1167
1168 // Invoke the JavaScript function in the given register. Changes the
1169 // current context to the context in the function before invoking.
1170 void InvokeFunctionWithNewTarget(Register function, Register new_target,
1171 Register actual_parameter_count,
1172 InvokeType type);
1173 void InvokeFunction(Register function, Register expected_parameter_count,
1174 Register actual_parameter_count, InvokeType type);
1175
1176 // Exception handling
1177
1178 // Push a new stack handler and link into stack handler chain.
1179 void PushStackHandler();
1180
1181 // Unlink the stack handler on top of the stack from the stack handler chain.
1182 // Must preserve the result register.
1183 void PopStackHandler();
1184
1185 // ---------------------------------------------------------------------------
1186 // Support functions.
1187
1188 // Compare object type for heap object. heap_object contains a non-Smi
1189 // whose object type should be compared with the given type. This both
1190 // sets the flags and leaves the object type in the type_reg register.
1191 // It leaves the map in the map register (unless the type_reg and map register
1192 // are the same register). It leaves the heap object in the heap_object
1193 // register unless the heap_object register is the same register as one of the
1194 // other registers.
1195 // Type_reg can be no_reg. In that case ip is used.
1196 void CompareObjectType(Register heap_object, Register map, Register type_reg,
1197 InstanceType type);
1198
1199 // Compare instance type in a map. map contains a valid map object whose
1200 // object type should be compared with the given type. This both
1201 // sets the flags and leaves the object type in the type_reg register.
1202 void CompareInstanceType(Register map, Register type_reg, InstanceType type);
1203
1204 // Compare instance type ranges for a map (lower_limit and higher_limit
1205 // inclusive).
1206 //
1207 // Always use unsigned comparisons: ls for a positive result.
1208 void CompareInstanceTypeRange(Register map, Register type_reg,
1209 InstanceType lower_limit,
1210 InstanceType higher_limit);
1211
1212 // Compare the object in a register to a value from the root list.
1213 // Uses the ip register as scratch.
1214 void CompareRoot(Register obj, RootIndex index);
PushRoot(RootIndex index)1215 void PushRoot(RootIndex index) {
1216 LoadRoot(r0, index);
1217 Push(r0);
1218 }
1219
1220 // Compare the object in a register to a value and jump if they are equal.
JumpIfRoot(Register with,RootIndex index,Label * if_equal)1221 void JumpIfRoot(Register with, RootIndex index, Label* if_equal) {
1222 CompareRoot(with, index);
1223 beq(if_equal);
1224 }
1225
1226 // Compare the object in a register to a value and jump if they are not equal.
JumpIfNotRoot(Register with,RootIndex index,Label * if_not_equal)1227 void JumpIfNotRoot(Register with, RootIndex index, Label* if_not_equal) {
1228 CompareRoot(with, index);
1229 bne(if_not_equal);
1230 }
1231
1232 // Checks if value is in range [lower_limit, higher_limit] using a single
1233 // comparison.
1234 void CompareRange(Register value, unsigned lower_limit,
1235 unsigned higher_limit);
1236 void JumpIfIsInRange(Register value, unsigned lower_limit,
1237 unsigned higher_limit, Label* on_in_range);
1238
1239 // ---------------------------------------------------------------------------
1240 // Runtime calls
1241
1242 static int CallSizeNotPredictableCodeSize(Address target,
1243 RelocInfo::Mode rmode,
1244 Condition cond = al);
1245 void CallJSEntry(Register target);
1246
1247 // Call a runtime routine.
1248 void CallRuntime(const Runtime::Function* f, int num_arguments,
1249 SaveFPRegsMode save_doubles = SaveFPRegsMode::kIgnore);
CallRuntimeSaveDoubles(Runtime::FunctionId fid)1250 void CallRuntimeSaveDoubles(Runtime::FunctionId fid) {
1251 const Runtime::Function* function = Runtime::FunctionForId(fid);
1252 CallRuntime(function, function->nargs, SaveFPRegsMode::kSave);
1253 }
1254
1255 // Convenience function: Same as above, but takes the fid instead.
1256 void CallRuntime(Runtime::FunctionId fid,
1257 SaveFPRegsMode save_doubles = SaveFPRegsMode::kIgnore) {
1258 const Runtime::Function* function = Runtime::FunctionForId(fid);
1259 CallRuntime(function, function->nargs, save_doubles);
1260 }
1261
1262 // Convenience function: Same as above, but takes the fid instead.
1263 void CallRuntime(Runtime::FunctionId fid, int num_arguments,
1264 SaveFPRegsMode save_doubles = SaveFPRegsMode::kIgnore) {
1265 CallRuntime(Runtime::FunctionForId(fid), num_arguments, save_doubles);
1266 }
1267
1268 // Convenience function: tail call a runtime routine (jump).
1269 void TailCallRuntime(Runtime::FunctionId fid);
1270
1271 // Jump to a runtime routine.
1272 void JumpToExternalReference(const ExternalReference& builtin,
1273 bool builtin_exit_frame = false);
1274
1275 // Generates a trampoline to jump to the off-heap instruction stream.
1276 void JumpToOffHeapInstructionStream(Address entry);
1277
1278 // ---------------------------------------------------------------------------
1279 // In-place weak references.
1280 void LoadWeakValue(Register out, Register in, Label* target_if_cleared);
1281
1282 // ---------------------------------------------------------------------------
1283 // StatsCounter support
1284
IncrementCounter(StatsCounter * counter,int value,Register scratch1,Register scratch2)1285 void IncrementCounter(StatsCounter* counter, int value, Register scratch1,
1286 Register scratch2) {
1287 if (!FLAG_native_code_counters) return;
1288 EmitIncrementCounter(counter, value, scratch1, scratch2);
1289 }
1290 void EmitIncrementCounter(StatsCounter* counter, int value, Register scratch1,
1291 Register scratch2);
DecrementCounter(StatsCounter * counter,int value,Register scratch1,Register scratch2)1292 void DecrementCounter(StatsCounter* counter, int value, Register scratch1,
1293 Register scratch2) {
1294 if (!FLAG_native_code_counters) return;
1295 EmitDecrementCounter(counter, value, scratch1, scratch2);
1296 }
1297 void EmitDecrementCounter(StatsCounter* counter, int value, Register scratch1,
1298 Register scratch2);
1299
1300 // ---------------------------------------------------------------------------
1301 // Stack limit utilities
1302
1303 void StackOverflowCheck(Register num_args, Register scratch,
1304 Label* stack_overflow);
1305 void LoadStackLimit(Register destination, StackLimitKind kind);
1306
1307 // ---------------------------------------------------------------------------
1308 // Smi utilities
1309
1310 // Jump if either of the registers contain a non-smi.
JumpIfNotSmi(Register value,Label * not_smi_label)1311 inline void JumpIfNotSmi(Register value, Label* not_smi_label) {
1312 TestIfSmi(value, r0);
1313 bne(not_smi_label, cr0);
1314 }
1315
1316 #if !defined(V8_COMPRESS_POINTERS) && !defined(V8_31BIT_SMIS_ON_64BIT_ARCH)
1317 // Ensure it is permissible to read/write int value directly from
1318 // upper half of the smi.
1319 STATIC_ASSERT(kSmiTag == 0);
1320 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 32);
1321 #endif
1322 #if V8_TARGET_ARCH_PPC64 && V8_TARGET_LITTLE_ENDIAN
1323 #define SmiWordOffset(offset) (offset + kSystemPointerSize / 2)
1324 #else
1325 #define SmiWordOffset(offset) offset
1326 #endif
1327
1328 // Abort execution if argument is not a Constructor, enabled via --debug-code.
1329 void AssertConstructor(Register object);
1330
1331 // Abort execution if argument is not a JSFunction, enabled via --debug-code.
1332 void AssertFunction(Register object);
1333
1334 // Abort execution if argument is not a callable JSFunction, enabled via
1335 // --debug-code.
1336 void AssertCallableFunction(Register object);
1337
1338 // Abort execution if argument is not a JSBoundFunction,
1339 // enabled via --debug-code.
1340 void AssertBoundFunction(Register object);
1341
1342 // Abort execution if argument is not a JSGeneratorObject (or subclass),
1343 // enabled via --debug-code.
1344 void AssertGeneratorObject(Register object);
1345
1346 // Abort execution if argument is not undefined or an AllocationSite, enabled
1347 // via --debug-code.
1348 void AssertUndefinedOrAllocationSite(Register object, Register scratch);
1349
1350 // ---------------------------------------------------------------------------
1351 // Patching helpers.
1352
1353 template <typename Field>
1354 void DecodeField(Register dst, Register src, RCBit rc = LeaveRC) {
1355 ExtractBitRange(dst, src, Field::kShift + Field::kSize - 1, Field::kShift,
1356 rc);
1357 }
1358
1359 template <typename Field>
1360 void DecodeField(Register reg, RCBit rc = LeaveRC) {
1361 DecodeField<Field>(reg, reg, rc);
1362 }
1363
1364 private:
1365 static const int kSmiShift = kSmiTagSize + kSmiShiftSize;
1366
1367 // Helper functions for generating invokes.
1368 void InvokePrologue(Register expected_parameter_count,
1369 Register actual_parameter_count, Label* done,
1370 InvokeType type);
1371
1372 DISALLOW_IMPLICIT_CONSTRUCTORS(MacroAssembler);
1373 };
1374
1375 #define ACCESS_MASM(masm) masm->
1376
1377 } // namespace internal
1378 } // namespace v8
1379
1380 #endif // V8_CODEGEN_PPC_MACRO_ASSEMBLER_PPC_H_
1381