1 | /* |
2 | * Copyright (C) 2011-2018 Apple Inc. 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 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #pragma once |
27 | |
28 | #include "MacroAssembler.h" |
29 | #include <array> |
30 | #include <wtf/PrintStream.h> |
31 | |
32 | namespace JSC { |
33 | |
34 | enum NoResultTag { NoResult }; |
35 | |
36 | // We use the same conventions in the basline JIT as in the LLint. If you |
37 | // change mappings in the GPRInfo, you should change them in the offlineasm |
38 | // compiler adequately. The register naming conventions are described at the |
39 | // top of the LowLevelInterpreter.asm file. |
40 | |
41 | typedef MacroAssembler::RegisterID GPRReg; |
42 | static constexpr GPRReg InvalidGPRReg { GPRReg::InvalidGPRReg }; |
43 | |
44 | #if ENABLE(ASSEMBLER) |
45 | |
46 | #if USE(JSVALUE64) |
47 | class JSValueRegs { |
48 | public: |
49 | constexpr JSValueRegs() |
50 | : m_gpr(InvalidGPRReg) |
51 | { |
52 | } |
53 | |
54 | constexpr explicit JSValueRegs(GPRReg gpr) |
55 | : m_gpr(gpr) |
56 | { |
57 | } |
58 | |
59 | static JSValueRegs payloadOnly(GPRReg gpr) |
60 | { |
61 | return JSValueRegs(gpr); |
62 | } |
63 | |
64 | static JSValueRegs withTwoAvailableRegs(GPRReg gpr, GPRReg) |
65 | { |
66 | return JSValueRegs(gpr); |
67 | } |
68 | |
69 | bool operator!() const { return m_gpr == InvalidGPRReg; } |
70 | explicit operator bool() const { return m_gpr != InvalidGPRReg; } |
71 | |
72 | bool operator==(JSValueRegs other) { return m_gpr == other.m_gpr; } |
73 | bool operator!=(JSValueRegs other) { return !(*this == other); } |
74 | |
75 | GPRReg gpr() const { return m_gpr; } |
76 | GPRReg tagGPR() const { return InvalidGPRReg; } |
77 | GPRReg payloadGPR() const { return m_gpr; } |
78 | |
79 | bool uses(GPRReg gpr) const { return m_gpr == gpr; } |
80 | |
81 | void dump(PrintStream&) const; |
82 | |
83 | private: |
84 | GPRReg m_gpr; |
85 | }; |
86 | |
87 | class JSValueSource { |
88 | public: |
89 | JSValueSource() |
90 | : m_offset(notAddress()) |
91 | , m_base(InvalidGPRReg) |
92 | { |
93 | } |
94 | |
95 | JSValueSource(JSValueRegs regs) |
96 | : m_offset(notAddress()) |
97 | , m_base(regs.gpr()) |
98 | { |
99 | } |
100 | |
101 | explicit JSValueSource(GPRReg gpr) |
102 | : m_offset(notAddress()) |
103 | , m_base(gpr) |
104 | { |
105 | } |
106 | |
107 | JSValueSource(MacroAssembler::Address address) |
108 | : m_offset(address.offset) |
109 | , m_base(address.base) |
110 | { |
111 | ASSERT(m_offset != notAddress()); |
112 | ASSERT(m_base != InvalidGPRReg); |
113 | } |
114 | |
115 | static JSValueSource unboxedCell(GPRReg payloadGPR) |
116 | { |
117 | return JSValueSource(payloadGPR); |
118 | } |
119 | |
120 | bool operator!() const { return m_base == InvalidGPRReg; } |
121 | explicit operator bool() const { return m_base != InvalidGPRReg; } |
122 | |
123 | bool isAddress() const { return m_offset != notAddress(); } |
124 | |
125 | int32_t offset() const |
126 | { |
127 | ASSERT(isAddress()); |
128 | return m_offset; |
129 | } |
130 | |
131 | GPRReg base() const |
132 | { |
133 | ASSERT(isAddress()); |
134 | return m_base; |
135 | } |
136 | |
137 | GPRReg gpr() const |
138 | { |
139 | ASSERT(!isAddress()); |
140 | return m_base; |
141 | } |
142 | |
143 | GPRReg payloadGPR() const { return gpr(); } |
144 | |
145 | JSValueRegs regs() const |
146 | { |
147 | return JSValueRegs(gpr()); |
148 | } |
149 | |
150 | MacroAssembler::Address asAddress() const { return MacroAssembler::Address(base(), offset()); } |
151 | |
152 | private: |
153 | static inline int32_t notAddress() { return 0x80000000; } |
154 | |
155 | int32_t m_offset; |
156 | GPRReg m_base; |
157 | }; |
158 | #endif // USE(JSVALUE64) |
159 | |
160 | #if USE(JSVALUE32_64) |
161 | class JSValueRegs { |
162 | public: |
163 | JSValueRegs() |
164 | : m_tagGPR(InvalidGPRReg) |
165 | , m_payloadGPR(InvalidGPRReg) |
166 | { |
167 | } |
168 | |
169 | JSValueRegs(GPRReg tagGPR, GPRReg payloadGPR) |
170 | : m_tagGPR(tagGPR) |
171 | , m_payloadGPR(payloadGPR) |
172 | { |
173 | } |
174 | |
175 | static JSValueRegs withTwoAvailableRegs(GPRReg gpr1, GPRReg gpr2) |
176 | { |
177 | return JSValueRegs(gpr1, gpr2); |
178 | } |
179 | |
180 | static JSValueRegs payloadOnly(GPRReg gpr) |
181 | { |
182 | return JSValueRegs(InvalidGPRReg, gpr); |
183 | } |
184 | |
185 | bool operator!() const { return !static_cast<bool>(*this); } |
186 | explicit operator bool() const |
187 | { |
188 | return static_cast<GPRReg>(m_tagGPR) != InvalidGPRReg |
189 | || static_cast<GPRReg>(m_payloadGPR) != InvalidGPRReg; |
190 | } |
191 | |
192 | bool operator==(JSValueRegs other) const |
193 | { |
194 | return m_tagGPR == other.m_tagGPR |
195 | && m_payloadGPR == other.m_payloadGPR; |
196 | } |
197 | bool operator!=(JSValueRegs other) const { return !(*this == other); } |
198 | |
199 | GPRReg tagGPR() const { return m_tagGPR; } |
200 | GPRReg payloadGPR() const { return m_payloadGPR; } |
201 | GPRReg gpr(WhichValueWord which) const |
202 | { |
203 | switch (which) { |
204 | case TagWord: |
205 | return tagGPR(); |
206 | case PayloadWord: |
207 | return payloadGPR(); |
208 | } |
209 | ASSERT_NOT_REACHED(); |
210 | return tagGPR(); |
211 | } |
212 | |
213 | bool uses(GPRReg gpr) const { return m_tagGPR == gpr || m_payloadGPR == gpr; } |
214 | |
215 | void dump(PrintStream&) const; |
216 | |
217 | private: |
218 | GPRReg m_tagGPR; |
219 | GPRReg m_payloadGPR; |
220 | }; |
221 | |
222 | class JSValueSource { |
223 | public: |
224 | JSValueSource() |
225 | : m_offset(notAddress()) |
226 | , m_baseOrTag(InvalidGPRReg) |
227 | , m_payload(InvalidGPRReg) |
228 | , m_tagType(0) |
229 | { |
230 | } |
231 | |
232 | JSValueSource(JSValueRegs regs) |
233 | : m_offset(notAddress()) |
234 | , m_baseOrTag(regs.tagGPR()) |
235 | , m_payload(regs.payloadGPR()) |
236 | , m_tagType(0) |
237 | { |
238 | } |
239 | |
240 | JSValueSource(GPRReg tagGPR, GPRReg payloadGPR) |
241 | : m_offset(notAddress()) |
242 | , m_baseOrTag(tagGPR) |
243 | , m_payload(payloadGPR) |
244 | , m_tagType(0) |
245 | { |
246 | } |
247 | |
248 | JSValueSource(MacroAssembler::Address address) |
249 | : m_offset(address.offset) |
250 | , m_baseOrTag(address.base) |
251 | , m_payload(InvalidGPRReg) |
252 | , m_tagType(0) |
253 | { |
254 | ASSERT(m_offset != notAddress()); |
255 | ASSERT(m_baseOrTag != InvalidGPRReg); |
256 | } |
257 | |
258 | static JSValueSource unboxedCell(GPRReg payloadGPR) |
259 | { |
260 | JSValueSource result; |
261 | result.m_offset = notAddress(); |
262 | result.m_baseOrTag = InvalidGPRReg; |
263 | result.m_payload = payloadGPR; |
264 | result.m_tagType = static_cast<int8_t>(JSValue::CellTag); |
265 | return result; |
266 | } |
267 | |
268 | bool operator!() const { return !static_cast<bool>(*this); } |
269 | explicit operator bool() const |
270 | { |
271 | return m_baseOrTag != InvalidGPRReg || m_payload != InvalidGPRReg; |
272 | } |
273 | |
274 | bool isAddress() const |
275 | { |
276 | ASSERT(!!*this); |
277 | return m_offset != notAddress(); |
278 | } |
279 | |
280 | int32_t offset() const |
281 | { |
282 | ASSERT(isAddress()); |
283 | return m_offset; |
284 | } |
285 | |
286 | GPRReg base() const |
287 | { |
288 | ASSERT(isAddress()); |
289 | return m_baseOrTag; |
290 | } |
291 | |
292 | GPRReg tagGPR() const |
293 | { |
294 | ASSERT(!isAddress() && m_baseOrTag != InvalidGPRReg); |
295 | return m_baseOrTag; |
296 | } |
297 | |
298 | GPRReg payloadGPR() const |
299 | { |
300 | ASSERT(!isAddress()); |
301 | return m_payload; |
302 | } |
303 | |
304 | bool hasKnownTag() const |
305 | { |
306 | ASSERT(!!*this); |
307 | ASSERT(!isAddress()); |
308 | return m_baseOrTag == InvalidGPRReg; |
309 | } |
310 | |
311 | uint32_t tag() const |
312 | { |
313 | return static_cast<int32_t>(m_tagType); |
314 | } |
315 | |
316 | JSValueRegs regs() const |
317 | { |
318 | return JSValueRegs(tagGPR(), payloadGPR()); |
319 | } |
320 | |
321 | MacroAssembler::Address asAddress(unsigned additionalOffset = 0) const { return MacroAssembler::Address(base(), offset() + additionalOffset); } |
322 | |
323 | private: |
324 | static inline int32_t notAddress() { return 0x80000000; } |
325 | |
326 | int32_t m_offset; |
327 | GPRReg m_baseOrTag; |
328 | GPRReg m_payload; |
329 | int8_t m_tagType; // Contains the low bits of the tag. |
330 | }; |
331 | #endif // USE(JSVALUE32_64) |
332 | |
333 | #if CPU(X86) |
334 | #define NUMBER_OF_ARGUMENT_REGISTERS 0u |
335 | #define NUMBER_OF_CALLEE_SAVES_REGISTERS 0u |
336 | |
337 | class GPRInfo { |
338 | public: |
339 | typedef GPRReg RegisterType; |
340 | static const unsigned numberOfRegisters = 6; |
341 | static const unsigned numberOfArgumentRegisters = NUMBER_OF_ARGUMENT_REGISTERS; |
342 | |
343 | // Temporary registers. |
344 | static const GPRReg regT0 = X86Registers::eax; |
345 | static const GPRReg regT1 = X86Registers::edx; |
346 | static const GPRReg regT2 = X86Registers::ecx; |
347 | static const GPRReg regT3 = X86Registers::ebx; // Callee-save |
348 | static const GPRReg regT4 = X86Registers::esi; // Callee-save |
349 | static const GPRReg regT5 = X86Registers::edi; // Callee-save |
350 | static const GPRReg callFrameRegister = X86Registers::ebp; |
351 | // These constants provide the names for the general purpose argument & return value registers. |
352 | static const GPRReg argumentGPR0 = X86Registers::ecx; // regT2 |
353 | static const GPRReg argumentGPR1 = X86Registers::edx; // regT1 |
354 | static const GPRReg argumentGPR2 = X86Registers::eax; // regT0 |
355 | static const GPRReg argumentGPR3 = X86Registers::ebx; // regT3 |
356 | static const GPRReg nonArgGPR0 = X86Registers::esi; // regT4 |
357 | static const GPRReg returnValueGPR = X86Registers::eax; // regT0 |
358 | static const GPRReg returnValueGPR2 = X86Registers::edx; // regT1 |
359 | static const GPRReg nonPreservedNonReturnGPR = X86Registers::ecx; |
360 | |
361 | static GPRReg toRegister(unsigned index) |
362 | { |
363 | ASSERT(index < numberOfRegisters); |
364 | static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4, regT5 }; |
365 | return registerForIndex[index]; |
366 | } |
367 | |
368 | static GPRReg toArgumentRegister(unsigned) |
369 | { |
370 | UNREACHABLE_FOR_PLATFORM(); |
371 | return InvalidGPRReg; |
372 | } |
373 | |
374 | static unsigned toIndex(GPRReg reg) |
375 | { |
376 | ASSERT(reg != InvalidGPRReg); |
377 | ASSERT(static_cast<int>(reg) < 8); |
378 | static const unsigned indexForRegister[8] = { 0, 2, 1, 3, InvalidIndex, InvalidIndex, 4, 5 }; |
379 | unsigned result = indexForRegister[reg]; |
380 | return result; |
381 | } |
382 | |
383 | static const char* debugName(GPRReg reg) |
384 | { |
385 | ASSERT(reg != InvalidGPRReg); |
386 | return MacroAssembler::gprName(reg); |
387 | } |
388 | |
389 | static const unsigned InvalidIndex = 0xffffffff; |
390 | }; |
391 | |
392 | #endif // CPU(X86) |
393 | |
394 | #if CPU(X86_64) |
395 | #if !OS(WINDOWS) |
396 | #define NUMBER_OF_ARGUMENT_REGISTERS 6u |
397 | #define NUMBER_OF_CALLEE_SAVES_REGISTERS 5u |
398 | #else |
399 | #define NUMBER_OF_ARGUMENT_REGISTERS 4u |
400 | #define NUMBER_OF_CALLEE_SAVES_REGISTERS 7u |
401 | #endif |
402 | |
403 | class GPRInfo { |
404 | public: |
405 | typedef GPRReg RegisterType; |
406 | static const unsigned numberOfRegisters = 11; |
407 | static const unsigned numberOfArgumentRegisters = NUMBER_OF_ARGUMENT_REGISTERS; |
408 | |
409 | // These registers match the baseline JIT. |
410 | static const GPRReg callFrameRegister = X86Registers::ebp; |
411 | static const GPRReg tagTypeNumberRegister = X86Registers::r14; |
412 | static const GPRReg tagMaskRegister = X86Registers::r15; |
413 | |
414 | // Temporary registers. |
415 | static const GPRReg regT0 = X86Registers::eax; |
416 | #if !OS(WINDOWS) |
417 | static const GPRReg regT1 = X86Registers::esi; |
418 | static const GPRReg regT2 = X86Registers::edx; |
419 | static const GPRReg regT3 = X86Registers::ecx; |
420 | static const GPRReg regT4 = X86Registers::r8; |
421 | static const GPRReg regT5 = X86Registers::r10; |
422 | static const GPRReg regT6 = X86Registers::edi; |
423 | static const GPRReg regT7 = X86Registers::r9; |
424 | #else |
425 | static const GPRReg regT1 = X86Registers::edx; |
426 | static const GPRReg regT2 = X86Registers::r8; |
427 | static const GPRReg regT3 = X86Registers::r9; |
428 | static const GPRReg regT4 = X86Registers::r10; |
429 | static const GPRReg regT5 = X86Registers::ecx; |
430 | #endif |
431 | |
432 | static const GPRReg regCS0 = X86Registers::ebx; |
433 | |
434 | #if !OS(WINDOWS) |
435 | static const GPRReg regCS1 = X86Registers::r12; |
436 | static const GPRReg regCS2 = X86Registers::r13; |
437 | static const GPRReg regCS3 = X86Registers::r14; |
438 | static const GPRReg regCS4 = X86Registers::r15; |
439 | #else |
440 | static const GPRReg regCS1 = X86Registers::esi; |
441 | static const GPRReg regCS2 = X86Registers::edi; |
442 | static const GPRReg regCS3 = X86Registers::r12; |
443 | static const GPRReg regCS4 = X86Registers::r13; |
444 | static const GPRReg regCS5 = X86Registers::r14; |
445 | static const GPRReg regCS6 = X86Registers::r15; |
446 | #endif |
447 | |
448 | // These constants provide the names for the general purpose argument & return value registers. |
449 | #if !OS(WINDOWS) |
450 | static const GPRReg argumentGPR0 = X86Registers::edi; // regT6 |
451 | static const GPRReg argumentGPR1 = X86Registers::esi; // regT1 |
452 | static const GPRReg argumentGPR2 = X86Registers::edx; // regT2 |
453 | static const GPRReg argumentGPR3 = X86Registers::ecx; // regT3 |
454 | static const GPRReg argumentGPR4 = X86Registers::r8; // regT4 |
455 | static const GPRReg argumentGPR5 = X86Registers::r9; // regT7 |
456 | #else |
457 | static const GPRReg argumentGPR0 = X86Registers::ecx; // regT5 |
458 | static const GPRReg argumentGPR1 = X86Registers::edx; // regT1 |
459 | static const GPRReg argumentGPR2 = X86Registers::r8; // regT2 |
460 | static const GPRReg argumentGPR3 = X86Registers::r9; // regT3 |
461 | #endif |
462 | static const GPRReg nonArgGPR0 = X86Registers::r10; // regT5 (regT4 on Windows) |
463 | static const GPRReg returnValueGPR = X86Registers::eax; // regT0 |
464 | static const GPRReg returnValueGPR2 = X86Registers::edx; // regT1 or regT2 |
465 | static const GPRReg nonPreservedNonReturnGPR = X86Registers::r10; // regT5 (regT4 on Windows) |
466 | static const GPRReg nonPreservedNonArgumentGPR0 = X86Registers::r10; // regT5 (regT4 on Windows) |
467 | static const GPRReg nonPreservedNonArgumentGPR1 = X86Registers::eax; |
468 | |
469 | // FIXME: I believe that all uses of this are dead in the sense that it just causes the scratch |
470 | // register allocator to select a different register and potentially spill things. It would be better |
471 | // if we instead had a more explicit way of saying that we don't have a scratch register. |
472 | static const GPRReg patchpointScratchRegister; |
473 | |
474 | static GPRReg toRegister(unsigned index) |
475 | { |
476 | ASSERT(index < numberOfRegisters); |
477 | #if !OS(WINDOWS) |
478 | static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4, regT5, regT6, regT7, regCS0, regCS1, regCS2 }; |
479 | #else |
480 | static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4, regT5, regCS0, regCS1, regCS2, regCS3, regCS4 }; |
481 | #endif |
482 | return registerForIndex[index]; |
483 | } |
484 | |
485 | static GPRReg toArgumentRegister(unsigned index) |
486 | { |
487 | ASSERT(index < numberOfArgumentRegisters); |
488 | #if !OS(WINDOWS) |
489 | static const GPRReg registerForIndex[numberOfArgumentRegisters] = { argumentGPR0, argumentGPR1, argumentGPR2, argumentGPR3, argumentGPR4, argumentGPR5 }; |
490 | #else |
491 | static const GPRReg registerForIndex[numberOfArgumentRegisters] = { argumentGPR0, argumentGPR1, argumentGPR2, argumentGPR3 }; |
492 | #endif |
493 | return registerForIndex[index]; |
494 | } |
495 | |
496 | static unsigned toIndex(GPRReg reg) |
497 | { |
498 | ASSERT(reg != InvalidGPRReg); |
499 | ASSERT(static_cast<int>(reg) < 16); |
500 | #if !OS(WINDOWS) |
501 | static const unsigned indexForRegister[16] = { 0, 3, 2, 8, InvalidIndex, InvalidIndex, 1, 6, 4, 7, 5, InvalidIndex, 9, 10, InvalidIndex, InvalidIndex }; |
502 | #else |
503 | static const unsigned indexForRegister[16] = { 0, 5, 1, 6, InvalidIndex, InvalidIndex, 7, 8, 2, 3, 4, InvalidIndex, 9, 10, InvalidIndex, InvalidIndex }; |
504 | #endif |
505 | return indexForRegister[reg]; |
506 | } |
507 | |
508 | static const char* debugName(GPRReg reg) |
509 | { |
510 | ASSERT(reg != InvalidGPRReg); |
511 | return MacroAssembler::gprName(reg); |
512 | } |
513 | |
514 | static const std::array<GPRReg, 3>& reservedRegisters() |
515 | { |
516 | static const std::array<GPRReg, 3> reservedRegisters { { |
517 | MacroAssembler::s_scratchRegister, |
518 | tagTypeNumberRegister, |
519 | tagMaskRegister, |
520 | } }; |
521 | return reservedRegisters; |
522 | } |
523 | |
524 | static const unsigned InvalidIndex = 0xffffffff; |
525 | }; |
526 | |
527 | #endif // CPU(X86_64) |
528 | |
529 | #if CPU(ARM_THUMB2) |
530 | #define NUMBER_OF_ARGUMENT_REGISTERS 4u |
531 | #define NUMBER_OF_CALLEE_SAVES_REGISTERS 1u |
532 | |
533 | class GPRInfo { |
534 | public: |
535 | typedef GPRReg RegisterType; |
536 | static const unsigned numberOfRegisters = 9; |
537 | static const unsigned numberOfArgumentRegisters = NUMBER_OF_ARGUMENT_REGISTERS; |
538 | |
539 | // Temporary registers. |
540 | static const GPRReg regT0 = ARMRegisters::r0; |
541 | static const GPRReg regT1 = ARMRegisters::r1; |
542 | static const GPRReg regT2 = ARMRegisters::r2; |
543 | static const GPRReg regT3 = ARMRegisters::r3; |
544 | static const GPRReg regT4 = ARMRegisters::r8; |
545 | static const GPRReg regT5 = ARMRegisters::r9; |
546 | static const GPRReg regT6 = ARMRegisters::r10; |
547 | static const GPRReg regT7 = ARMRegisters::r5; |
548 | static const GPRReg regT8 = ARMRegisters::r4; |
549 | static const GPRReg regCS0 = ARMRegisters::r11; |
550 | // These registers match the baseline JIT. |
551 | static const GPRReg callFrameRegister = ARMRegisters::fp; |
552 | // These constants provide the names for the general purpose argument & return value registers. |
553 | static const GPRReg argumentGPR0 = ARMRegisters::r0; // regT0 |
554 | static const GPRReg argumentGPR1 = ARMRegisters::r1; // regT1 |
555 | static const GPRReg argumentGPR2 = ARMRegisters::r2; // regT2 |
556 | static const GPRReg argumentGPR3 = ARMRegisters::r3; // regT3 |
557 | static const GPRReg nonArgGPR0 = ARMRegisters::r4; // regT8 |
558 | static const GPRReg nonArgGPR1 = ARMRegisters::r8; // regT4 |
559 | static const GPRReg returnValueGPR = ARMRegisters::r0; // regT0 |
560 | static const GPRReg returnValueGPR2 = ARMRegisters::r1; // regT1 |
561 | static const GPRReg nonPreservedNonReturnGPR = ARMRegisters::r5; |
562 | |
563 | static GPRReg toRegister(unsigned index) |
564 | { |
565 | ASSERT(index < numberOfRegisters); |
566 | static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4, regT5, regT6, regT7, regT8 }; |
567 | return registerForIndex[index]; |
568 | } |
569 | |
570 | static GPRReg toArgumentRegister(unsigned index) |
571 | { |
572 | ASSERT(index < numberOfArgumentRegisters); |
573 | static const GPRReg registerForIndex[numberOfArgumentRegisters] = { argumentGPR0, argumentGPR1, argumentGPR2, argumentGPR3 }; |
574 | return registerForIndex[index]; |
575 | } |
576 | |
577 | static unsigned toIndex(GPRReg reg) |
578 | { |
579 | ASSERT(reg != InvalidGPRReg); |
580 | ASSERT(static_cast<int>(reg) < 16); |
581 | static const unsigned indexForRegister[16] = |
582 | { 0, 1, 2, 3, 8, 7, InvalidIndex, InvalidIndex, 4, 5, 6, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex }; |
583 | unsigned result = indexForRegister[reg]; |
584 | return result; |
585 | } |
586 | |
587 | static const char* debugName(GPRReg reg) |
588 | { |
589 | ASSERT(reg != InvalidGPRReg); |
590 | return MacroAssembler::gprName(reg); |
591 | } |
592 | |
593 | static const unsigned InvalidIndex = 0xffffffff; |
594 | }; |
595 | |
596 | #endif // CPU(ARM) |
597 | |
598 | #if CPU(ARM64) |
599 | #define NUMBER_OF_ARGUMENT_REGISTERS 8u |
600 | // Callee Saves includes x19..x28 and FP registers q8..q15 |
601 | #define NUMBER_OF_CALLEE_SAVES_REGISTERS 18u |
602 | |
603 | class GPRInfo { |
604 | public: |
605 | typedef GPRReg RegisterType; |
606 | static const unsigned numberOfRegisters = 16; |
607 | static const unsigned numberOfArgumentRegisters = 8; |
608 | |
609 | // These registers match the baseline JIT. |
610 | static const GPRReg callFrameRegister = ARM64Registers::fp; |
611 | static const GPRReg tagTypeNumberRegister = ARM64Registers::x27; |
612 | static const GPRReg tagMaskRegister = ARM64Registers::x28; |
613 | static const GPRReg dataTempRegister = MacroAssembler::dataTempRegister; |
614 | static const GPRReg memoryTempRegister = MacroAssembler::memoryTempRegister; |
615 | // Temporary registers. |
616 | static const GPRReg regT0 = ARM64Registers::x0; |
617 | static const GPRReg regT1 = ARM64Registers::x1; |
618 | static const GPRReg regT2 = ARM64Registers::x2; |
619 | static const GPRReg regT3 = ARM64Registers::x3; |
620 | static const GPRReg regT4 = ARM64Registers::x4; |
621 | static const GPRReg regT5 = ARM64Registers::x5; |
622 | static const GPRReg regT6 = ARM64Registers::x6; |
623 | static const GPRReg regT7 = ARM64Registers::x7; |
624 | static const GPRReg regT8 = ARM64Registers::x8; |
625 | static const GPRReg regT9 = ARM64Registers::x9; |
626 | static const GPRReg regT10 = ARM64Registers::x10; |
627 | static const GPRReg regT11 = ARM64Registers::x11; |
628 | static const GPRReg regT12 = ARM64Registers::x12; |
629 | static const GPRReg regT13 = ARM64Registers::x13; |
630 | static const GPRReg regT14 = ARM64Registers::x14; |
631 | static const GPRReg regT15 = ARM64Registers::x15; |
632 | static const GPRReg regCS0 = ARM64Registers::x19; // Used by FTL only |
633 | static const GPRReg regCS1 = ARM64Registers::x20; // Used by FTL only |
634 | static const GPRReg regCS2 = ARM64Registers::x21; // Used by FTL only |
635 | static const GPRReg regCS3 = ARM64Registers::x22; // Used by FTL only |
636 | static const GPRReg regCS4 = ARM64Registers::x23; // Used by FTL only |
637 | static const GPRReg regCS5 = ARM64Registers::x24; // Used by FTL only |
638 | static const GPRReg regCS6 = ARM64Registers::x25; // Used by FTL only |
639 | static const GPRReg regCS7 = ARM64Registers::x26; |
640 | static const GPRReg regCS8 = ARM64Registers::x27; // tagTypeNumber |
641 | static const GPRReg regCS9 = ARM64Registers::x28; // tagMask |
642 | // These constants provide the names for the general purpose argument & return value registers. |
643 | static const GPRReg argumentGPR0 = ARM64Registers::x0; // regT0 |
644 | static const GPRReg argumentGPR1 = ARM64Registers::x1; // regT1 |
645 | static const GPRReg argumentGPR2 = ARM64Registers::x2; // regT2 |
646 | static const GPRReg argumentGPR3 = ARM64Registers::x3; // regT3 |
647 | static const GPRReg argumentGPR4 = ARM64Registers::x4; // regT4 |
648 | static const GPRReg argumentGPR5 = ARM64Registers::x5; // regT5 |
649 | static const GPRReg argumentGPR6 = ARM64Registers::x6; // regT6 |
650 | static const GPRReg argumentGPR7 = ARM64Registers::x7; // regT7 |
651 | static const GPRReg nonArgGPR0 = ARM64Registers::x8; // regT8 |
652 | static const GPRReg nonArgGPR1 = ARM64Registers::x9; // regT9 |
653 | static const GPRReg returnValueGPR = ARM64Registers::x0; // regT0 |
654 | static const GPRReg returnValueGPR2 = ARM64Registers::x1; // regT1 |
655 | static const GPRReg nonPreservedNonReturnGPR = ARM64Registers::x2; |
656 | static const GPRReg nonPreservedNonArgumentGPR0 = ARM64Registers::x8; |
657 | static const GPRReg nonPreservedNonArgumentGPR1 = ARM64Registers::x9; |
658 | static const GPRReg patchpointScratchRegister; |
659 | |
660 | // GPRReg mapping is direct, the machine register numbers can |
661 | // be used directly as indices into the GPR RegisterBank. |
662 | COMPILE_ASSERT(ARM64Registers::q0 == 0, q0_is_0); |
663 | COMPILE_ASSERT(ARM64Registers::q1 == 1, q1_is_1); |
664 | COMPILE_ASSERT(ARM64Registers::q2 == 2, q2_is_2); |
665 | COMPILE_ASSERT(ARM64Registers::q3 == 3, q3_is_3); |
666 | COMPILE_ASSERT(ARM64Registers::q4 == 4, q4_is_4); |
667 | COMPILE_ASSERT(ARM64Registers::q5 == 5, q5_is_5); |
668 | COMPILE_ASSERT(ARM64Registers::q6 == 6, q6_is_6); |
669 | COMPILE_ASSERT(ARM64Registers::q7 == 7, q7_is_7); |
670 | COMPILE_ASSERT(ARM64Registers::q8 == 8, q8_is_8); |
671 | COMPILE_ASSERT(ARM64Registers::q9 == 9, q9_is_9); |
672 | COMPILE_ASSERT(ARM64Registers::q10 == 10, q10_is_10); |
673 | COMPILE_ASSERT(ARM64Registers::q11 == 11, q11_is_11); |
674 | COMPILE_ASSERT(ARM64Registers::q12 == 12, q12_is_12); |
675 | COMPILE_ASSERT(ARM64Registers::q13 == 13, q13_is_13); |
676 | COMPILE_ASSERT(ARM64Registers::q14 == 14, q14_is_14); |
677 | COMPILE_ASSERT(ARM64Registers::q15 == 15, q15_is_15); |
678 | static GPRReg toRegister(unsigned index) |
679 | { |
680 | return (GPRReg)index; |
681 | } |
682 | static unsigned toIndex(GPRReg reg) |
683 | { |
684 | if (reg > regT15) |
685 | return InvalidIndex; |
686 | return (unsigned)reg; |
687 | } |
688 | |
689 | static GPRReg toArgumentRegister(unsigned index) |
690 | { |
691 | ASSERT(index < numberOfArgumentRegisters); |
692 | return toRegister(index); |
693 | } |
694 | |
695 | static const char* debugName(GPRReg reg) |
696 | { |
697 | ASSERT(reg != InvalidGPRReg); |
698 | return MacroAssembler::gprName(reg); |
699 | } |
700 | |
701 | static const std::array<GPRReg, 4>& reservedRegisters() |
702 | { |
703 | static const std::array<GPRReg, 4> reservedRegisters { { |
704 | dataTempRegister, |
705 | memoryTempRegister, |
706 | tagTypeNumberRegister, |
707 | tagMaskRegister, |
708 | } }; |
709 | return reservedRegisters; |
710 | } |
711 | |
712 | static const unsigned InvalidIndex = 0xffffffff; |
713 | }; |
714 | |
715 | #endif // CPU(ARM64) |
716 | |
717 | #if CPU(MIPS) |
718 | #define NUMBER_OF_ARGUMENT_REGISTERS 4u |
719 | #define NUMBER_OF_CALLEE_SAVES_REGISTERS 1u |
720 | |
721 | class GPRInfo { |
722 | public: |
723 | typedef GPRReg RegisterType; |
724 | static const unsigned numberOfRegisters = 11; |
725 | static const unsigned numberOfArgumentRegisters = NUMBER_OF_ARGUMENT_REGISTERS; |
726 | |
727 | // regT0 must be v0 for returning a 32-bit value. |
728 | // regT1 must be v1 for returning a pair of 32-bit value. |
729 | |
730 | // Temporary registers. |
731 | static const GPRReg regT0 = MIPSRegisters::v0; |
732 | static const GPRReg regT1 = MIPSRegisters::v1; |
733 | static const GPRReg regT2 = MIPSRegisters::t2; |
734 | static const GPRReg regT3 = MIPSRegisters::t3; |
735 | static const GPRReg regT4 = MIPSRegisters::t4; |
736 | static const GPRReg regT5 = MIPSRegisters::t5; |
737 | static const GPRReg regT6 = MIPSRegisters::t6; |
738 | static const GPRReg regT7 = MIPSRegisters::a0; |
739 | static const GPRReg regT8 = MIPSRegisters::a1; |
740 | static const GPRReg regT9 = MIPSRegisters::a2; |
741 | static const GPRReg regT10 = MIPSRegisters::a3; |
742 | // These registers match the baseline JIT. |
743 | static const GPRReg callFrameRegister = MIPSRegisters::fp; |
744 | // These constants provide the names for the general purpose argument & return value registers. |
745 | static const GPRReg argumentGPR0 = MIPSRegisters::a0; |
746 | static const GPRReg argumentGPR1 = MIPSRegisters::a1; |
747 | static const GPRReg argumentGPR2 = MIPSRegisters::a2; |
748 | static const GPRReg argumentGPR3 = MIPSRegisters::a3; |
749 | static const GPRReg nonArgGPR0 = regT4; |
750 | static const GPRReg returnValueGPR = regT0; |
751 | static const GPRReg returnValueGPR2 = regT1; |
752 | static const GPRReg nonPreservedNonReturnGPR = regT2; |
753 | static const GPRReg regCS0 = MIPSRegisters::s0; |
754 | |
755 | static GPRReg toRegister(unsigned index) |
756 | { |
757 | ASSERT(index < numberOfRegisters); |
758 | static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4, regT5, regT6, regT7, regT8, regT9, regT10 }; |
759 | return registerForIndex[index]; |
760 | } |
761 | |
762 | static GPRReg toArgumentRegister(unsigned index) |
763 | { |
764 | ASSERT(index < numberOfArgumentRegisters); |
765 | static const GPRReg registerForIndex[numberOfArgumentRegisters] = { argumentGPR0, argumentGPR1, argumentGPR2, argumentGPR3 }; |
766 | return registerForIndex[index]; |
767 | } |
768 | |
769 | static unsigned toIndex(GPRReg reg) |
770 | { |
771 | ASSERT(reg != InvalidGPRReg); |
772 | ASSERT(reg < 32); |
773 | static const unsigned indexForRegister[32] = { |
774 | InvalidIndex, InvalidIndex, 0, 1, 7, 8, 9, 10, |
775 | InvalidIndex, InvalidIndex, 2, 3, 4, 5, 6, InvalidIndex, |
776 | InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, |
777 | InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex |
778 | }; |
779 | unsigned result = indexForRegister[reg]; |
780 | return result; |
781 | } |
782 | |
783 | static const char* debugName(GPRReg reg) |
784 | { |
785 | ASSERT(reg != InvalidGPRReg); |
786 | return MacroAssembler::gprName(reg); |
787 | } |
788 | |
789 | static const unsigned InvalidIndex = 0xffffffff; |
790 | }; |
791 | |
792 | #endif // CPU(MIPS) |
793 | |
794 | // The baseline JIT uses "accumulator" style execution with regT0 (for 64-bit) |
795 | // and regT0 + regT1 (for 32-bit) serving as the accumulator register(s) for |
796 | // passing results of one opcode to the next. Hence: |
797 | COMPILE_ASSERT(GPRInfo::regT0 == GPRInfo::returnValueGPR, regT0_must_equal_returnValueGPR); |
798 | #if USE(JSVALUE32_64) |
799 | COMPILE_ASSERT(GPRInfo::regT1 == GPRInfo::returnValueGPR2, regT1_must_equal_returnValueGPR2); |
800 | #endif |
801 | |
802 | inline GPRReg (GPRReg result) { return result; } |
803 | #if USE(JSVALUE64) |
804 | inline GPRReg (JSValueRegs result) { return result.gpr(); } |
805 | #else |
806 | inline JSValueRegs extractResult(JSValueRegs result) { return result; } |
807 | #endif |
808 | inline NoResultTag (NoResultTag) { return NoResult; } |
809 | |
810 | // We use this hack to get the GPRInfo from the GPRReg type in templates because our code is bad and we should feel bad.. |
811 | constexpr GPRInfo toInfoFromReg(GPRReg) { return GPRInfo(); } |
812 | |
813 | #endif // ENABLE(ASSEMBLER) |
814 | |
815 | } // namespace JSC |
816 | |
817 | namespace WTF { |
818 | |
819 | inline void printInternal(PrintStream& out, JSC::GPRReg reg) |
820 | { |
821 | #if ENABLE(ASSEMBLER) |
822 | out.print("%" , JSC::GPRInfo::debugName(reg)); |
823 | #else |
824 | out.printf("%%r%d" , reg); |
825 | #endif |
826 | } |
827 | |
828 | } // namespace WTF |
829 | |