blob: e84d69525198ea0a02aa239506fa62cb714e19a1 [file] [log] [blame]
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001// Copyright (c) 1994-2006 Sun Microsystems Inc.
2// All Rights Reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions
6// are met:
7//
8// - Redistributions of source code must retain the above copyright notice,
9// this list of conditions and the following disclaimer.
10//
11// - Redistribution in binary form must reproduce the above copyright
12// notice, this list of conditions and the following disclaimer in the
13// documentation and/or other materials provided with the
14// distribution.
15//
16// - Neither the name of Sun Microsystems or the names of contributors may
17// be used to endorse or promote products derived from this software without
18// specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31// OF THE POSSIBILITY OF SUCH DAMAGE.
32
33// The original source code covered by the above license above has been
34// modified significantly by Google Inc.
35// Copyright 2014 the V8 project authors. All rights reserved.
36
37// A light-weight PPC Assembler
38// Generates user mode instructions for the PPC architecture up
39
40#ifndef V8_PPC_ASSEMBLER_PPC_H_
41#define V8_PPC_ASSEMBLER_PPC_H_
42
43#include <stdio.h>
44#include <vector>
45
46#include "src/assembler.h"
47#include "src/ppc/constants-ppc.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040048
49#define ABI_USES_FUNCTION_DESCRIPTORS \
50 (V8_HOST_ARCH_PPC && (V8_OS_AIX || \
51 (V8_TARGET_ARCH_PPC64 && V8_TARGET_BIG_ENDIAN)))
52
53#define ABI_PASSES_HANDLES_IN_REGS \
54 (!V8_HOST_ARCH_PPC || V8_OS_AIX || V8_TARGET_ARCH_PPC64)
55
Emily Bernierd0a1eb72015-03-24 16:35:39 -040056#define ABI_RETURNS_OBJECT_PAIRS_IN_REGS \
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000057 (!V8_HOST_ARCH_PPC || !V8_TARGET_ARCH_PPC64 || V8_TARGET_LITTLE_ENDIAN)
Emily Bernierd0a1eb72015-03-24 16:35:39 -040058
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000059#if !V8_HOST_ARCH_PPC || (V8_TARGET_ARCH_PPC64 && V8_TARGET_LITTLE_ENDIAN)
60#define ABI_CALL_VIA_IP 1
61#else
62#define ABI_CALL_VIA_IP 0
63#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -040064
65#if !V8_HOST_ARCH_PPC || V8_OS_AIX || V8_TARGET_ARCH_PPC64
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000066#define ABI_TOC_REGISTER Register::kCode_r2
Emily Bernierd0a1eb72015-03-24 16:35:39 -040067#else
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000068#define ABI_TOC_REGISTER Register::kCode_r13
Emily Bernierd0a1eb72015-03-24 16:35:39 -040069#endif
70
71#define INSTR_AND_DATA_CACHE_COHERENCY LWSYNC
72
73namespace v8 {
74namespace internal {
75
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000076// clang-format off
77#define GENERAL_REGISTERS(V) \
78 V(r0) V(sp) V(r2) V(r3) V(r4) V(r5) V(r6) V(r7) \
79 V(r8) V(r9) V(r10) V(r11) V(ip) V(r13) V(r14) V(r15) \
80 V(r16) V(r17) V(r18) V(r19) V(r20) V(r21) V(r22) V(r23) \
81 V(r24) V(r25) V(r26) V(r27) V(r28) V(r29) V(r30) V(fp)
82
83#if V8_EMBEDDED_CONSTANT_POOL
84#define ALLOCATABLE_GENERAL_REGISTERS(V) \
85 V(r3) V(r4) V(r5) V(r6) V(r7) \
86 V(r8) V(r9) V(r10) V(r14) V(r15) \
87 V(r16) V(r17) V(r18) V(r19) V(r20) V(r21) V(r22) V(r23) \
88 V(r24) V(r25) V(r26) V(r27) V(r30)
89#else
90#define ALLOCATABLE_GENERAL_REGISTERS(V) \
91 V(r3) V(r4) V(r5) V(r6) V(r7) \
92 V(r8) V(r9) V(r10) V(r14) V(r15) \
93 V(r16) V(r17) V(r18) V(r19) V(r20) V(r21) V(r22) V(r23) \
94 V(r24) V(r25) V(r26) V(r27) V(r28) V(r30)
95#endif
96
97#define DOUBLE_REGISTERS(V) \
98 V(d0) V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
99 V(d8) V(d9) V(d10) V(d11) V(d12) V(d13) V(d14) V(d15) \
100 V(d16) V(d17) V(d18) V(d19) V(d20) V(d21) V(d22) V(d23) \
101 V(d24) V(d25) V(d26) V(d27) V(d28) V(d29) V(d30) V(d31)
102
103#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
104 V(d1) V(d2) V(d3) V(d4) V(d5) V(d6) V(d7) \
105 V(d8) V(d9) V(d10) V(d11) V(d12) V(d15) \
106 V(d16) V(d17) V(d18) V(d19) V(d20) V(d21) V(d22) V(d23) \
107 V(d24) V(d25) V(d26) V(d27) V(d28) V(d29) V(d30) V(d31)
108// clang-format on
109
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400110// CPU Registers.
111//
112// 1) We would prefer to use an enum, but enum values are assignment-
113// compatible with int, which has caused code-generation bugs.
114//
115// 2) We would prefer to use a class instead of a struct but we don't like
116// the register initialization to depend on the particular initialization
117// order (which appears to be different on OS X, Linux, and Windows for the
118// installed versions of C++ we tried). Using a struct permits C-style
119// "initialization". Also, the Register objects cannot be const as this
120// forces initialization stubs in MSVC, making us dependent on initialization
121// order.
122//
123// 3) By not using an enum, we are possibly preventing the compiler from
124// doing certain constant folds, which may significantly reduce the
125// code generated for some assembly instructions (because they boil down
126// to a few constants). If this is a problem, we could change the code
127// such that we use an enum in optimized mode, and the struct in debug
128// mode. This way we get the compile-time error checking in debug mode
129// and best performance in optimized code.
130
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400131struct Register {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000132 enum Code {
133#define REGISTER_CODE(R) kCode_##R,
134 GENERAL_REGISTERS(REGISTER_CODE)
135#undef REGISTER_CODE
136 kAfterLast,
137 kCode_no_reg = -1
138 };
139
140 static const int kNumRegisters = Code::kAfterLast;
141
142#define REGISTER_COUNT(R) 1 +
143 static const int kNumAllocatable =
144 ALLOCATABLE_GENERAL_REGISTERS(REGISTER_COUNT)0;
145#undef REGISTER_COUNT
146
147#define REGISTER_BIT(R) 1 << kCode_##R |
148 static const RegList kAllocatable =
149 ALLOCATABLE_GENERAL_REGISTERS(REGISTER_BIT)0;
150#undef REGISTER_BIT
151
152 static Register from_code(int code) {
153 DCHECK(code >= 0);
154 DCHECK(code < kNumRegisters);
155 Register r = {code};
156 return r;
157 }
158 const char* ToString();
159 bool IsAllocatable() const;
160 bool is_valid() const { return 0 <= reg_code && reg_code < kNumRegisters; }
161 bool is(Register reg) const { return reg_code == reg.reg_code; }
162 int code() const {
163 DCHECK(is_valid());
164 return reg_code;
165 }
166 int bit() const {
167 DCHECK(is_valid());
168 return 1 << reg_code;
169 }
170 void set_code(int code) {
171 reg_code = code;
172 DCHECK(is_valid());
173 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400174
175#if V8_TARGET_LITTLE_ENDIAN
176 static const int kMantissaOffset = 0;
177 static const int kExponentOffset = 4;
178#else
179 static const int kMantissaOffset = 4;
180 static const int kExponentOffset = 0;
181#endif
182
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400183 // Unfortunately we can't make this private in a struct.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000184 int reg_code;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400185};
186
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000187#define DECLARE_REGISTER(R) const Register R = {Register::kCode_##R};
188GENERAL_REGISTERS(DECLARE_REGISTER)
189#undef DECLARE_REGISTER
190const Register no_reg = {Register::kCode_no_reg};
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400191
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000192// Aliases
193const Register kLithiumScratch = r11; // lithium scratch.
194const Register kConstantPoolRegister = r28; // Constant pool.
195const Register kRootRegister = r29; // Roots array pointer.
196const Register cp = r30; // JavaScript context pointer.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400197
198// Double word FP register.
199struct DoubleRegister {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000200 enum Code {
201#define REGISTER_CODE(R) kCode_##R,
202 DOUBLE_REGISTERS(REGISTER_CODE)
203#undef REGISTER_CODE
204 kAfterLast,
205 kCode_no_reg = -1
206 };
207
208 static const int kNumRegisters = Code::kAfterLast;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400209 static const int kMaxNumRegisters = kNumRegisters;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400210
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000211 const char* ToString();
212 bool IsAllocatable() const;
213 bool is_valid() const { return 0 <= reg_code && reg_code < kNumRegisters; }
214 bool is(DoubleRegister reg) const { return reg_code == reg.reg_code; }
215 int code() const {
216 DCHECK(is_valid());
217 return reg_code;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400218 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000219 int bit() const {
220 DCHECK(is_valid());
221 return 1 << reg_code;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400222 }
223
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400224 static DoubleRegister from_code(int code) {
225 DoubleRegister r = {code};
226 return r;
227 }
228
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000229 int reg_code;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400230};
231
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000232#define DECLARE_REGISTER(R) \
233 const DoubleRegister R = {DoubleRegister::kCode_##R};
234DOUBLE_REGISTERS(DECLARE_REGISTER)
235#undef DECLARE_REGISTER
236const Register no_dreg = {Register::kCode_no_reg};
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400237
238// Aliases for double registers. Defined using #define instead of
239// "static const DoubleRegister&" because Clang complains otherwise when a
240// compilation unit that includes this header doesn't use the variables.
241#define kFirstCalleeSavedDoubleReg d14
242#define kLastCalleeSavedDoubleReg d31
243#define kDoubleRegZero d14
244#define kScratchDoubleReg d13
245
246Register ToRegister(int num);
247
248// Coprocessor register
249struct CRegister {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000250 bool is_valid() const { return 0 <= reg_code && reg_code < 16; }
251 bool is(CRegister creg) const { return reg_code == creg.reg_code; }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400252 int code() const {
253 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000254 return reg_code;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400255 }
256 int bit() const {
257 DCHECK(is_valid());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000258 return 1 << reg_code;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400259 }
260
261 // Unfortunately we can't make this private in a struct.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000262 int reg_code;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400263};
264
265
266const CRegister no_creg = {-1};
267
268const CRegister cr0 = {0};
269const CRegister cr1 = {1};
270const CRegister cr2 = {2};
271const CRegister cr3 = {3};
272const CRegister cr4 = {4};
273const CRegister cr5 = {5};
274const CRegister cr6 = {6};
275const CRegister cr7 = {7};
276const CRegister cr8 = {8};
277const CRegister cr9 = {9};
278const CRegister cr10 = {10};
279const CRegister cr11 = {11};
280const CRegister cr12 = {12};
281const CRegister cr13 = {13};
282const CRegister cr14 = {14};
283const CRegister cr15 = {15};
284
285// -----------------------------------------------------------------------------
286// Machine instruction Operands
287
288#if V8_TARGET_ARCH_PPC64
289const RelocInfo::Mode kRelocInfo_NONEPTR = RelocInfo::NONE64;
290#else
291const RelocInfo::Mode kRelocInfo_NONEPTR = RelocInfo::NONE32;
292#endif
293
294// Class Operand represents a shifter operand in data processing instructions
295class Operand BASE_EMBEDDED {
296 public:
297 // immediate
298 INLINE(explicit Operand(intptr_t immediate,
299 RelocInfo::Mode rmode = kRelocInfo_NONEPTR));
300 INLINE(static Operand Zero()) { return Operand(static_cast<intptr_t>(0)); }
301 INLINE(explicit Operand(const ExternalReference& f));
302 explicit Operand(Handle<Object> handle);
303 INLINE(explicit Operand(Smi* value));
304
305 // rm
306 INLINE(explicit Operand(Register rm));
307
308 // Return true if this is a register operand.
309 INLINE(bool is_reg() const);
310
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400311 bool must_output_reloc_info(const Assembler* assembler) const;
312
313 inline intptr_t immediate() const {
314 DCHECK(!rm_.is_valid());
315 return imm_;
316 }
317
318 Register rm() const { return rm_; }
319
320 private:
321 Register rm_;
322 intptr_t imm_; // valid if rm_ == no_reg
323 RelocInfo::Mode rmode_;
324
325 friend class Assembler;
326 friend class MacroAssembler;
327};
328
329
330// Class MemOperand represents a memory operand in load and store instructions
331// On PowerPC we have base register + 16bit signed value
332// Alternatively we can have a 16bit signed value immediate
333class MemOperand BASE_EMBEDDED {
334 public:
335 explicit MemOperand(Register rn, int32_t offset = 0);
336
337 explicit MemOperand(Register ra, Register rb);
338
339 int32_t offset() const {
340 DCHECK(rb_.is(no_reg));
341 return offset_;
342 }
343
344 // PowerPC - base register
345 Register ra() const {
346 DCHECK(!ra_.is(no_reg));
347 return ra_;
348 }
349
350 Register rb() const {
351 DCHECK(offset_ == 0 && !rb_.is(no_reg));
352 return rb_;
353 }
354
355 private:
356 Register ra_; // base
357 int32_t offset_; // offset
358 Register rb_; // index
359
360 friend class Assembler;
361};
362
363
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000364class DeferredRelocInfo {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400365 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000366 DeferredRelocInfo() {}
367 DeferredRelocInfo(int position, RelocInfo::Mode rmode, intptr_t data)
368 : position_(position), rmode_(rmode), data_(data) {}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400369
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000370 int position() const { return position_; }
371 RelocInfo::Mode rmode() const { return rmode_; }
372 intptr_t data() const { return data_; }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400373
374 private:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000375 int position_;
376 RelocInfo::Mode rmode_;
377 intptr_t data_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400378};
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400379
380
381class Assembler : public AssemblerBase {
382 public:
383 // Create an assembler. Instructions and relocation information are emitted
384 // into a buffer, with the instructions starting from the beginning and the
385 // relocation information starting from the end of the buffer. See CodeDesc
386 // for a detailed comment on the layout (globals.h).
387 //
388 // If the provided buffer is NULL, the assembler allocates and grows its own
389 // buffer, and buffer_size determines the initial buffer size. The buffer is
390 // owned by the assembler and deallocated upon destruction of the assembler.
391 //
392 // If the provided buffer is not NULL, the assembler uses the provided buffer
393 // for code generation and assumes its size to be buffer_size. If the buffer
394 // is too small, a fatal error occurs. No deallocation of the buffer is done
395 // upon destruction of the assembler.
396 Assembler(Isolate* isolate, void* buffer, int buffer_size);
397 virtual ~Assembler() {}
398
399 // GetCode emits any pending (non-emitted) code and fills the descriptor
400 // desc. GetCode() is idempotent; it returns the same result if no other
401 // Assembler functions are invoked in between GetCode() calls.
402 void GetCode(CodeDesc* desc);
403
404 // Label operations & relative jumps (PPUM Appendix D)
405 //
406 // Takes a branch opcode (cc) and a label (L) and generates
407 // either a backward branch or a forward branch and links it
408 // to the label fixup chain. Usage:
409 //
410 // Label L; // unbound label
411 // j(cc, &L); // forward branch to unbound label
412 // bind(&L); // bind label to the current pc
413 // j(cc, &L); // backward branch to bound label
414 // bind(&L); // illegal: a label may be bound only once
415 //
416 // Note: The same Label can be used for forward and backward branches
417 // but it may be bound only once.
418
419 void bind(Label* L); // binds an unbound label L to the current code position
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000420
421 // Links a label at the current pc_offset(). If already bound, returns the
422 // bound position. If already linked, returns the position of the prior link.
423 // Otherwise, returns the current pc_offset().
424 int link(Label* L);
425
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400426 // Determines if Label is bound and near enough so that a single
427 // branch instruction can be used to reach it.
428 bool is_near(Label* L, Condition cond);
429
430 // Returns the branch offset to the given label from the current code position
431 // Links the label to the current position if it is still unbound
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000432 int branch_offset(Label* L) {
433 if (L->is_unused() && !trampoline_emitted_) {
434 TrackBranch();
435 }
436 return link(L) - pc_offset();
437 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400438
439 // Puts a labels target address at the given position.
440 // The high 8 bits are set to zero.
441 void label_at_put(Label* L, int at_offset);
442
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000443 INLINE(static bool IsConstantPoolLoadStart(
444 Address pc, ConstantPoolEntry::Access* access = nullptr));
445 INLINE(static bool IsConstantPoolLoadEnd(
446 Address pc, ConstantPoolEntry::Access* access = nullptr));
447 INLINE(static int GetConstantPoolOffset(Address pc,
448 ConstantPoolEntry::Access access,
449 ConstantPoolEntry::Type type));
450 INLINE(void PatchConstantPoolAccessInstruction(
451 int pc_offset, int offset, ConstantPoolEntry::Access access,
452 ConstantPoolEntry::Type type));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400453
454 // Return the address in the constant pool of the code target address used by
455 // the branch/call instruction at pc, or the object in a mov.
456 INLINE(static Address target_constant_pool_address_at(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000457 Address pc, Address constant_pool, ConstantPoolEntry::Access access,
458 ConstantPoolEntry::Type type));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400459
460 // Read/Modify the code target address in the branch/call instruction at pc.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000461 INLINE(static Address target_address_at(Address pc, Address constant_pool));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400462 INLINE(static void set_target_address_at(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000463 Isolate* isolate, Address pc, Address constant_pool, Address target,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400464 ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED));
465 INLINE(static Address target_address_at(Address pc, Code* code)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000466 Address constant_pool = code ? code->constant_pool() : NULL;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400467 return target_address_at(pc, constant_pool);
468 }
469 INLINE(static void set_target_address_at(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000470 Isolate* isolate, Address pc, Code* code, Address target,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400471 ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000472 Address constant_pool = code ? code->constant_pool() : NULL;
473 set_target_address_at(isolate, pc, constant_pool, target,
474 icache_flush_mode);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400475 }
476
477 // Return the code target address at a call site from the return address
478 // of that call in the instruction stream.
479 inline static Address target_address_from_return_address(Address pc);
480
481 // Given the address of the beginning of a call, return the address
482 // in the instruction stream that the call will return to.
483 INLINE(static Address return_address_from_call_start(Address pc));
484
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400485 // This sets the branch destination.
486 // This is for calls and branches within generated code.
487 inline static void deserialization_set_special_target_at(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000488 Isolate* isolate, Address instruction_payload, Code* code,
489 Address target);
490
491 // This sets the internal reference at the pc.
492 inline static void deserialization_set_target_internal_reference_at(
493 Isolate* isolate, Address pc, Address target,
494 RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400495
496 // Size of an instruction.
497 static const int kInstrSize = sizeof(Instr);
498
499 // Here we are patching the address in the LUI/ORI instruction pair.
500 // These values are used in the serialization process and must be zero for
501 // PPC platform, as Code, Embedded Object or External-reference pointers
502 // are split across two consecutive instructions and don't exist separately
503 // in the code, so the serializer should not step forwards in memory after
504 // a target is resolved and written.
505 static const int kSpecialTargetSize = 0;
506
507// Number of instructions to load an address via a mov sequence.
508#if V8_TARGET_ARCH_PPC64
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000509 static const int kMovInstructionsConstantPool = 1;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400510 static const int kMovInstructionsNoConstantPool = 5;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000511#if defined(V8_PPC_TAGGING_OPT)
512 static const int kTaggedLoadInstructions = 1;
513#else
514 static const int kTaggedLoadInstructions = 2;
515#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400516#else
517 static const int kMovInstructionsConstantPool = 1;
518 static const int kMovInstructionsNoConstantPool = 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000519 static const int kTaggedLoadInstructions = 1;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400520#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000521 static const int kMovInstructions = FLAG_enable_embedded_constant_pool
522 ? kMovInstructionsConstantPool
523 : kMovInstructionsNoConstantPool;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400524
525 // Distance between the instruction referring to the address of the call
526 // target and the return address.
527
528 // Call sequence is a FIXED_SEQUENCE:
529 // mov r8, @ call address
530 // mtlr r8
531 // blrl
532 // @ return address
533 static const int kCallTargetAddressOffset =
534 (kMovInstructions + 2) * kInstrSize;
535
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400536 // Distance between start of patched debug break slot and the emitted address
537 // to jump to.
538 // Patched debug break slot code is a FIXED_SEQUENCE:
539 // mov r0, <address>
540 // mtlr r0
541 // blrl
542 static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
543
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400544 // This is the length of the code sequence from SetDebugBreakAtSlot()
545 // FIXED_SEQUENCE
546 static const int kDebugBreakSlotInstructions =
547 kMovInstructionsNoConstantPool + 2;
548 static const int kDebugBreakSlotLength =
549 kDebugBreakSlotInstructions * kInstrSize;
550
551 static inline int encode_crbit(const CRegister& cr, enum CRBit crbit) {
552 return ((cr.code() * CRWIDTH) + crbit);
553 }
554
555 // ---------------------------------------------------------------------------
556 // Code generation
557
558 // Insert the smallest number of nop instructions
559 // possible to align the pc offset to a multiple
560 // of m. m must be a power of 2 (>= 4).
561 void Align(int m);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000562 // Insert the smallest number of zero bytes possible to align the pc offset
563 // to a mulitple of m. m must be a power of 2 (>= 2).
564 void DataAlign(int m);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400565 // Aligns code to something that's optimal for a jump target for the platform.
566 void CodeTargetAlign();
567
568 // Branch instructions
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000569 void bclr(BOfield bo, int condition_bit, LKBit lk);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400570 void blr();
571 void bc(int branch_offset, BOfield bo, int condition_bit, LKBit lk = LeaveLK);
572 void b(int branch_offset, LKBit lk);
573
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000574 void bcctr(BOfield bo, int condition_bit, LKBit lk);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400575 void bctr();
576 void bctrl();
577
578 // Convenience branch instructions using labels
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000579 void b(Label* L, LKBit lk = LeaveLK) { b(branch_offset(L), lk); }
580
581 inline CRegister cmpi_optimization(CRegister cr) {
582 // Check whether the branch is preceeded by an optimizable cmpi against 0.
583 // The cmpi can be deleted if it is also preceeded by an instruction that
584 // sets the register used by the compare and supports a dot form.
585 unsigned int sradi_mask = kOpcodeMask | kExt2OpcodeVariant2Mask;
586 unsigned int srawi_mask = kOpcodeMask | kExt2OpcodeMask;
587 int pos = pc_offset();
588 int cmpi_pos = pc_offset() - kInstrSize;
589
590 if (cmpi_pos > 0 && optimizable_cmpi_pos_ == cmpi_pos &&
591 cmpi_cr_.code() == cr.code() && last_bound_pos_ != pos) {
592 int xpos = cmpi_pos - kInstrSize;
593 int xinstr = instr_at(xpos);
594 int cmpi_ra = (instr_at(cmpi_pos) & 0x1f0000) >> 16;
595 // ra is at the same bit position for the three cases below.
596 int ra = (xinstr & 0x1f0000) >> 16;
597 if (cmpi_ra == ra) {
598 if ((xinstr & sradi_mask) == (EXT2 | SRADIX)) {
599 cr = cr0;
600 instr_at_put(xpos, xinstr | SetRC);
601 pc_ -= kInstrSize;
602 } else if ((xinstr & srawi_mask) == (EXT2 | SRAWIX)) {
603 cr = cr0;
604 instr_at_put(xpos, xinstr | SetRC);
605 pc_ -= kInstrSize;
606 } else if ((xinstr & kOpcodeMask) == ANDIx) {
607 cr = cr0;
608 pc_ -= kInstrSize;
609 // nothing to do here since andi. records.
610 }
611 // didn't match one of the above, must keep cmpwi.
612 }
613 }
614 return cr;
615 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400616
617 void bc_short(Condition cond, Label* L, CRegister cr = cr7,
618 LKBit lk = LeaveLK) {
619 DCHECK(cond != al);
620 DCHECK(cr.code() >= 0 && cr.code() <= 7);
621
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000622 cr = cmpi_optimization(cr);
623
624 int b_offset = branch_offset(L);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400625
626 switch (cond) {
627 case eq:
628 bc(b_offset, BT, encode_crbit(cr, CR_EQ), lk);
629 break;
630 case ne:
631 bc(b_offset, BF, encode_crbit(cr, CR_EQ), lk);
632 break;
633 case gt:
634 bc(b_offset, BT, encode_crbit(cr, CR_GT), lk);
635 break;
636 case le:
637 bc(b_offset, BF, encode_crbit(cr, CR_GT), lk);
638 break;
639 case lt:
640 bc(b_offset, BT, encode_crbit(cr, CR_LT), lk);
641 break;
642 case ge:
643 bc(b_offset, BF, encode_crbit(cr, CR_LT), lk);
644 break;
645 case unordered:
646 bc(b_offset, BT, encode_crbit(cr, CR_FU), lk);
647 break;
648 case ordered:
649 bc(b_offset, BF, encode_crbit(cr, CR_FU), lk);
650 break;
651 case overflow:
652 bc(b_offset, BT, encode_crbit(cr, CR_SO), lk);
653 break;
654 case nooverflow:
655 bc(b_offset, BF, encode_crbit(cr, CR_SO), lk);
656 break;
657 default:
658 UNIMPLEMENTED();
659 }
660 }
661
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000662 void bclr(Condition cond, CRegister cr = cr7, LKBit lk = LeaveLK) {
663 DCHECK(cond != al);
664 DCHECK(cr.code() >= 0 && cr.code() <= 7);
665
666 cr = cmpi_optimization(cr);
667
668 switch (cond) {
669 case eq:
670 bclr(BT, encode_crbit(cr, CR_EQ), lk);
671 break;
672 case ne:
673 bclr(BF, encode_crbit(cr, CR_EQ), lk);
674 break;
675 case gt:
676 bclr(BT, encode_crbit(cr, CR_GT), lk);
677 break;
678 case le:
679 bclr(BF, encode_crbit(cr, CR_GT), lk);
680 break;
681 case lt:
682 bclr(BT, encode_crbit(cr, CR_LT), lk);
683 break;
684 case ge:
685 bclr(BF, encode_crbit(cr, CR_LT), lk);
686 break;
687 case unordered:
688 bclr(BT, encode_crbit(cr, CR_FU), lk);
689 break;
690 case ordered:
691 bclr(BF, encode_crbit(cr, CR_FU), lk);
692 break;
693 case overflow:
694 bclr(BT, encode_crbit(cr, CR_SO), lk);
695 break;
696 case nooverflow:
697 bclr(BF, encode_crbit(cr, CR_SO), lk);
698 break;
699 default:
700 UNIMPLEMENTED();
701 }
702 }
703
704 void isel(Register rt, Register ra, Register rb, int cb);
705 void isel(Condition cond, Register rt, Register ra, Register rb,
706 CRegister cr = cr7) {
707 DCHECK(cond != al);
708 DCHECK(cr.code() >= 0 && cr.code() <= 7);
709
710 cr = cmpi_optimization(cr);
711
712 switch (cond) {
713 case eq:
714 isel(rt, ra, rb, encode_crbit(cr, CR_EQ));
715 break;
716 case ne:
717 isel(rt, rb, ra, encode_crbit(cr, CR_EQ));
718 break;
719 case gt:
720 isel(rt, ra, rb, encode_crbit(cr, CR_GT));
721 break;
722 case le:
723 isel(rt, rb, ra, encode_crbit(cr, CR_GT));
724 break;
725 case lt:
726 isel(rt, ra, rb, encode_crbit(cr, CR_LT));
727 break;
728 case ge:
729 isel(rt, rb, ra, encode_crbit(cr, CR_LT));
730 break;
731 case unordered:
732 isel(rt, ra, rb, encode_crbit(cr, CR_FU));
733 break;
734 case ordered:
735 isel(rt, rb, ra, encode_crbit(cr, CR_FU));
736 break;
737 case overflow:
738 isel(rt, ra, rb, encode_crbit(cr, CR_SO));
739 break;
740 case nooverflow:
741 isel(rt, rb, ra, encode_crbit(cr, CR_SO));
742 break;
743 default:
744 UNIMPLEMENTED();
745 }
746 }
747
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400748 void b(Condition cond, Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
749 if (cond == al) {
750 b(L, lk);
751 return;
752 }
753
754 if ((L->is_bound() && is_near(L, cond)) || !is_trampoline_emitted()) {
755 bc_short(cond, L, cr, lk);
756 return;
757 }
758
759 Label skip;
760 Condition neg_cond = NegateCondition(cond);
761 bc_short(neg_cond, &skip, cr);
762 b(L, lk);
763 bind(&skip);
764 }
765
766 void bne(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
767 b(ne, L, cr, lk);
768 }
769 void beq(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
770 b(eq, L, cr, lk);
771 }
772 void blt(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
773 b(lt, L, cr, lk);
774 }
775 void bge(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
776 b(ge, L, cr, lk);
777 }
778 void ble(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
779 b(le, L, cr, lk);
780 }
781 void bgt(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
782 b(gt, L, cr, lk);
783 }
784 void bunordered(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
785 b(unordered, L, cr, lk);
786 }
787 void bordered(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) {
788 b(ordered, L, cr, lk);
789 }
790 void boverflow(Label* L, CRegister cr = cr0, LKBit lk = LeaveLK) {
791 b(overflow, L, cr, lk);
792 }
793 void bnooverflow(Label* L, CRegister cr = cr0, LKBit lk = LeaveLK) {
794 b(nooverflow, L, cr, lk);
795 }
796
797 // Decrement CTR; branch if CTR != 0
798 void bdnz(Label* L, LKBit lk = LeaveLK) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000799 bc(branch_offset(L), DCBNZ, 0, lk);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400800 }
801
802 // Data-processing instructions
803
804 void sub(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
805 RCBit r = LeaveRC);
806
807 void subfic(Register dst, Register src, const Operand& imm);
808
809 void subfc(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
810 RCBit r = LeaveRC);
811
812 void add(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
813 RCBit r = LeaveRC);
814
815 void addc(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
816 RCBit r = LeaveRC);
817
818 void addze(Register dst, Register src1, OEBit o, RCBit r);
819
820 void mullw(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
821 RCBit r = LeaveRC);
822
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000823 void mulhw(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
824 void mulhwu(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400825
826 void divw(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
827 RCBit r = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000828 void divwu(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
829 RCBit r = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400830
831 void addi(Register dst, Register src, const Operand& imm);
832 void addis(Register dst, Register src, const Operand& imm);
833 void addic(Register dst, Register src, const Operand& imm);
834
835 void and_(Register dst, Register src1, Register src2, RCBit rc = LeaveRC);
836 void andc(Register dst, Register src1, Register src2, RCBit rc = LeaveRC);
837 void andi(Register ra, Register rs, const Operand& imm);
838 void andis(Register ra, Register rs, const Operand& imm);
839 void nor(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
840 void notx(Register dst, Register src, RCBit r = LeaveRC);
841 void ori(Register dst, Register src, const Operand& imm);
842 void oris(Register dst, Register src, const Operand& imm);
843 void orx(Register dst, Register src1, Register src2, RCBit rc = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000844 void orc(Register dst, Register src1, Register src2, RCBit rc = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400845 void xori(Register dst, Register src, const Operand& imm);
846 void xoris(Register ra, Register rs, const Operand& imm);
847 void xor_(Register dst, Register src1, Register src2, RCBit rc = LeaveRC);
848 void cmpi(Register src1, const Operand& src2, CRegister cr = cr7);
849 void cmpli(Register src1, const Operand& src2, CRegister cr = cr7);
850 void cmpwi(Register src1, const Operand& src2, CRegister cr = cr7);
851 void cmplwi(Register src1, const Operand& src2, CRegister cr = cr7);
852 void li(Register dst, const Operand& src);
853 void lis(Register dst, const Operand& imm);
854 void mr(Register dst, Register src);
855
856 void lbz(Register dst, const MemOperand& src);
857 void lbzx(Register dst, const MemOperand& src);
858 void lbzux(Register dst, const MemOperand& src);
859 void lhz(Register dst, const MemOperand& src);
860 void lhzx(Register dst, const MemOperand& src);
861 void lhzux(Register dst, const MemOperand& src);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000862 void lha(Register dst, const MemOperand& src);
863 void lhax(Register dst, const MemOperand& src);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400864 void lwz(Register dst, const MemOperand& src);
865 void lwzu(Register dst, const MemOperand& src);
866 void lwzx(Register dst, const MemOperand& src);
867 void lwzux(Register dst, const MemOperand& src);
868 void lwa(Register dst, const MemOperand& src);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000869 void lwax(Register dst, const MemOperand& src);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400870 void stb(Register dst, const MemOperand& src);
871 void stbx(Register dst, const MemOperand& src);
872 void stbux(Register dst, const MemOperand& src);
873 void sth(Register dst, const MemOperand& src);
874 void sthx(Register dst, const MemOperand& src);
875 void sthux(Register dst, const MemOperand& src);
876 void stw(Register dst, const MemOperand& src);
877 void stwu(Register dst, const MemOperand& src);
878 void stwx(Register rs, const MemOperand& src);
879 void stwux(Register rs, const MemOperand& src);
880
881 void extsb(Register rs, Register ra, RCBit r = LeaveRC);
882 void extsh(Register rs, Register ra, RCBit r = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000883 void extsw(Register rs, Register ra, RCBit r = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400884
885 void neg(Register rt, Register ra, OEBit o = LeaveOE, RCBit c = LeaveRC);
886
887#if V8_TARGET_ARCH_PPC64
888 void ld(Register rd, const MemOperand& src);
889 void ldx(Register rd, const MemOperand& src);
890 void ldu(Register rd, const MemOperand& src);
891 void ldux(Register rd, const MemOperand& src);
892 void std(Register rs, const MemOperand& src);
893 void stdx(Register rs, const MemOperand& src);
894 void stdu(Register rs, const MemOperand& src);
895 void stdux(Register rs, const MemOperand& src);
896 void rldic(Register dst, Register src, int sh, int mb, RCBit r = LeaveRC);
897 void rldicl(Register dst, Register src, int sh, int mb, RCBit r = LeaveRC);
898 void rldcl(Register ra, Register rs, Register rb, int mb, RCBit r = LeaveRC);
899 void rldicr(Register dst, Register src, int sh, int me, RCBit r = LeaveRC);
900 void rldimi(Register dst, Register src, int sh, int mb, RCBit r = LeaveRC);
901 void sldi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC);
902 void srdi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC);
903 void clrrdi(Register dst, Register src, const Operand& val,
904 RCBit rc = LeaveRC);
905 void clrldi(Register dst, Register src, const Operand& val,
906 RCBit rc = LeaveRC);
907 void sradi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
908 void srd(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
909 void sld(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
910 void srad(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
911 void rotld(Register ra, Register rs, Register rb, RCBit r = LeaveRC);
912 void rotldi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
913 void rotrdi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
914 void cntlzd_(Register dst, Register src, RCBit rc = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000915 void popcntd(Register dst, Register src);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400916 void mulld(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
917 RCBit r = LeaveRC);
918 void divd(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
919 RCBit r = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000920 void divdu(Register dst, Register src1, Register src2, OEBit o = LeaveOE,
921 RCBit r = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400922#endif
923
924 void rlwinm(Register ra, Register rs, int sh, int mb, int me,
925 RCBit rc = LeaveRC);
926 void rlwimi(Register ra, Register rs, int sh, int mb, int me,
927 RCBit rc = LeaveRC);
928 void rlwnm(Register ra, Register rs, Register rb, int mb, int me,
929 RCBit rc = LeaveRC);
930 void slwi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC);
931 void srwi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC);
932 void clrrwi(Register dst, Register src, const Operand& val,
933 RCBit rc = LeaveRC);
934 void clrlwi(Register dst, Register src, const Operand& val,
935 RCBit rc = LeaveRC);
936 void srawi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
937 void srw(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
938 void slw(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
939 void sraw(Register dst, Register src1, Register src2, RCBit r = LeaveRC);
940 void rotlw(Register ra, Register rs, Register rb, RCBit r = LeaveRC);
941 void rotlwi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
942 void rotrwi(Register ra, Register rs, int sh, RCBit r = LeaveRC);
943
944 void cntlzw_(Register dst, Register src, RCBit rc = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000945 void popcntw(Register dst, Register src);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400946
947 void subi(Register dst, Register src1, const Operand& src2);
948
949 void cmp(Register src1, Register src2, CRegister cr = cr7);
950 void cmpl(Register src1, Register src2, CRegister cr = cr7);
951 void cmpw(Register src1, Register src2, CRegister cr = cr7);
952 void cmplw(Register src1, Register src2, CRegister cr = cr7);
953
954 void mov(Register dst, const Operand& src);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000955 void bitwise_mov(Register dst, intptr_t value);
956 void bitwise_mov32(Register dst, int32_t value);
957 void bitwise_add32(Register dst, Register src, int32_t value);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400958
959 // Load the position of the label relative to the generated code object
960 // pointer in a register.
961 void mov_label_offset(Register dst, Label* label);
962
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000963 // dst = base + label position + delta
964 void add_label_offset(Register dst, Register base, Label* label,
965 int delta = 0);
966
967 // Load the address of the label in a register and associate with an
968 // internal reference relocation.
969 void mov_label_addr(Register dst, Label* label);
970
971 // Emit the address of the label (i.e. a jump table entry) and associate with
972 // an internal reference relocation.
973 void emit_label_addr(Label* label);
974
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400975 // Multiply instructions
976 void mul(Register dst, Register src1, Register src2, OEBit s = LeaveOE,
977 RCBit r = LeaveRC);
978
979 // Miscellaneous arithmetic instructions
980
981 // Special register access
982 void crxor(int bt, int ba, int bb);
983 void crclr(int bt) { crxor(bt, bt, bt); }
984 void creqv(int bt, int ba, int bb);
985 void crset(int bt) { creqv(bt, bt, bt); }
986 void mflr(Register dst);
987 void mtlr(Register src);
988 void mtctr(Register src);
989 void mtxer(Register src);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000990 void mcrfs(CRegister cr, FPSCRBit bit);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400991 void mfcr(Register dst);
992#if V8_TARGET_ARCH_PPC64
993 void mffprd(Register dst, DoubleRegister src);
994 void mffprwz(Register dst, DoubleRegister src);
995 void mtfprd(DoubleRegister dst, Register src);
996 void mtfprwz(DoubleRegister dst, Register src);
997 void mtfprwa(DoubleRegister dst, Register src);
998#endif
999
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001000 void function_descriptor();
1001
1002 // Exception-generating instructions and debugging support
1003 void stop(const char* msg, Condition cond = al,
1004 int32_t code = kDefaultStopCode, CRegister cr = cr7);
1005
1006 void bkpt(uint32_t imm16); // v5 and above
1007
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001008 void dcbf(Register ra, Register rb);
1009 void sync();
1010 void lwsync();
1011 void icbi(Register ra, Register rb);
1012 void isync();
1013
1014 // Support for floating point
1015 void lfd(const DoubleRegister frt, const MemOperand& src);
1016 void lfdu(const DoubleRegister frt, const MemOperand& src);
1017 void lfdx(const DoubleRegister frt, const MemOperand& src);
1018 void lfdux(const DoubleRegister frt, const MemOperand& src);
1019 void lfs(const DoubleRegister frt, const MemOperand& src);
1020 void lfsu(const DoubleRegister frt, const MemOperand& src);
1021 void lfsx(const DoubleRegister frt, const MemOperand& src);
1022 void lfsux(const DoubleRegister frt, const MemOperand& src);
1023 void stfd(const DoubleRegister frs, const MemOperand& src);
1024 void stfdu(const DoubleRegister frs, const MemOperand& src);
1025 void stfdx(const DoubleRegister frs, const MemOperand& src);
1026 void stfdux(const DoubleRegister frs, const MemOperand& src);
1027 void stfs(const DoubleRegister frs, const MemOperand& src);
1028 void stfsu(const DoubleRegister frs, const MemOperand& src);
1029 void stfsx(const DoubleRegister frs, const MemOperand& src);
1030 void stfsux(const DoubleRegister frs, const MemOperand& src);
1031
1032 void fadd(const DoubleRegister frt, const DoubleRegister fra,
1033 const DoubleRegister frb, RCBit rc = LeaveRC);
1034 void fsub(const DoubleRegister frt, const DoubleRegister fra,
1035 const DoubleRegister frb, RCBit rc = LeaveRC);
1036 void fdiv(const DoubleRegister frt, const DoubleRegister fra,
1037 const DoubleRegister frb, RCBit rc = LeaveRC);
1038 void fmul(const DoubleRegister frt, const DoubleRegister fra,
1039 const DoubleRegister frc, RCBit rc = LeaveRC);
1040 void fcmpu(const DoubleRegister fra, const DoubleRegister frb,
1041 CRegister cr = cr7);
1042 void fmr(const DoubleRegister frt, const DoubleRegister frb,
1043 RCBit rc = LeaveRC);
1044 void fctiwz(const DoubleRegister frt, const DoubleRegister frb);
1045 void fctiw(const DoubleRegister frt, const DoubleRegister frb);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001046 void frin(const DoubleRegister frt, const DoubleRegister frb,
1047 RCBit rc = LeaveRC);
1048 void friz(const DoubleRegister frt, const DoubleRegister frb,
1049 RCBit rc = LeaveRC);
1050 void frip(const DoubleRegister frt, const DoubleRegister frb,
1051 RCBit rc = LeaveRC);
1052 void frim(const DoubleRegister frt, const DoubleRegister frb,
1053 RCBit rc = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001054 void frsp(const DoubleRegister frt, const DoubleRegister frb,
1055 RCBit rc = LeaveRC);
1056 void fcfid(const DoubleRegister frt, const DoubleRegister frb,
1057 RCBit rc = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001058 void fcfidu(const DoubleRegister frt, const DoubleRegister frb,
1059 RCBit rc = LeaveRC);
1060 void fcfidus(const DoubleRegister frt, const DoubleRegister frb,
1061 RCBit rc = LeaveRC);
1062 void fcfids(const DoubleRegister frt, const DoubleRegister frb,
1063 RCBit rc = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001064 void fctid(const DoubleRegister frt, const DoubleRegister frb,
1065 RCBit rc = LeaveRC);
1066 void fctidz(const DoubleRegister frt, const DoubleRegister frb,
1067 RCBit rc = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001068 void fctidu(const DoubleRegister frt, const DoubleRegister frb,
1069 RCBit rc = LeaveRC);
1070 void fctiduz(const DoubleRegister frt, const DoubleRegister frb,
1071 RCBit rc = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001072 void fsel(const DoubleRegister frt, const DoubleRegister fra,
1073 const DoubleRegister frc, const DoubleRegister frb,
1074 RCBit rc = LeaveRC);
1075 void fneg(const DoubleRegister frt, const DoubleRegister frb,
1076 RCBit rc = LeaveRC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001077 void mtfsb0(FPSCRBit bit, RCBit rc = LeaveRC);
1078 void mtfsb1(FPSCRBit bit, RCBit rc = LeaveRC);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001079 void mtfsfi(int bf, int immediate, RCBit rc = LeaveRC);
1080 void mffs(const DoubleRegister frt, RCBit rc = LeaveRC);
1081 void mtfsf(const DoubleRegister frb, bool L = 1, int FLM = 0, bool W = 0,
1082 RCBit rc = LeaveRC);
1083 void fsqrt(const DoubleRegister frt, const DoubleRegister frb,
1084 RCBit rc = LeaveRC);
1085 void fabs(const DoubleRegister frt, const DoubleRegister frb,
1086 RCBit rc = LeaveRC);
1087 void fmadd(const DoubleRegister frt, const DoubleRegister fra,
1088 const DoubleRegister frc, const DoubleRegister frb,
1089 RCBit rc = LeaveRC);
1090 void fmsub(const DoubleRegister frt, const DoubleRegister fra,
1091 const DoubleRegister frc, const DoubleRegister frb,
1092 RCBit rc = LeaveRC);
1093
1094 // Pseudo instructions
1095
1096 // Different nop operations are used by the code generator to detect certain
1097 // states of the generated code.
1098 enum NopMarkerTypes {
1099 NON_MARKING_NOP = 0,
1100 GROUP_ENDING_NOP,
1101 DEBUG_BREAK_NOP,
1102 // IC markers.
1103 PROPERTY_ACCESS_INLINED,
1104 PROPERTY_ACCESS_INLINED_CONTEXT,
1105 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
1106 // Helper values.
1107 LAST_CODE_MARKER,
1108 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
1109 };
1110
1111 void nop(int type = 0); // 0 is the default non-marking type.
1112
1113 void push(Register src) {
1114#if V8_TARGET_ARCH_PPC64
1115 stdu(src, MemOperand(sp, -kPointerSize));
1116#else
1117 stwu(src, MemOperand(sp, -kPointerSize));
1118#endif
1119 }
1120
1121 void pop(Register dst) {
1122#if V8_TARGET_ARCH_PPC64
1123 ld(dst, MemOperand(sp));
1124#else
1125 lwz(dst, MemOperand(sp));
1126#endif
1127 addi(sp, sp, Operand(kPointerSize));
1128 }
1129
1130 void pop() { addi(sp, sp, Operand(kPointerSize)); }
1131
1132 // Jump unconditionally to given label.
1133 void jmp(Label* L) { b(L); }
1134
1135 // Check the code size generated from label to here.
1136 int SizeOfCodeGeneratedSince(Label* label) {
1137 return pc_offset() - label->pos();
1138 }
1139
1140 // Check the number of instructions generated from label to here.
1141 int InstructionsGeneratedSince(Label* label) {
1142 return SizeOfCodeGeneratedSince(label) / kInstrSize;
1143 }
1144
1145 // Class for scoping postponing the trampoline pool generation.
1146 class BlockTrampolinePoolScope {
1147 public:
1148 explicit BlockTrampolinePoolScope(Assembler* assem) : assem_(assem) {
1149 assem_->StartBlockTrampolinePool();
1150 }
1151 ~BlockTrampolinePoolScope() { assem_->EndBlockTrampolinePool(); }
1152
1153 private:
1154 Assembler* assem_;
1155
1156 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockTrampolinePoolScope);
1157 };
1158
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001159 // Class for scoping disabling constant pool entry merging
1160 class BlockConstantPoolEntrySharingScope {
1161 public:
1162 explicit BlockConstantPoolEntrySharingScope(Assembler* assem)
1163 : assem_(assem) {
1164 assem_->StartBlockConstantPoolEntrySharing();
1165 }
1166 ~BlockConstantPoolEntrySharingScope() {
1167 assem_->EndBlockConstantPoolEntrySharing();
1168 }
1169
1170 private:
1171 Assembler* assem_;
1172
1173 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstantPoolEntrySharingScope);
1174 };
1175
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001176 // Debugging
1177
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001178 // Mark generator continuation.
1179 void RecordGeneratorContinuation();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001180
1181 // Mark address of a debug break slot.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001182 void RecordDebugBreakSlot(RelocInfo::Mode mode);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001183
1184 // Record the AST id of the CallIC being compiled, so that it can be placed
1185 // in the relocation information.
1186 void SetRecordedAstId(TypeFeedbackId ast_id) {
1187 // Causes compiler to fail
1188 // DCHECK(recorded_ast_id_.IsNone());
1189 recorded_ast_id_ = ast_id;
1190 }
1191
1192 TypeFeedbackId RecordedAstId() {
1193 // Causes compiler to fail
1194 // DCHECK(!recorded_ast_id_.IsNone());
1195 return recorded_ast_id_;
1196 }
1197
1198 void ClearRecordedAstId() { recorded_ast_id_ = TypeFeedbackId::None(); }
1199
1200 // Record a comment relocation entry that can be used by a disassembler.
1201 // Use --code-comments to enable.
1202 void RecordComment(const char* msg);
1203
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001204 // Record a deoptimization reason that can be used by a log or cpu profiler.
1205 // Use --trace-deopt to enable.
1206 void RecordDeoptReason(const int reason, const SourcePosition position);
1207
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001208 // Writes a single byte or word of data in the code stream. Used
1209 // for inline tables, e.g., jump-tables.
1210 void db(uint8_t data);
1211 void dd(uint32_t data);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001212 void dq(uint64_t data);
1213 void dp(uintptr_t data);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001214
1215 PositionsRecorder* positions_recorder() { return &positions_recorder_; }
1216
1217 // Read/patch instructions
1218 Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
1219 void instr_at_put(int pos, Instr instr) {
1220 *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
1221 }
1222 static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
1223 static void instr_at_put(byte* pc, Instr instr) {
1224 *reinterpret_cast<Instr*>(pc) = instr;
1225 }
1226 static Condition GetCondition(Instr instr);
1227
1228 static bool IsLis(Instr instr);
1229 static bool IsLi(Instr instr);
1230 static bool IsAddic(Instr instr);
1231 static bool IsOri(Instr instr);
1232
1233 static bool IsBranch(Instr instr);
1234 static Register GetRA(Instr instr);
1235 static Register GetRB(Instr instr);
1236#if V8_TARGET_ARCH_PPC64
1237 static bool Is64BitLoadIntoR12(Instr instr1, Instr instr2, Instr instr3,
1238 Instr instr4, Instr instr5);
1239#else
1240 static bool Is32BitLoadIntoR12(Instr instr1, Instr instr2);
1241#endif
1242
1243 static bool IsCmpRegister(Instr instr);
1244 static bool IsCmpImmediate(Instr instr);
1245 static bool IsRlwinm(Instr instr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001246 static bool IsAndi(Instr instr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001247#if V8_TARGET_ARCH_PPC64
1248 static bool IsRldicl(Instr instr);
1249#endif
1250 static bool IsCrSet(Instr instr);
1251 static Register GetCmpImmediateRegister(Instr instr);
1252 static int GetCmpImmediateRawImmediate(Instr instr);
1253 static bool IsNop(Instr instr, int type = NON_MARKING_NOP);
1254
1255 // Postpone the generation of the trampoline pool for the specified number of
1256 // instructions.
1257 void BlockTrampolinePoolFor(int instructions);
1258 void CheckTrampolinePool();
1259
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001260 // For mov. Return the number of actual instructions required to
1261 // load the operand into a register. This can be anywhere from
1262 // one (constant pool small section) to five instructions (full
1263 // 64-bit sequence).
1264 //
1265 // The value returned is only valid as long as no entries are added to the
1266 // constant pool between this call and the actual instruction being emitted.
1267 int instructions_required_for_mov(Register dst, const Operand& src) const;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001268
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001269 // Decide between using the constant pool vs. a mov immediate sequence.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001270 bool use_constant_pool_for_mov(Register dst, const Operand& src,
1271 bool canOptimize) const;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001272
1273 // The code currently calls CheckBuffer() too often. This has the side
1274 // effect of randomly growing the buffer in the middle of multi-instruction
1275 // sequences.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001276 //
1277 // This function allows outside callers to check and grow the buffer
1278 void EnsureSpaceFor(int space_needed);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001279
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001280 int EmitConstantPool() { return constant_pool_builder_.Emit(this); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001281
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001282 bool ConstantPoolAccessIsInOverflow() const {
1283 return constant_pool_builder_.NextAccess(ConstantPoolEntry::INTPTR) ==
1284 ConstantPoolEntry::OVERFLOWED;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001285 }
1286
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001287 Label* ConstantPoolPosition() {
1288 return constant_pool_builder_.EmittedPosition();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001289 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001290
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001291 void EmitRelocations();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001292
1293 protected:
1294 // Relocation for a type-recording IC has the AST id added to it. This
1295 // member variable is a way to pass the information from the call site to
1296 // the relocation info.
1297 TypeFeedbackId recorded_ast_id_;
1298
1299 int buffer_space() const { return reloc_info_writer.pos() - pc_; }
1300
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001301 // Decode instruction(s) at pos and return backchain to previous
1302 // label reference or kEndOfChain.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001303 int target_at(int pos);
1304
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001305 // Patch instruction(s) at pos to target target_pos (e.g. branch)
1306 void target_at_put(int pos, int target_pos, bool* is_branch = nullptr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001307
1308 // Record reloc info for current pc_
1309 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001310 ConstantPoolEntry::Access ConstantPoolAddEntry(RelocInfo::Mode rmode,
1311 intptr_t value) {
1312 bool sharing_ok = RelocInfo::IsNone(rmode) ||
1313 !(serializer_enabled() || rmode < RelocInfo::CELL ||
1314 is_constant_pool_entry_sharing_blocked());
1315 return constant_pool_builder_.AddEntry(pc_offset(), value, sharing_ok);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001316 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001317 ConstantPoolEntry::Access ConstantPoolAddEntry(double value) {
1318 return constant_pool_builder_.AddEntry(pc_offset(), value);
1319 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001320
1321 // Block the emission of the trampoline pool before pc_offset.
1322 void BlockTrampolinePoolBefore(int pc_offset) {
1323 if (no_trampoline_pool_before_ < pc_offset)
1324 no_trampoline_pool_before_ = pc_offset;
1325 }
1326
1327 void StartBlockTrampolinePool() { trampoline_pool_blocked_nesting_++; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001328 void EndBlockTrampolinePool() {
1329 int count = --trampoline_pool_blocked_nesting_;
1330 if (count == 0) CheckTrampolinePoolQuick();
1331 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001332 bool is_trampoline_pool_blocked() const {
1333 return trampoline_pool_blocked_nesting_ > 0;
1334 }
1335
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001336 void StartBlockConstantPoolEntrySharing() {
1337 constant_pool_entry_sharing_blocked_nesting_++;
1338 }
1339 void EndBlockConstantPoolEntrySharing() {
1340 constant_pool_entry_sharing_blocked_nesting_--;
1341 }
1342 bool is_constant_pool_entry_sharing_blocked() const {
1343 return constant_pool_entry_sharing_blocked_nesting_ > 0;
1344 }
1345
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001346 bool has_exception() const { return internal_trampoline_exception_; }
1347
1348 bool is_trampoline_emitted() const { return trampoline_emitted_; }
1349
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001350 private:
1351 // Code generation
1352 // The relocation writer's position is at least kGap bytes below the end of
1353 // the generated instructions. This is so that multi-instruction sequences do
1354 // not have to check for overflow. The same is true for writes of large
1355 // relocation info entries.
1356 static const int kGap = 32;
1357
1358 // Repeated checking whether the trampoline pool should be emitted is rather
1359 // expensive. By default we only check again once a number of instructions
1360 // has been generated.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001361 int next_trampoline_check_; // pc offset of next buffer check.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001362
1363 // Emission of the trampoline pool may be blocked in some code sequences.
1364 int trampoline_pool_blocked_nesting_; // Block emission if this is not zero.
1365 int no_trampoline_pool_before_; // Block emission before this pc offset.
1366
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001367 // Do not share constant pool entries.
1368 int constant_pool_entry_sharing_blocked_nesting_;
1369
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001370 // Relocation info generation
1371 // Each relocation is encoded as a variable size value
1372 static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
1373 RelocInfoWriter reloc_info_writer;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001374 std::vector<DeferredRelocInfo> relocations_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001375
1376 // The bound position, before this we cannot do instruction elimination.
1377 int last_bound_pos_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001378 // Optimizable cmpi information.
1379 int optimizable_cmpi_pos_;
1380 CRegister cmpi_cr_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001381
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001382 ConstantPoolBuilder constant_pool_builder_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001383
1384 // Code emission
1385 inline void CheckBuffer();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001386 void GrowBuffer(int needed = 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001387 inline void emit(Instr x);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001388 inline void TrackBranch();
1389 inline void UntrackBranch();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001390 inline void CheckTrampolinePoolQuick();
1391
1392 // Instruction generation
1393 void a_form(Instr instr, DoubleRegister frt, DoubleRegister fra,
1394 DoubleRegister frb, RCBit r);
1395 void d_form(Instr instr, Register rt, Register ra, const intptr_t val,
1396 bool signed_disp);
1397 void x_form(Instr instr, Register ra, Register rs, Register rb, RCBit r);
1398 void xo_form(Instr instr, Register rt, Register ra, Register rb, OEBit o,
1399 RCBit r);
1400 void md_form(Instr instr, Register ra, Register rs, int shift, int maskbit,
1401 RCBit r);
1402 void mds_form(Instr instr, Register ra, Register rs, Register rb, int maskbit,
1403 RCBit r);
1404
1405 // Labels
1406 void print(Label* L);
1407 int max_reach_from(int pos);
1408 void bind_to(Label* L, int pos);
1409 void next(Label* L);
1410
1411 class Trampoline {
1412 public:
1413 Trampoline() {
1414 next_slot_ = 0;
1415 free_slot_count_ = 0;
1416 }
1417 Trampoline(int start, int slot_count) {
1418 next_slot_ = start;
1419 free_slot_count_ = slot_count;
1420 }
1421 int take_slot() {
1422 int trampoline_slot = kInvalidSlotPos;
1423 if (free_slot_count_ <= 0) {
1424 // We have run out of space on trampolines.
1425 // Make sure we fail in debug mode, so we become aware of each case
1426 // when this happens.
1427 DCHECK(0);
1428 // Internal exception will be caught.
1429 } else {
1430 trampoline_slot = next_slot_;
1431 free_slot_count_--;
1432 next_slot_ += kTrampolineSlotsSize;
1433 }
1434 return trampoline_slot;
1435 }
1436
1437 private:
1438 int next_slot_;
1439 int free_slot_count_;
1440 };
1441
1442 int32_t get_trampoline_entry();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001443 int tracked_branch_count_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001444 // If trampoline is emitted, generated code is becoming large. As
1445 // this is already a slow case which can possibly break our code
1446 // generation for the extreme case, we use this information to
1447 // trigger different mode of branch instruction generation, where we
1448 // no longer use a single branch instruction.
1449 bool trampoline_emitted_;
1450 static const int kTrampolineSlotsSize = kInstrSize;
1451 static const int kMaxCondBranchReach = (1 << (16 - 1)) - 1;
1452 static const int kMaxBlockTrampolineSectionSize = 64 * kInstrSize;
1453 static const int kInvalidSlotPos = -1;
1454
1455 Trampoline trampoline_;
1456 bool internal_trampoline_exception_;
1457
1458 friend class RegExpMacroAssemblerPPC;
1459 friend class RelocInfo;
1460 friend class CodePatcher;
1461 friend class BlockTrampolinePoolScope;
1462 PositionsRecorder positions_recorder_;
1463 friend class PositionsRecorder;
1464 friend class EnsureSpace;
1465};
1466
1467
1468class EnsureSpace BASE_EMBEDDED {
1469 public:
1470 explicit EnsureSpace(Assembler* assembler) { assembler->CheckBuffer(); }
1471};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001472} // namespace internal
1473} // namespace v8
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001474
1475#endif // V8_PPC_ASSEMBLER_PPC_H_