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_S390_MACRO_ASSEMBLER_S390_H_
10 #define V8_CODEGEN_S390_MACRO_ASSEMBLER_S390_H_
11
12 #include "src/codegen/bailout-reason.h"
13 #include "src/codegen/s390/assembler-s390.h"
14 #include "src/common/globals.h"
15 #include "src/objects/contexts.h"
16
17 namespace v8 {
18 namespace internal {
19
20 // ----------------------------------------------------------------------------
21 // Static helper functions
22
23 // Generate a MemOperand for loading a field from an object.
FieldMemOperand(Register object,int offset)24 inline MemOperand FieldMemOperand(Register object, int offset) {
25 return MemOperand(object, offset - kHeapObjectTag);
26 }
27
28 // Generate a MemOperand for loading a field from an object.
FieldMemOperand(Register object,Register index,int offset)29 inline MemOperand FieldMemOperand(Register object, Register index, int offset) {
30 return MemOperand(object, index, offset - kHeapObjectTag);
31 }
32
33 enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET };
34 enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK };
35 enum LinkRegisterStatus { kLRHasNotBeenSaved, kLRHasBeenSaved };
36
37 Register GetRegisterThatIsNotOneOf(Register reg1, Register reg2 = no_reg,
38 Register reg3 = no_reg,
39 Register reg4 = no_reg,
40 Register reg5 = no_reg,
41 Register reg6 = no_reg);
42
43 // These exist to provide portability between 32 and 64bit
44 #if V8_TARGET_ARCH_S390X
45
46 // The length of the arithmetic operation is the length
47 // of the register.
48
49 // Length:
50 // H = halfword
51 // W = word
52
53 // arithmetics and bitwise
54 #define AddMI agsi
55 #define AddRR agr
56 #define SubRR sgr
57 #define AndRR ngr
58 #define OrRR ogr
59 #define XorRR xgr
60 #define LoadComplementRR lcgr
61 #define LoadNegativeRR lngr
62
63 // Distinct Operands
64 #define AddP_RRR agrk
65 #define AddPImm_RRI aghik
66 #define AddLogicalP_RRR algrk
67 #define SubP_RRR sgrk
68 #define SubLogicalP_RRR slgrk
69 #define AndP_RRR ngrk
70 #define OrP_RRR ogrk
71 #define XorP_RRR xgrk
72
73 // Load / Store
74 #define LoadRR lgr
75 #define LoadAndTestRR ltgr
76 #define LoadImmP lghi
77
78 // Compare
79 #define CmpPH cghi
80 #define CmpLogicalPW clgfi
81
82 // Shifts
83 #define ShiftLeftP sllg
84 #define ShiftRightP srlg
85 #define ShiftLeftArithP slag
86 #define ShiftRightArithP srag
87 #else
88
89 // arithmetics and bitwise
90 // Reg2Reg
91 #define AddMI asi
92 #define AddRR ar
93 #define SubRR sr
94 #define AndRR nr
95 #define OrRR or_z
96 #define XorRR xr
97 #define LoadComplementRR lcr
98 #define LoadNegativeRR lnr
99
100 // Distinct Operands
101 #define AddP_RRR ark
102 #define AddPImm_RRI ahik
103 #define AddLogicalP_RRR alrk
104 #define SubP_RRR srk
105 #define SubLogicalP_RRR slrk
106 #define AndP_RRR nrk
107 #define OrP_RRR ork
108 #define XorP_RRR xrk
109
110 // Load / Store
111 #define LoadRR lr
112 #define LoadAndTestRR ltr
113 #define LoadImmP lhi
114
115 // Compare
116 #define CmpPH chi
117 #define CmpLogicalPW clfi
118
119 // Shifts
120 #define ShiftLeftP ShiftLeft
121 #define ShiftRightP ShiftRight
122 #define ShiftLeftArithP ShiftLeftArith
123 #define ShiftRightArithP ShiftRightArith
124
125 #endif
126
127 class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
128 public:
129 using TurboAssemblerBase::TurboAssemblerBase;
130
131 void LoadFromConstantsTable(Register destination,
132 int constant_index) override;
133 void LoadRootRegisterOffset(Register destination, intptr_t offset) override;
134 void LoadRootRelative(Register destination, int32_t offset) override;
135
136 // Jump, Call, and Ret pseudo instructions implementing inter-working.
137 void Jump(Register target, Condition cond = al);
138 void Jump(Address target, RelocInfo::Mode rmode, Condition cond = al);
139 void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
140 void Jump(const ExternalReference& reference) override;
141 // Jump the register contains a smi.
JumpIfSmi(Register value,Label * smi_label)142 inline void JumpIfSmi(Register value, Label* smi_label) {
143 TestIfSmi(value);
144 beq(smi_label /*, cr0*/); // branch if SMI
145 }
146 void JumpIfEqual(Register x, int32_t y, Label* dest);
147 void JumpIfLessThan(Register x, int32_t y, Label* dest);
148
149 void Call(Register target);
150 void Call(Address target, RelocInfo::Mode rmode, Condition cond = al);
151 void Call(Handle<Code> code, RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
152 Condition cond = al);
Ret()153 void Ret() { b(r14); }
Ret(Condition cond)154 void Ret(Condition cond) { b(cond, r14); }
155
156 void CallForDeoptimization(Builtins::Name target, int deopt_id, Label* exit,
157 DeoptimizeKind kind,
158 Label* jump_deoptimization_entry_label);
159
160 // Emit code to discard a non-negative number of pointer-sized elements
161 // from the stack, clobbering only the sp register.
162 void Drop(int count);
163 void Drop(Register count, Register scratch = r0);
164
Ret(int drop)165 void Ret(int drop) {
166 Drop(drop);
167 Ret();
168 }
169
170 void Call(Label* target);
171
172 // Load the builtin given by the Smi in |builtin_index| into the same
173 // register.
174 void LoadEntryFromBuiltinIndex(Register builtin_index);
175 void LoadCodeObjectEntry(Register destination, Register code_object) override;
176 void CallCodeObject(Register code_object) override;
177 void JumpCodeObject(Register code_object) override;
178
179 void CallBuiltinByIndex(Register builtin_index) override;
180
181 // Register move. May do nothing if the registers are identical.
Move(Register dst,Smi smi)182 void Move(Register dst, Smi smi) { LoadSmiLiteral(dst, smi); }
183 void Move(Register dst, Handle<HeapObject> source,
184 RelocInfo::Mode rmode = RelocInfo::FULL_EMBEDDED_OBJECT);
185 void Move(Register dst, ExternalReference reference);
186 void Move(Register dst, Register src, Condition cond = al);
187 void Move(DoubleRegister dst, DoubleRegister src);
188
189 void MoveChar(const MemOperand& opnd1, const MemOperand& opnd2,
190 const Operand& length);
191
192 void CompareLogicalChar(const MemOperand& opnd1, const MemOperand& opnd2,
193 const Operand& length);
194
195 void ExclusiveOrChar(const MemOperand& opnd1, const MemOperand& opnd2,
196 const Operand& length);
197
198 void RotateInsertSelectBits(Register dst, Register src,
199 const Operand& startBit, const Operand& endBit,
200 const Operand& shiftAmt, bool zeroBits);
201
202 void BranchRelativeOnIdxHighP(Register dst, Register inc, Label* L);
203
204 void SaveRegisters(RegList registers);
205 void RestoreRegisters(RegList registers);
206
207 void CallRecordWriteStub(Register object, Register address,
208 RememberedSetAction remembered_set_action,
209 SaveFPRegsMode fp_mode);
210 void CallRecordWriteStub(Register object, Register address,
211 RememberedSetAction remembered_set_action,
212 SaveFPRegsMode fp_mode, Address wasm_target);
213 void CallEphemeronKeyBarrier(Register object, Register address,
214 SaveFPRegsMode fp_mode);
215
216 void MultiPush(RegList regs, Register location = sp);
217 void MultiPop(RegList regs, Register location = sp);
218
219 void MultiPushDoubles(RegList dregs, Register location = sp);
220 void MultiPopDoubles(RegList dregs, Register location = sp);
221
222 // Calculate how much stack space (in bytes) are required to store caller
223 // registers excluding those specified in the arguments.
224 int RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode,
225 Register exclusion1 = no_reg,
226 Register exclusion2 = no_reg,
227 Register exclusion3 = no_reg) const;
228
229 // Push caller saved registers on the stack, and return the number of bytes
230 // stack pointer is adjusted.
231 int PushCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg,
232 Register exclusion2 = no_reg,
233 Register exclusion3 = no_reg);
234 // Restore caller saved registers from the stack, and return the number of
235 // bytes stack pointer is adjusted.
236 int PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg,
237 Register exclusion2 = no_reg,
238 Register exclusion3 = no_reg);
239
240 // Load an object from the root table.
LoadRoot(Register destination,RootIndex index)241 void LoadRoot(Register destination, RootIndex index) override {
242 LoadRoot(destination, index, al);
243 }
244 void LoadRoot(Register destination, RootIndex index, Condition cond);
245 //--------------------------------------------------------------------------
246 // S390 Macro Assemblers for Instructions
247 //--------------------------------------------------------------------------
248
249 // Arithmetic Operations
250
251 // Add (Register - Immediate)
252 void Add32(Register dst, const Operand& imm);
253 void Add32_RI(Register dst, const Operand& imm);
254 void AddP(Register dst, const Operand& imm);
255 void Add32(Register dst, Register src, const Operand& imm);
256 void Add32_RRI(Register dst, Register src, const Operand& imm);
257 void AddP(Register dst, Register src, const Operand& imm);
258
259 // Add (Register - Register)
260 void Add32(Register dst, Register src);
261 void AddP(Register dst, Register src);
262 void AddP_ExtendSrc(Register dst, Register src);
263 void Add32(Register dst, Register src1, Register src2);
264 void AddP(Register dst, Register src1, Register src2);
265 void AddP_ExtendSrc(Register dst, Register src1, Register src2);
266
267 // Add (Register - Mem)
268 void Add32(Register dst, const MemOperand& opnd);
269 void AddP(Register dst, const MemOperand& opnd);
270 void AddP_ExtendSrc(Register dst, const MemOperand& opnd);
271
272 // Add (Mem - Immediate)
273 void Add32(const MemOperand& opnd, const Operand& imm);
274 void AddP(const MemOperand& opnd, const Operand& imm);
275
276 // Add Logical (Register - Register)
277 void AddLogical32(Register dst, Register src1, Register src2);
278
279 // Add Logical With Carry (Register - Register)
280 void AddLogicalWithCarry32(Register dst, Register src1, Register src2);
281
282 // Add Logical (Register - Immediate)
283 void AddLogical(Register dst, const Operand& imm);
284 void AddLogicalP(Register dst, const Operand& imm);
285
286 // Add Logical (Register - Mem)
287 void AddLogical(Register dst, const MemOperand& opnd);
288 void AddLogicalP(Register dst, const MemOperand& opnd);
289
290 // Subtract (Register - Immediate)
291 void Sub32(Register dst, const Operand& imm);
Sub32_RI(Register dst,const Operand & imm)292 void Sub32_RI(Register dst, const Operand& imm) { Sub32(dst, imm); }
293 void SubP(Register dst, const Operand& imm);
294 void Sub32(Register dst, Register src, const Operand& imm);
Sub32_RRI(Register dst,Register src,const Operand & imm)295 void Sub32_RRI(Register dst, Register src, const Operand& imm) {
296 Sub32(dst, src, imm);
297 }
298 void SubP(Register dst, Register src, const Operand& imm);
299
300 // Subtract (Register - Register)
301 void Sub32(Register dst, Register src);
302 void SubP(Register dst, Register src);
303 void SubP_ExtendSrc(Register dst, Register src);
304 void Sub32(Register dst, Register src1, Register src2);
305 void SubP(Register dst, Register src1, Register src2);
306 void SubP_ExtendSrc(Register dst, Register src1, Register src2);
307
308 // Subtract (Register - Mem)
309 void Sub32(Register dst, const MemOperand& opnd);
310 void SubP(Register dst, const MemOperand& opnd);
311 void SubP_ExtendSrc(Register dst, const MemOperand& opnd);
312 void LoadAndSub32(Register dst, Register src, const MemOperand& opnd);
313 void LoadAndSub64(Register dst, Register src, const MemOperand& opnd);
314
315 // Subtract Logical (Register - Mem)
316 void SubLogical(Register dst, const MemOperand& opnd);
317 void SubLogicalP(Register dst, const MemOperand& opnd);
318 void SubLogicalP_ExtendSrc(Register dst, const MemOperand& opnd);
319 // Subtract Logical 32-bit
320 void SubLogical32(Register dst, Register src1, Register src2);
321 // Subtract Logical With Borrow 32-bit
322 void SubLogicalWithBorrow32(Register dst, Register src1, Register src2);
323
324 // Multiply
325 void MulP(Register dst, const Operand& opnd);
326 void MulP(Register dst, Register src);
327 void MulP(Register dst, const MemOperand& opnd);
328 void Mul(Register dst, Register src1, Register src2);
329 void Mul32(Register dst, const MemOperand& src1);
330 void Mul32(Register dst, Register src1);
331 void Mul32(Register dst, const Operand& src1);
332 void MulHigh32(Register dst, Register src1, const MemOperand& src2);
333 void MulHigh32(Register dst, Register src1, Register src2);
334 void MulHigh32(Register dst, Register src1, const Operand& src2);
335 void MulHighU32(Register dst, Register src1, const MemOperand& src2);
336 void MulHighU32(Register dst, Register src1, Register src2);
337 void MulHighU32(Register dst, Register src1, const Operand& src2);
338 void Mul32WithOverflowIfCCUnequal(Register dst, Register src1,
339 const MemOperand& src2);
340 void Mul32WithOverflowIfCCUnequal(Register dst, Register src1, Register src2);
341 void Mul32WithOverflowIfCCUnequal(Register dst, Register src1,
342 const Operand& src2);
343 void Mul64(Register dst, const MemOperand& src1);
344 void Mul64(Register dst, Register src1);
345 void Mul64(Register dst, const Operand& src1);
346 void MulPWithCondition(Register dst, Register src1, Register src2);
347
348 // Divide
349 void DivP(Register dividend, Register divider);
350 void Div32(Register dst, Register src1, const MemOperand& src2);
351 void Div32(Register dst, Register src1, Register src2);
352 void DivU32(Register dst, Register src1, const MemOperand& src2);
353 void DivU32(Register dst, Register src1, Register src2);
354 void Div64(Register dst, Register src1, const MemOperand& src2);
355 void Div64(Register dst, Register src1, Register src2);
356 void DivU64(Register dst, Register src1, const MemOperand& src2);
357 void DivU64(Register dst, Register src1, Register src2);
358
359 // Mod
360 void Mod32(Register dst, Register src1, const MemOperand& src2);
361 void Mod32(Register dst, Register src1, Register src2);
362 void ModU32(Register dst, Register src1, const MemOperand& src2);
363 void ModU32(Register dst, Register src1, Register src2);
364 void Mod64(Register dst, Register src1, const MemOperand& src2);
365 void Mod64(Register dst, Register src1, Register src2);
366 void ModU64(Register dst, Register src1, const MemOperand& src2);
367 void ModU64(Register dst, Register src1, Register src2);
368
369 // Square root
370 void Sqrt(DoubleRegister result, DoubleRegister input);
371 void Sqrt(DoubleRegister result, const MemOperand& input);
372
373 // Compare
374 void Cmp32(Register src1, Register src2);
375 void CmpP(Register src1, Register src2);
376 void Cmp32(Register dst, const Operand& opnd);
377 void CmpP(Register dst, const Operand& opnd);
378 void Cmp32(Register dst, const MemOperand& opnd);
379 void CmpP(Register dst, const MemOperand& opnd);
380 void CmpAndSwap(Register old_val, Register new_val, const MemOperand& opnd);
381 void CmpAndSwap64(Register old_val, Register new_val, const MemOperand& opnd);
382
383 // Compare Logical
384 void CmpLogical32(Register src1, Register src2);
385 void CmpLogicalP(Register src1, Register src2);
386 void CmpLogical32(Register src1, const Operand& opnd);
387 void CmpLogicalP(Register src1, const Operand& opnd);
388 void CmpLogical32(Register dst, const MemOperand& opnd);
389 void CmpLogicalP(Register dst, const MemOperand& opnd);
390
391 // Compare Logical Byte (CLI/CLIY)
392 void CmpLogicalByte(const MemOperand& mem, const Operand& imm);
393
394 // Load 32bit
395 void Load(Register dst, const MemOperand& opnd);
396 void Load(Register dst, const Operand& opnd);
397 void LoadW(Register dst, const MemOperand& opnd, Register scratch = no_reg);
398 void LoadW(Register dst, Register src);
399 void LoadlW(Register dst, const MemOperand& opnd, Register scratch = no_reg);
400 void LoadlW(Register dst, Register src);
401 void LoadLogicalHalfWordP(Register dst, const MemOperand& opnd);
402 void LoadLogicalHalfWordP(Register dst, Register src);
403 void LoadB(Register dst, const MemOperand& opnd);
404 void LoadB(Register dst, Register src);
405 void LoadlB(Register dst, const MemOperand& opnd);
406 void LoadlB(Register dst, Register src);
407
408 void LoadLogicalReversedWordP(Register dst, const MemOperand& opnd);
409 void LoadLogicalReversedHalfWordP(Register dst, const MemOperand& opnd);
410
411 // Load And Test
412 void LoadAndTest32(Register dst, Register src);
413 void LoadAndTestP_ExtendSrc(Register dst, Register src);
414 void LoadAndTestP(Register dst, Register src);
415
416 void LoadAndTest32(Register dst, const MemOperand& opnd);
417 void LoadAndTestP(Register dst, const MemOperand& opnd);
418
419 // Load Floating Point
420 void LoadDouble(DoubleRegister dst, const MemOperand& opnd);
421 void LoadFloat32(DoubleRegister dst, const MemOperand& opnd);
422 void LoadFloat32ConvertToDouble(DoubleRegister dst, const MemOperand& mem);
423 void LoadSimd128(Simd128Register dst, const MemOperand& mem,
424 Register scratch);
425
426 void AddFloat32(DoubleRegister dst, const MemOperand& opnd,
427 DoubleRegister scratch);
428 void AddFloat64(DoubleRegister dst, const MemOperand& opnd,
429 DoubleRegister scratch);
430 void SubFloat32(DoubleRegister dst, const MemOperand& opnd,
431 DoubleRegister scratch);
432 void SubFloat64(DoubleRegister dst, const MemOperand& opnd,
433 DoubleRegister scratch);
434 void MulFloat32(DoubleRegister dst, const MemOperand& opnd,
435 DoubleRegister scratch);
436 void MulFloat64(DoubleRegister dst, const MemOperand& opnd,
437 DoubleRegister scratch);
438 void DivFloat32(DoubleRegister dst, const MemOperand& opnd,
439 DoubleRegister scratch);
440 void DivFloat64(DoubleRegister dst, const MemOperand& opnd,
441 DoubleRegister scratch);
442 void LoadFloat32ToDouble(DoubleRegister dst, const MemOperand& opnd,
443 DoubleRegister scratch);
444
445 // Load On Condition
446 void LoadOnConditionP(Condition cond, Register dst, Register src);
447
448 void LoadPositiveP(Register result, Register input);
449 void LoadPositive32(Register result, Register input);
450
451 // Store Floating Point
452 void StoreDouble(DoubleRegister dst, const MemOperand& opnd);
453 void StoreFloat32(DoubleRegister dst, const MemOperand& opnd);
454 void StoreDoubleAsFloat32(DoubleRegister src, const MemOperand& mem,
455 DoubleRegister scratch);
456 void StoreSimd128(Simd128Register src, const MemOperand& mem,
457 Register scratch);
458
459 void Branch(Condition c, const Operand& opnd);
460 void BranchOnCount(Register r1, Label* l);
461
462 // Shifts
463 void ShiftLeft(Register dst, Register src, Register val);
464 void ShiftLeft(Register dst, Register src, const Operand& val);
465 void ShiftRight(Register dst, Register src, Register val);
466 void ShiftRight(Register dst, Register src, const Operand& val);
467 void ShiftLeftArith(Register dst, Register src, Register shift);
468 void ShiftLeftArith(Register dst, Register src, const Operand& val);
469 void ShiftRightArith(Register dst, Register src, Register shift);
470 void ShiftRightArith(Register dst, Register src, const Operand& val);
471
472 void ClearRightImm(Register dst, Register src, const Operand& val);
473
474 // Bitwise operations
475 void And(Register dst, Register src);
476 void AndP(Register dst, Register src);
477 void And(Register dst, Register src1, Register src2);
478 void AndP(Register dst, Register src1, Register src2);
479 void And(Register dst, const MemOperand& opnd);
480 void AndP(Register dst, const MemOperand& opnd);
481 void And(Register dst, const Operand& opnd);
482 void AndP(Register dst, const Operand& opnd);
483 void And(Register dst, Register src, const Operand& opnd);
484 void AndP(Register dst, Register src, const Operand& opnd);
485 void Or(Register dst, Register src);
486 void OrP(Register dst, Register src);
487 void Or(Register dst, Register src1, Register src2);
488 void OrP(Register dst, Register src1, Register src2);
489 void Or(Register dst, const MemOperand& opnd);
490 void OrP(Register dst, const MemOperand& opnd);
491 void Or(Register dst, const Operand& opnd);
492 void OrP(Register dst, const Operand& opnd);
493 void Or(Register dst, Register src, const Operand& opnd);
494 void OrP(Register dst, Register src, const Operand& opnd);
495 void Xor(Register dst, Register src);
496 void XorP(Register dst, Register src);
497 void Xor(Register dst, Register src1, Register src2);
498 void XorP(Register dst, Register src1, Register src2);
499 void Xor(Register dst, const MemOperand& opnd);
500 void XorP(Register dst, const MemOperand& opnd);
501 void Xor(Register dst, const Operand& opnd);
502 void XorP(Register dst, const Operand& opnd);
503 void Xor(Register dst, Register src, const Operand& opnd);
504 void XorP(Register dst, Register src, const Operand& opnd);
505 void Popcnt32(Register dst, Register src);
506 void Not32(Register dst, Register src = no_reg);
507 void Not64(Register dst, Register src = no_reg);
508 void NotP(Register dst, Register src = no_reg);
509
510 #ifdef V8_TARGET_ARCH_S390X
511 void Popcnt64(Register dst, Register src);
512 #endif
513
514 void mov(Register dst, const Operand& src);
515
CleanUInt32(Register x)516 void CleanUInt32(Register x) {
517 #ifdef V8_TARGET_ARCH_S390X
518 llgfr(x, x);
519 #endif
520 }
521
push(DoubleRegister src)522 void push(DoubleRegister src) {
523 lay(sp, MemOperand(sp, -kSystemPointerSize));
524 StoreDouble(src, MemOperand(sp));
525 }
526
push(Register src)527 void push(Register src) {
528 lay(sp, MemOperand(sp, -kSystemPointerSize));
529 StoreP(src, MemOperand(sp));
530 }
531
pop(DoubleRegister dst)532 void pop(DoubleRegister dst) {
533 LoadDouble(dst, MemOperand(sp));
534 la(sp, MemOperand(sp, kSystemPointerSize));
535 }
536
pop(Register dst)537 void pop(Register dst) {
538 LoadP(dst, MemOperand(sp));
539 la(sp, MemOperand(sp, kSystemPointerSize));
540 }
541
pop()542 void pop() { la(sp, MemOperand(sp, kSystemPointerSize)); }
543
Push(Register src)544 void Push(Register src) { push(src); }
545
546 // Push a handle.
547 void Push(Handle<HeapObject> handle);
548 void Push(Smi smi);
549
550 // Push two registers. Pushes leftmost register first (to highest address).
Push(Register src1,Register src2)551 void Push(Register src1, Register src2) {
552 lay(sp, MemOperand(sp, -kSystemPointerSize * 2));
553 StoreP(src1, MemOperand(sp, kSystemPointerSize));
554 StoreP(src2, MemOperand(sp, 0));
555 }
556
557 // Push three registers. Pushes leftmost register first (to highest address).
Push(Register src1,Register src2,Register src3)558 void Push(Register src1, Register src2, Register src3) {
559 lay(sp, MemOperand(sp, -kSystemPointerSize * 3));
560 StoreP(src1, MemOperand(sp, kSystemPointerSize * 2));
561 StoreP(src2, MemOperand(sp, kSystemPointerSize));
562 StoreP(src3, MemOperand(sp, 0));
563 }
564
565 // Push four registers. Pushes leftmost register first (to highest address).
Push(Register src1,Register src2,Register src3,Register src4)566 void Push(Register src1, Register src2, Register src3, Register src4) {
567 lay(sp, MemOperand(sp, -kSystemPointerSize * 4));
568 StoreP(src1, MemOperand(sp, kSystemPointerSize * 3));
569 StoreP(src2, MemOperand(sp, kSystemPointerSize * 2));
570 StoreP(src3, MemOperand(sp, kSystemPointerSize));
571 StoreP(src4, MemOperand(sp, 0));
572 }
573
574 // Push five registers. Pushes leftmost register first (to highest address).
Push(Register src1,Register src2,Register src3,Register src4,Register src5)575 void Push(Register src1, Register src2, Register src3, Register src4,
576 Register src5) {
577 DCHECK(src1 != src2);
578 DCHECK(src1 != src3);
579 DCHECK(src2 != src3);
580 DCHECK(src1 != src4);
581 DCHECK(src2 != src4);
582 DCHECK(src3 != src4);
583 DCHECK(src1 != src5);
584 DCHECK(src2 != src5);
585 DCHECK(src3 != src5);
586 DCHECK(src4 != src5);
587
588 lay(sp, MemOperand(sp, -kSystemPointerSize * 5));
589 StoreP(src1, MemOperand(sp, kSystemPointerSize * 4));
590 StoreP(src2, MemOperand(sp, kSystemPointerSize * 3));
591 StoreP(src3, MemOperand(sp, kSystemPointerSize * 2));
592 StoreP(src4, MemOperand(sp, kSystemPointerSize));
593 StoreP(src5, MemOperand(sp, 0));
594 }
595
596 enum PushArrayOrder { kNormal, kReverse };
597 void PushArray(Register array, Register size, Register scratch,
598 Register scratch2, PushArrayOrder order = kNormal);
599
Pop(Register dst)600 void Pop(Register dst) { pop(dst); }
601
602 // Pop two registers. Pops rightmost register first (from lower address).
Pop(Register src1,Register src2)603 void Pop(Register src1, Register src2) {
604 LoadP(src2, MemOperand(sp, 0));
605 LoadP(src1, MemOperand(sp, kSystemPointerSize));
606 la(sp, MemOperand(sp, 2 * kSystemPointerSize));
607 }
608
609 // Pop three registers. Pops rightmost register first (from lower address).
Pop(Register src1,Register src2,Register src3)610 void Pop(Register src1, Register src2, Register src3) {
611 LoadP(src3, MemOperand(sp, 0));
612 LoadP(src2, MemOperand(sp, kSystemPointerSize));
613 LoadP(src1, MemOperand(sp, 2 * kSystemPointerSize));
614 la(sp, MemOperand(sp, 3 * kSystemPointerSize));
615 }
616
617 // Pop four registers. Pops rightmost register first (from lower address).
Pop(Register src1,Register src2,Register src3,Register src4)618 void Pop(Register src1, Register src2, Register src3, Register src4) {
619 LoadP(src4, MemOperand(sp, 0));
620 LoadP(src3, MemOperand(sp, kSystemPointerSize));
621 LoadP(src2, MemOperand(sp, 2 * kSystemPointerSize));
622 LoadP(src1, MemOperand(sp, 3 * kSystemPointerSize));
623 la(sp, MemOperand(sp, 4 * kSystemPointerSize));
624 }
625
626 // Pop five registers. Pops rightmost register first (from lower address).
Pop(Register src1,Register src2,Register src3,Register src4,Register src5)627 void Pop(Register src1, Register src2, Register src3, Register src4,
628 Register src5) {
629 LoadP(src5, MemOperand(sp, 0));
630 LoadP(src4, MemOperand(sp, kSystemPointerSize));
631 LoadP(src3, MemOperand(sp, 2 * kSystemPointerSize));
632 LoadP(src2, MemOperand(sp, 3 * kSystemPointerSize));
633 LoadP(src1, MemOperand(sp, 4 * kSystemPointerSize));
634 la(sp, MemOperand(sp, 5 * kSystemPointerSize));
635 }
636
637 // Push a fixed frame, consisting of lr, fp, constant pool.
638 void PushCommonFrame(Register marker_reg = no_reg);
639
640 // Push a standard frame, consisting of lr, fp, constant pool,
641 // context and JS function
642 void PushStandardFrame(Register function_reg);
643
644 void PopCommonFrame(Register marker_reg = no_reg);
645
646 // Restore caller's frame pointer and return address prior to being
647 // overwritten by tail call stack preparation.
648 void RestoreFrameStateForTailCall();
649
InitializeRootRegister()650 void InitializeRootRegister() {
651 ExternalReference isolate_root = ExternalReference::isolate_root(isolate());
652 mov(kRootRegister, Operand(isolate_root));
653 }
654
655 // If the value is a NaN, canonicalize the value else, do nothing.
656 void CanonicalizeNaN(const DoubleRegister dst, const DoubleRegister src);
CanonicalizeNaN(const DoubleRegister value)657 void CanonicalizeNaN(const DoubleRegister value) {
658 CanonicalizeNaN(value, value);
659 }
660
661 // Converts the integer (untagged smi) in |src| to a double, storing
662 // the result to |dst|
663 void ConvertIntToDouble(DoubleRegister dst, Register src);
664
665 // Converts the unsigned integer (untagged smi) in |src| to
666 // a double, storing the result to |dst|
667 void ConvertUnsignedIntToDouble(DoubleRegister dst, Register src);
668
669 // Converts the integer (untagged smi) in |src| to
670 // a float, storing the result in |dst|
671 void ConvertIntToFloat(DoubleRegister dst, Register src);
672
673 // Converts the unsigned integer (untagged smi) in |src| to
674 // a float, storing the result in |dst|
675 void ConvertUnsignedIntToFloat(DoubleRegister dst, Register src);
676
677 void ConvertInt64ToFloat(DoubleRegister double_dst, Register src);
678 void ConvertInt64ToDouble(DoubleRegister double_dst, Register src);
679 void ConvertUnsignedInt64ToFloat(DoubleRegister double_dst, Register src);
680 void ConvertUnsignedInt64ToDouble(DoubleRegister double_dst, Register src);
681
682 void MovIntToFloat(DoubleRegister dst, Register src);
683 void MovFloatToInt(Register dst, DoubleRegister src);
684 void MovDoubleToInt64(Register dst, DoubleRegister src);
685 void MovInt64ToDouble(DoubleRegister dst, Register src);
686 // Converts the double_input to an integer. Note that, upon return,
687 // the contents of double_dst will also hold the fixed point representation.
688 void ConvertFloat32ToInt64(const Register dst,
689 const DoubleRegister double_input,
690 FPRoundingMode rounding_mode = kRoundToZero);
691
692 // Converts the double_input to an integer. Note that, upon return,
693 // the contents of double_dst will also hold the fixed point representation.
694 void ConvertDoubleToInt64(const Register dst,
695 const DoubleRegister double_input,
696 FPRoundingMode rounding_mode = kRoundToZero);
697 void ConvertDoubleToInt32(const Register dst,
698 const DoubleRegister double_input,
699 FPRoundingMode rounding_mode = kRoundToZero);
700
701 void ConvertFloat32ToInt32(const Register result,
702 const DoubleRegister double_input,
703 FPRoundingMode rounding_mode);
704 void ConvertFloat32ToUnsignedInt32(
705 const Register result, const DoubleRegister double_input,
706 FPRoundingMode rounding_mode = kRoundToZero);
707 // Converts the double_input to an unsigned integer. Note that, upon return,
708 // the contents of double_dst will also hold the fixed point representation.
709 void ConvertDoubleToUnsignedInt64(
710 const Register dst, const DoubleRegister double_input,
711 FPRoundingMode rounding_mode = kRoundToZero);
712 void ConvertDoubleToUnsignedInt32(
713 const Register dst, const DoubleRegister double_input,
714 FPRoundingMode rounding_mode = kRoundToZero);
715 void ConvertFloat32ToUnsignedInt64(
716 const Register result, const DoubleRegister double_input,
717 FPRoundingMode rounding_mode = kRoundToZero);
718
719 #if !V8_TARGET_ARCH_S390X
720 void ShiftLeftPair(Register dst_low, Register dst_high, Register src_low,
721 Register src_high, Register scratch, Register shift);
722 void ShiftLeftPair(Register dst_low, Register dst_high, Register src_low,
723 Register src_high, uint32_t shift);
724 void ShiftRightPair(Register dst_low, Register dst_high, Register src_low,
725 Register src_high, Register scratch, Register shift);
726 void ShiftRightPair(Register dst_low, Register dst_high, Register src_low,
727 Register src_high, uint32_t shift);
728 void ShiftRightArithPair(Register dst_low, Register dst_high,
729 Register src_low, Register src_high,
730 Register scratch, Register shift);
731 void ShiftRightArithPair(Register dst_low, Register dst_high,
732 Register src_low, Register src_high, uint32_t shift);
733 #endif
734
735 // Generates function and stub prologue code.
736 void StubPrologue(StackFrame::Type type, Register base = no_reg,
737 int prologue_offset = 0);
738 void Prologue(Register base, int prologue_offset = 0);
739
740 // Get the actual activation frame alignment for target environment.
741 static int ActivationFrameAlignment();
742 // ----------------------------------------------------------------
743 // new S390 macro-assembler interfaces that are slightly higher level
744 // than assembler-s390 and may generate variable length sequences
745
746 // load a literal signed int value <value> to GPR <dst>
747 void LoadIntLiteral(Register dst, int value);
748
749 // load an SMI value <value> to GPR <dst>
750 void LoadSmiLiteral(Register dst, Smi smi);
751
752 // load a literal double value <value> to FPR <result>
753 void LoadDoubleLiteral(DoubleRegister result, double value, Register scratch);
754 void LoadDoubleLiteral(DoubleRegister result, uint64_t value,
755 Register scratch);
756
757 void LoadFloat32Literal(DoubleRegister result, float value, Register scratch);
758
759 void StoreW(Register src, const MemOperand& mem, Register scratch = no_reg);
760
761 void LoadHalfWordP(Register dst, Register src);
762
763 void LoadHalfWordP(Register dst, const MemOperand& mem,
764 Register scratch = no_reg);
765
766 void StoreHalfWord(Register src, const MemOperand& mem,
767 Register scratch = r0);
768 void StoreByte(Register src, const MemOperand& mem, Register scratch = r0);
769 void CmpSmiLiteral(Register src1, Smi smi, Register scratch);
770
771 // Set new rounding mode RN to FPSCR
772 void SetRoundingMode(FPRoundingMode RN);
773
774 // reset rounding mode to default (kRoundToNearest)
775 void ResetRoundingMode();
776
777 // These exist to provide portability between 32 and 64bit
778 void LoadP(Register dst, const MemOperand& mem, Register scratch = no_reg);
779 void StoreP(Register src, const MemOperand& mem, Register scratch = no_reg);
780 void StoreP(const MemOperand& mem, const Operand& opnd,
781 Register scratch = no_reg);
782 void LoadMultipleP(Register dst1, Register dst2, const MemOperand& mem);
783 void StoreMultipleP(Register dst1, Register dst2, const MemOperand& mem);
784 void LoadMultipleW(Register dst1, Register dst2, const MemOperand& mem);
785 void StoreMultipleW(Register dst1, Register dst2, const MemOperand& mem);
786
787 void SwapP(Register src, Register dst, Register scratch);
788 void SwapP(Register src, MemOperand dst, Register scratch);
789 void SwapP(MemOperand src, MemOperand dst, Register scratch_0,
790 Register scratch_1);
791 void SwapFloat32(DoubleRegister src, DoubleRegister dst,
792 DoubleRegister scratch);
793 void SwapFloat32(DoubleRegister src, MemOperand dst, DoubleRegister scratch);
794 void SwapFloat32(MemOperand src, MemOperand dst, DoubleRegister scratch);
795 void SwapDouble(DoubleRegister src, DoubleRegister dst,
796 DoubleRegister scratch);
797 void SwapDouble(DoubleRegister src, MemOperand dst, DoubleRegister scratch);
798 void SwapDouble(MemOperand src, MemOperand dst, DoubleRegister scratch);
799 void SwapSimd128(Simd128Register src, Simd128Register dst,
800 Simd128Register scratch);
801 void SwapSimd128(Simd128Register src, MemOperand dst,
802 Simd128Register scratch);
803 void SwapSimd128(MemOperand src, MemOperand dst, Simd128Register scratch);
804
805 // Cleanse pointer address on 31bit by zero out top bit.
806 // This is a NOP on 64-bit.
CleanseP(Register src)807 void CleanseP(Register src) {
808 #if (V8_HOST_ARCH_S390 && !(V8_TARGET_ARCH_S390X))
809 nilh(src, Operand(0x7FFF));
810 #endif
811 }
812
813 void PrepareForTailCall(Register callee_args_count,
814 Register caller_args_count, Register scratch0,
815 Register scratch1);
816
817 // ---------------------------------------------------------------------------
818 // Runtime calls
819
820 // Before calling a C-function from generated code, align arguments on stack.
821 // After aligning the frame, non-register arguments must be stored in
822 // sp[0], sp[4], etc., not pushed. The argument count assumes all arguments
823 // are word sized. If double arguments are used, this function assumes that
824 // all double arguments are stored before core registers; otherwise the
825 // correct alignment of the double values is not guaranteed.
826 // Some compilers/platforms require the stack to be aligned when calling
827 // C++ code.
828 // Needs a scratch register to do some arithmetic. This register will be
829 // trashed.
830 void PrepareCallCFunction(int num_reg_arguments, int num_double_registers,
831 Register scratch);
832 void PrepareCallCFunction(int num_reg_arguments, Register scratch);
833
834 // There are two ways of passing double arguments on ARM, depending on
835 // whether soft or hard floating point ABI is used. These functions
836 // abstract parameter passing for the three different ways we call
837 // C functions from generated code.
838 void MovToFloatParameter(DoubleRegister src);
839 void MovToFloatParameters(DoubleRegister src1, DoubleRegister src2);
840 void MovToFloatResult(DoubleRegister src);
841
842 // Calls a C function and cleans up the space for arguments allocated
843 // by PrepareCallCFunction. The called function is not allowed to trigger a
844 // garbage collection, since that might move the code and invalidate the
845 // return address (unless this is somehow accounted for by the called
846 // function).
847 void CallCFunction(ExternalReference function, int num_arguments);
848 void CallCFunction(Register function, int num_arguments);
849 void CallCFunction(ExternalReference function, int num_reg_arguments,
850 int num_double_arguments);
851 void CallCFunction(Register function, int num_reg_arguments,
852 int num_double_arguments);
853
854 void MovFromFloatParameter(DoubleRegister dst);
855 void MovFromFloatResult(DoubleRegister dst);
856
857 void Trap() override;
858 void DebugBreak() override;
859
860 // Emit code for a truncating division by a constant. The dividend register is
861 // unchanged and ip gets clobbered. Dividend and result must be different.
862 void TruncateDoubleToI(Isolate* isolate, Zone* zone, Register result,
863 DoubleRegister double_input, StubCallMode stub_mode);
864 void TryInlineTruncateDoubleToI(Register result, DoubleRegister double_input,
865 Label* done);
866
867 // ---------------------------------------------------------------------------
868 // Debugging
869
870 // Calls Abort(msg) if the condition cond is not satisfied.
871 // Use --debug_code to enable.
872 void Assert(Condition cond, AbortReason reason, CRegister cr = cr7);
873
874 // Like Assert(), but always enabled.
875 void Check(Condition cond, AbortReason reason, CRegister cr = cr7);
876
877 // Print a message to stdout and abort execution.
878 void Abort(AbortReason reason);
879
880 // ---------------------------------------------------------------------------
881 // Bit testing/extraction
882 //
883 // Bit numbering is such that the least significant bit is bit 0
884 // (for consistency between 32/64-bit).
885
886 // Extract consecutive bits (defined by rangeStart - rangeEnd) from src
887 // and place them into the least significant bits of dst.
ExtractBitRange(Register dst,Register src,int rangeStart,int rangeEnd)888 inline void ExtractBitRange(Register dst, Register src, int rangeStart,
889 int rangeEnd) {
890 DCHECK(rangeStart >= rangeEnd && rangeStart < kBitsPerSystemPointer);
891
892 // Try to use RISBG if possible.
893 if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) {
894 int shiftAmount = (64 - rangeEnd) % 64; // Convert to shift left.
895 int endBit = 63; // End is always LSB after shifting.
896 int startBit = 63 - rangeStart + rangeEnd;
897 RotateInsertSelectBits(dst, src, Operand(startBit), Operand(endBit),
898 Operand(shiftAmount), true);
899 } else {
900 if (rangeEnd > 0) // Don't need to shift if rangeEnd is zero.
901 ShiftRightP(dst, src, Operand(rangeEnd));
902 else if (dst != src) // If we didn't shift, we might need to copy
903 LoadRR(dst, src);
904 int width = rangeStart - rangeEnd + 1;
905 #if V8_TARGET_ARCH_S390X
906 uint64_t mask = (static_cast<uint64_t>(1) << width) - 1;
907 nihf(dst, Operand(mask >> 32));
908 nilf(dst, Operand(mask & 0xFFFFFFFF));
909 ltgr(dst, dst);
910 #else
911 uint32_t mask = (1 << width) - 1;
912 AndP(dst, Operand(mask));
913 #endif
914 }
915 }
916
ExtractBit(Register dst,Register src,uint32_t bitNumber)917 inline void ExtractBit(Register dst, Register src, uint32_t bitNumber) {
918 ExtractBitRange(dst, src, bitNumber, bitNumber);
919 }
920
921 // Extract consecutive bits (defined by mask) from src and place them
922 // into the least significant bits of dst.
923 inline void ExtractBitMask(Register dst, Register src, uintptr_t mask,
924 RCBit rc = LeaveRC) {
925 int start = kBitsPerSystemPointer - 1;
926 int end;
927 uintptr_t bit = (1L << start);
928
929 while (bit && (mask & bit) == 0) {
930 start--;
931 bit >>= 1;
932 }
933 end = start;
934 bit >>= 1;
935
936 while (bit && (mask & bit)) {
937 end--;
938 bit >>= 1;
939 }
940
941 // 1-bits in mask must be contiguous
942 DCHECK(bit == 0 || (mask & ((bit << 1) - 1)) == 0);
943
944 ExtractBitRange(dst, src, start, end);
945 }
946
947 // Test single bit in value.
948 inline void TestBit(Register value, int bitNumber, Register scratch = r0) {
949 ExtractBitRange(scratch, value, bitNumber, bitNumber);
950 }
951
952 // Test consecutive bit range in value. Range is defined by
953 // rangeStart - rangeEnd.
954 inline void TestBitRange(Register value, int rangeStart, int rangeEnd,
955 Register scratch = r0) {
956 ExtractBitRange(scratch, value, rangeStart, rangeEnd);
957 }
958
959 // Test consecutive bit range in value. Range is defined by mask.
960 inline void TestBitMask(Register value, uintptr_t mask,
961 Register scratch = r0) {
962 ExtractBitMask(scratch, value, mask, SetRC);
963 }
TestIfSmi(Register value)964 inline void TestIfSmi(Register value) { tmll(value, Operand(1)); }
965
TestIfSmi(MemOperand value)966 inline void TestIfSmi(MemOperand value) {
967 if (is_uint12(value.offset())) {
968 tm(value, Operand(1));
969 } else if (is_int20(value.offset())) {
970 tmy(value, Operand(1));
971 } else {
972 LoadB(r0, value);
973 tmll(r0, Operand(1));
974 }
975 }
976
TestIfInt32(Register value)977 inline void TestIfInt32(Register value) {
978 // High bits must be identical to fit into an 32-bit integer
979 cgfr(value, value);
980 }
SmiUntag(Register reg)981 void SmiUntag(Register reg) { SmiUntag(reg, reg); }
982
983 void SmiUntag(Register dst, const MemOperand& src);
SmiUntag(Register dst,Register src)984 void SmiUntag(Register dst, Register src) {
985 if (SmiValuesAre31Bits()) {
986 ShiftRightArith(dst, src, Operand(kSmiShift));
987 } else {
988 ShiftRightArithP(dst, src, Operand(kSmiShift));
989 }
990 lgfr(dst, dst);
991 }
992
993 // Activation support.
994 void EnterFrame(StackFrame::Type type,
995 bool load_constant_pool_pointer_reg = false);
996 // Returns the pc offset at which the frame ends.
997 int LeaveFrame(StackFrame::Type type, int stack_adjustment = 0);
998
999 void CheckPageFlag(Register object, Register scratch, int mask, Condition cc,
1000 Label* condition_met);
1001
1002 void ResetSpeculationPoisonRegister();
1003 void ComputeCodeStartAddress(Register dst);
1004 void LoadPC(Register dst);
1005
1006 // Control-flow integrity:
1007
1008 // Define a function entrypoint. This doesn't emit any code for this
1009 // architecture, as control-flow integrity is not supported for it.
CodeEntry()1010 void CodeEntry() {}
1011 // Define an exception handler.
ExceptionHandler()1012 void ExceptionHandler() {}
1013 // Define an exception handler and bind a label.
BindExceptionHandler(Label * label)1014 void BindExceptionHandler(Label* label) { bind(label); }
1015
1016 // Generates an instruction sequence s.t. the return address points to the
1017 // instruction following the call.
1018 // The return address on the stack is used by frame iteration.
1019 void StoreReturnAddressAndCall(Register target);
1020
1021 // ---------------------------------------------------------------------------
1022 // Pointer compression Support
1023
1024 // Loads a field containing a HeapObject and decompresses it if pointer
1025 // compression is enabled.
1026 void LoadTaggedPointerField(const Register& destination,
1027 const MemOperand& field_operand,
1028 const Register& scratch = no_reg);
1029
1030 // Loads a field containing any tagged value and decompresses it if necessary.
1031 void LoadAnyTaggedField(const Register& destination,
1032 const MemOperand& field_operand,
1033 const Register& scratch = no_reg);
1034
1035 // Loads a field containing smi value and untags it.
1036 void SmiUntagField(Register dst, const MemOperand& src);
1037
1038 // Compresses and stores tagged value to given on-heap location.
1039 void StoreTaggedField(const Register& value,
1040 const MemOperand& dst_field_operand,
1041 const Register& scratch = no_reg);
1042
1043 void DecompressTaggedSigned(Register destination, MemOperand field_operand);
1044 void DecompressTaggedSigned(Register destination, Register src);
1045 void DecompressTaggedPointer(Register destination, MemOperand field_operand);
1046 void DecompressTaggedPointer(Register destination, Register source);
1047 void DecompressAnyTagged(Register destination, MemOperand field_operand);
1048 void DecompressAnyTagged(Register destination, Register source);
1049
1050 private:
1051 static const int kSmiShift = kSmiTagSize + kSmiShiftSize;
1052
1053 void CallCFunctionHelper(Register function, int num_reg_arguments,
1054 int num_double_arguments);
1055
1056 void CallRecordWriteStub(Register object, Register address,
1057 RememberedSetAction remembered_set_action,
1058 SaveFPRegsMode fp_mode, Handle<Code> code_target,
1059 Address wasm_target);
1060
1061 void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al);
1062 int CalculateStackPassedWords(int num_reg_arguments,
1063 int num_double_arguments);
1064 };
1065
1066 // MacroAssembler implements a collection of frequently used macros.
1067 class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
1068 public:
1069 using TurboAssembler::TurboAssembler;
1070
1071 // It assumes that the arguments are located below the stack pointer.
1072 // argc is the number of arguments not including the receiver.
1073 // TODO(victorgomes): Remove this function once we stick with the reversed
1074 // arguments order.
LoadReceiver(Register dest,Register argc)1075 void LoadReceiver(Register dest, Register argc) {
1076 LoadP(dest, MemOperand(sp, 0));
1077 }
1078
StoreReceiver(Register rec,Register argc,Register scratch)1079 void StoreReceiver(Register rec, Register argc, Register scratch) {
1080 StoreP(rec, MemOperand(sp, 0));
1081 }
1082
1083 void CallRuntime(const Runtime::Function* f, int num_arguments,
1084 SaveFPRegsMode save_doubles = kDontSaveFPRegs);
CallRuntimeSaveDoubles(Runtime::FunctionId fid)1085 void CallRuntimeSaveDoubles(Runtime::FunctionId fid) {
1086 const Runtime::Function* function = Runtime::FunctionForId(fid);
1087 CallRuntime(function, function->nargs, kSaveFPRegs);
1088 }
1089
1090 // Convenience function: Same as above, but takes the fid instead.
1091 void CallRuntime(Runtime::FunctionId fid,
1092 SaveFPRegsMode save_doubles = kDontSaveFPRegs) {
1093 const Runtime::Function* function = Runtime::FunctionForId(fid);
1094 CallRuntime(function, function->nargs, save_doubles);
1095 }
1096
1097 // Convenience function: Same as above, but takes the fid instead.
1098 void CallRuntime(Runtime::FunctionId fid, int num_arguments,
1099 SaveFPRegsMode save_doubles = kDontSaveFPRegs) {
1100 CallRuntime(Runtime::FunctionForId(fid), num_arguments, save_doubles);
1101 }
1102
1103 // Convenience function: tail call a runtime routine (jump).
1104 void TailCallRuntime(Runtime::FunctionId fid);
1105
1106 // ---------------------------------------------------------------------------
1107 // Support functions.
1108
1109 // Compare object type for heap object. heap_object contains a non-Smi
1110 // whose object type should be compared with the given type. This both
1111 // sets the flags and leaves the object type in the type_reg register.
1112 // It leaves the map in the map register (unless the type_reg and map register
1113 // are the same register). It leaves the heap object in the heap_object
1114 // register unless the heap_object register is the same register as one of the
1115 // other registers.
1116 // Type_reg can be no_reg. In that case ip is used.
1117 void CompareObjectType(Register heap_object, Register map, Register type_reg,
1118 InstanceType type);
1119
1120 // Compare instance type in a map. map contains a valid map object whose
1121 // object type should be compared with the given type. This both
1122 // sets the flags and leaves the object type in the type_reg register.
1123 void CompareInstanceType(Register map, Register type_reg, InstanceType type);
1124
1125 // Compare the object in a register to a value from the root list.
1126 // Uses the ip register as scratch.
1127 void CompareRoot(Register obj, RootIndex index);
PushRoot(RootIndex index)1128 void PushRoot(RootIndex index) {
1129 LoadRoot(r0, index);
1130 Push(r0);
1131 }
1132
1133 template <class T>
CompareTagged(Register src1,T src2)1134 void CompareTagged(Register src1, T src2) {
1135 if (COMPRESS_POINTERS_BOOL) {
1136 Cmp32(src1, src2);
1137 } else {
1138 CmpP(src1, src2);
1139 }
1140 }
1141
1142 // Jump to a runtime routine.
1143 void JumpToExternalReference(const ExternalReference& builtin,
1144 bool builtin_exit_frame = false);
1145
1146 // Generates a trampoline to jump to the off-heap instruction stream.
1147 void JumpToInstructionStream(Address entry);
1148
1149 // Compare the object in a register to a value and jump if they are equal.
JumpIfRoot(Register with,RootIndex index,Label * if_equal)1150 void JumpIfRoot(Register with, RootIndex index, Label* if_equal) {
1151 CompareRoot(with, index);
1152 beq(if_equal);
1153 }
1154
1155 // 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)1156 void JumpIfNotRoot(Register with, RootIndex index, Label* if_not_equal) {
1157 CompareRoot(with, index);
1158 bne(if_not_equal);
1159 }
1160
1161 // Checks if value is in range [lower_limit, higher_limit] using a single
1162 // comparison.
1163 void JumpIfIsInRange(Register value, unsigned lower_limit,
1164 unsigned higher_limit, Label* on_in_range);
1165
1166 // ---------------------------------------------------------------------------
1167 // In-place weak references.
1168 void LoadWeakValue(Register out, Register in, Label* target_if_cleared);
1169
1170 // ---------------------------------------------------------------------------
1171 // StatsCounter support
1172
1173 void IncrementCounter(StatsCounter* counter, int value, Register scratch1,
1174 Register scratch2);
1175 void DecrementCounter(StatsCounter* counter, int value, Register scratch1,
1176 Register scratch2);
1177 // ---------------------------------------------------------------------------
1178 // JavaScript invokes
1179
1180 // Set up call kind marking in ecx. The method takes ecx as an
1181 // explicit first parameter to make the code more readable at the
1182 // call sites.
1183 // void SetCallKind(Register dst, CallKind kind);
1184
1185 // Removes current frame and its arguments from the stack preserving
1186 // the arguments and a return address pushed to the stack for the next call.
1187 // Both |callee_args_count| and |caller_args_count| do not include
1188 // receiver. |callee_args_count| is not modified. |caller_args_count|
1189 // is trashed.
1190
1191 // Invoke the JavaScript function code by either calling or jumping.
1192 void InvokeFunctionCode(Register function, Register new_target,
1193 Register expected_parameter_count,
1194 Register actual_parameter_count, InvokeFlag flag);
1195
1196 // On function call, call into the debugger if necessary.
1197 void CheckDebugHook(Register fun, Register new_target,
1198 Register expected_parameter_count,
1199 Register actual_parameter_count);
1200
1201 // Invoke the JavaScript function in the given register. Changes the
1202 // current context to the context in the function before invoking.
1203 void InvokeFunctionWithNewTarget(Register function, Register new_target,
1204 Register actual_parameter_count,
1205 InvokeFlag flag);
1206 void InvokeFunction(Register function, Register expected_parameter_count,
1207 Register actual_parameter_count, InvokeFlag flag);
1208
1209 // Frame restart support
1210 void MaybeDropFrames();
1211
1212 // Exception handling
1213
1214 // Push a new stack handler and link into stack handler chain.
1215 void PushStackHandler();
1216
1217 // Unlink the stack handler on top of the stack from the stack handler chain.
1218 // Must preserve the result register.
1219 void PopStackHandler();
1220
1221 // Enter exit frame.
1222 // stack_space - extra stack space, used for parameters before call to C.
1223 // At least one slot (for the return address) should be provided.
1224 void EnterExitFrame(bool save_doubles, int stack_space = 1,
1225 StackFrame::Type frame_type = StackFrame::EXIT);
1226
1227 // Leave the current exit frame. Expects the return value in r0.
1228 // Expect the number of values, pushed prior to the exit frame, to
1229 // remove in a register (or no_reg, if there is nothing to remove).
1230 void LeaveExitFrame(bool save_doubles, Register argument_count,
1231 bool argument_count_is_length = false);
1232
1233 void LoadMap(Register destination, Register object);
1234
1235 // Load the global proxy from the current context.
LoadGlobalProxy(Register dst)1236 void LoadGlobalProxy(Register dst) {
1237 LoadNativeContextSlot(Context::GLOBAL_PROXY_INDEX, dst);
1238 }
1239
1240 void LoadNativeContextSlot(int index, Register dst);
1241
1242 // ---------------------------------------------------------------------------
1243 // Smi utilities
1244
1245 // Shift left by kSmiShift
SmiTag(Register reg)1246 void SmiTag(Register reg) { SmiTag(reg, reg); }
SmiTag(Register dst,Register src)1247 void SmiTag(Register dst, Register src) {
1248 ShiftLeftP(dst, src, Operand(kSmiShift));
1249 }
1250
SmiToPtrArrayOffset(Register dst,Register src)1251 void SmiToPtrArrayOffset(Register dst, Register src) {
1252 #if defined(V8_COMPRESS_POINTERS) || defined(V8_31BIT_SMIS_ON_64BIT_ARCH)
1253 STATIC_ASSERT(kSmiTag == 0 && kSmiShift < kSystemPointerSizeLog2);
1254 ShiftLeftP(dst, src, Operand(kSystemPointerSizeLog2 - kSmiShift));
1255 #else
1256 STATIC_ASSERT(kSmiTag == 0 && kSmiShift > kSystemPointerSizeLog2);
1257 ShiftRightArithP(dst, src, Operand(kSmiShift - kSystemPointerSizeLog2));
1258 #endif
1259 }
1260
1261 // Jump if either of the registers contain a non-smi.
JumpIfNotSmi(Register value,Label * not_smi_label)1262 inline void JumpIfNotSmi(Register value, Label* not_smi_label) {
1263 TestIfSmi(value);
1264 bne(not_smi_label /*, cr0*/);
1265 }
1266
1267 // Abort execution if argument is a smi, enabled via --debug-code.
1268 void AssertNotSmi(Register object);
1269 void AssertSmi(Register object);
1270
1271 #if !defined(V8_COMPRESS_POINTERS) && !defined(V8_31BIT_SMIS_ON_64BIT_ARCH)
1272 // Ensure it is permissible to read/write int value directly from
1273 // upper half of the smi.
1274 STATIC_ASSERT(kSmiTag == 0);
1275 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 32);
1276 #endif
1277 #if V8_TARGET_LITTLE_ENDIAN
1278 #define SmiWordOffset(offset) (offset + kSystemPointerSize / 2)
1279 #else
1280 #define SmiWordOffset(offset) offset
1281 #endif
1282
1283 // Abort execution if argument is not a Constructor, enabled via --debug-code.
1284 void AssertConstructor(Register object, Register scratch);
1285
1286 // Abort execution if argument is not a JSFunction, enabled via --debug-code.
1287 void AssertFunction(Register object);
1288
1289 // Abort execution if argument is not a JSBoundFunction,
1290 // enabled via --debug-code.
1291 void AssertBoundFunction(Register object);
1292
1293 // Abort execution if argument is not a JSGeneratorObject (or subclass),
1294 // enabled via --debug-code.
1295 void AssertGeneratorObject(Register object);
1296
1297 // Abort execution if argument is not undefined or an AllocationSite, enabled
1298 // via --debug-code.
1299 void AssertUndefinedOrAllocationSite(Register object, Register scratch);
1300
1301 template <typename Field>
DecodeField(Register dst,Register src)1302 void DecodeField(Register dst, Register src) {
1303 ExtractBitRange(dst, src, Field::kShift + Field::kSize - 1, Field::kShift);
1304 }
1305
1306 template <typename Field>
DecodeField(Register reg)1307 void DecodeField(Register reg) {
1308 DecodeField<Field>(reg, reg);
1309 }
1310
1311 // ---------------------------------------------------------------------------
1312 // GC Support
1313
1314 void IncrementalMarkingRecordWriteHelper(Register object, Register value,
1315 Register address);
1316
1317 void CallJSEntry(Register target);
1318 static int CallSizeNotPredictableCodeSize(Address target,
1319 RelocInfo::Mode rmode,
1320 Condition cond = al);
1321 // Notify the garbage collector that we wrote a pointer into an object.
1322 // |object| is the object being stored into, |value| is the object being
1323 // stored. value and scratch registers are clobbered by the operation.
1324 // The offset is the offset from the start of the object, not the offset from
1325 // the tagged HeapObject pointer. For use with FieldMemOperand(reg, off).
1326 void RecordWriteField(
1327 Register object, int offset, Register value, Register scratch,
1328 LinkRegisterStatus lr_status, SaveFPRegsMode save_fp,
1329 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
1330 SmiCheck smi_check = INLINE_SMI_CHECK);
1331
1332 // For a given |object| notify the garbage collector that the slot |address|
1333 // has been written. |value| is the object being stored. The value and
1334 // address registers are clobbered by the operation.
1335 void RecordWrite(
1336 Register object, Register address, Register value,
1337 LinkRegisterStatus lr_status, SaveFPRegsMode save_fp,
1338 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
1339 SmiCheck smi_check = INLINE_SMI_CHECK);
1340
1341 private:
1342 static const int kSmiShift = kSmiTagSize + kSmiShiftSize;
1343 // Helper functions for generating invokes.
1344 void InvokePrologue(Register expected_parameter_count,
1345 Register actual_parameter_count, Label* done,
1346 InvokeFlag flag);
1347
1348 DISALLOW_IMPLICIT_CONSTRUCTORS(MacroAssembler);
1349 };
1350
1351 #define ACCESS_MASM(masm) masm->
1352
1353 } // namespace internal
1354 } // namespace v8
1355
1356 #endif // V8_CODEGEN_S390_MACRO_ASSEMBLER_S390_H_
1357