a19864acc59cb6ef6d455c63c79f7dcc293a3afb
[WebKit-https.git] / JavaScriptCore / assembler / ARMAssembler.h
1 /*
2  * Copyright (C) 2009, 2010 University of Szeged
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #ifndef ARMAssembler_h
28 #define ARMAssembler_h
29
30 #if ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
31
32 #include "AssemblerBufferWithConstantPool.h"
33 #include <wtf/Assertions.h>
34 namespace JSC {
35
36     typedef uint32_t ARMWord;
37
38     namespace ARMRegisters {
39         typedef enum {
40             r0 = 0,
41             r1,
42             r2,
43             r3,
44             S0 = r3,
45             r4,
46             r5,
47             r6,
48             r7,
49             r8,
50             S1 = r8,
51             r9,
52             r10,
53             r11,
54             r12,
55             r13,
56             sp = r13,
57             r14,
58             lr = r14,
59             r15,
60             pc = r15
61         } RegisterID;
62
63         typedef enum {
64             d0,
65             d1,
66             d2,
67             d3,
68             SD0 = d3
69         } FPRegisterID;
70
71     } // namespace ARMRegisters
72
73     class ARMAssembler {
74     public:
75         typedef ARMRegisters::RegisterID RegisterID;
76         typedef ARMRegisters::FPRegisterID FPRegisterID;
77         typedef AssemblerBufferWithConstantPool<2048, 4, 4, ARMAssembler> ARMBuffer;
78         typedef SegmentedVector<int, 64> Jumps;
79
80         ARMAssembler() { }
81
82         // ARM conditional constants
83         typedef enum {
84             EQ = 0x00000000, // Zero
85             NE = 0x10000000, // Non-zero
86             CS = 0x20000000,
87             CC = 0x30000000,
88             MI = 0x40000000,
89             PL = 0x50000000,
90             VS = 0x60000000,
91             VC = 0x70000000,
92             HI = 0x80000000,
93             LS = 0x90000000,
94             GE = 0xa0000000,
95             LT = 0xb0000000,
96             GT = 0xc0000000,
97             LE = 0xd0000000,
98             AL = 0xe0000000
99         } Condition;
100
101         // ARM instruction constants
102         enum {
103             AND = (0x0 << 21),
104             EOR = (0x1 << 21),
105             SUB = (0x2 << 21),
106             RSB = (0x3 << 21),
107             ADD = (0x4 << 21),
108             ADC = (0x5 << 21),
109             SBC = (0x6 << 21),
110             RSC = (0x7 << 21),
111             TST = (0x8 << 21),
112             TEQ = (0x9 << 21),
113             CMP = (0xa << 21),
114             CMN = (0xb << 21),
115             ORR = (0xc << 21),
116             MOV = (0xd << 21),
117             BIC = (0xe << 21),
118             MVN = (0xf << 21),
119             MUL = 0x00000090,
120             MULL = 0x00c00090,
121             FADDD = 0x0e300b00,
122             FDIVD = 0x0e800b00,
123             FSUBD = 0x0e300b40,
124             FMULD = 0x0e200b00,
125             FCMPD = 0x0eb40b40,
126             FSQRTD = 0x0eb10bc0,
127             DTR = 0x05000000,
128             LDRH = 0x00100090,
129             STRH = 0x00000090,
130             STMDB = 0x09200000,
131             LDMIA = 0x08b00000,
132             FDTR = 0x0d000b00,
133             B = 0x0a000000,
134             BL = 0x0b000000,
135 #if WTF_ARM_ARCH_AT_LEAST(5) || defined(__ARM_ARCH_4T__)
136             BX = 0x012fff10,
137 #endif
138             FMSR = 0x0e000a10,
139             FMRS = 0x0e100a10,
140             FSITOD = 0x0eb80bc0,
141             FTOSID = 0x0ebd0b40,
142             FMSTAT = 0x0ef1fa10,
143 #if WTF_ARM_ARCH_AT_LEAST(5)
144             CLZ = 0x016f0f10,
145             BKPT = 0xe120070,
146             BLX = 0x012fff30,
147 #endif
148 #if WTF_ARM_ARCH_AT_LEAST(7)
149             MOVW = 0x03000000,
150             MOVT = 0x03400000,
151 #endif
152         };
153
154         enum {
155             OP2_IMM = (1 << 25),
156             OP2_IMMh = (1 << 22),
157             OP2_INV_IMM = (1 << 26),
158             SET_CC = (1 << 20),
159             OP2_OFSREG = (1 << 25),
160             DT_UP = (1 << 23),
161             DT_BYTE = (1 << 22),
162             DT_WB = (1 << 21),
163             // This flag is inlcuded in LDR and STR
164             DT_PRE = (1 << 24),
165             HDT_UH = (1 << 5),
166             DT_LOAD = (1 << 20),
167         };
168
169         // Masks of ARM instructions
170         enum {
171             BRANCH_MASK = 0x00ffffff,
172             NONARM = 0xf0000000,
173             SDT_MASK = 0x0c000000,
174             SDT_OFFSET_MASK = 0xfff,
175         };
176
177         enum {
178             BOFFSET_MIN = -0x00800000,
179             BOFFSET_MAX = 0x007fffff,
180             SDT = 0x04000000,
181         };
182
183         enum {
184             padForAlign8  = 0x00,
185             padForAlign16 = 0x0000,
186             padForAlign32 = 0xee120070,
187         };
188
189         static const ARMWord INVALID_IMM = 0xf0000000;
190         static const ARMWord InvalidBranchTarget = 0xffffffff;
191         static const int DefaultPrefetching = 2;
192
193         class JmpSrc {
194             friend class ARMAssembler;
195         public:
196             JmpSrc()
197                 : m_offset(-1)
198             {
199             }
200
201         private:
202             JmpSrc(int offset)
203                 : m_offset(offset)
204             {
205             }
206
207             int m_offset;
208         };
209
210         class JmpDst {
211             friend class ARMAssembler;
212         public:
213             JmpDst()
214                 : m_offset(-1)
215                 , m_used(false)
216             {
217             }
218
219             bool isUsed() const { return m_used; }
220             void used() { m_used = true; }
221         private:
222             JmpDst(int offset)
223                 : m_offset(offset)
224                 , m_used(false)
225             {
226                 ASSERT(m_offset == offset);
227             }
228
229             int m_offset : 31;
230             int m_used : 1;
231         };
232
233         // Instruction formating
234
235         void emitInst(ARMWord op, int rd, int rn, ARMWord op2)
236         {
237             ASSERT ( ((op2 & ~OP2_IMM) <= 0xfff) || (((op2 & ~OP2_IMMh) <= 0xfff)) );
238             m_buffer.putInt(op | RN(rn) | RD(rd) | op2);
239         }
240
241         void and_r(int rd, int rn, ARMWord op2, Condition cc = AL)
242         {
243             emitInst(static_cast<ARMWord>(cc) | AND, rd, rn, op2);
244         }
245
246         void ands_r(int rd, int rn, ARMWord op2, Condition cc = AL)
247         {
248             emitInst(static_cast<ARMWord>(cc) | AND | SET_CC, rd, rn, op2);
249         }
250
251         void eor_r(int rd, int rn, ARMWord op2, Condition cc = AL)
252         {
253             emitInst(static_cast<ARMWord>(cc) | EOR, rd, rn, op2);
254         }
255
256         void eors_r(int rd, int rn, ARMWord op2, Condition cc = AL)
257         {
258             emitInst(static_cast<ARMWord>(cc) | EOR | SET_CC, rd, rn, op2);
259         }
260
261         void sub_r(int rd, int rn, ARMWord op2, Condition cc = AL)
262         {
263             emitInst(static_cast<ARMWord>(cc) | SUB, rd, rn, op2);
264         }
265
266         void subs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
267         {
268             emitInst(static_cast<ARMWord>(cc) | SUB | SET_CC, rd, rn, op2);
269         }
270
271         void rsb_r(int rd, int rn, ARMWord op2, Condition cc = AL)
272         {
273             emitInst(static_cast<ARMWord>(cc) | RSB, rd, rn, op2);
274         }
275
276         void rsbs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
277         {
278             emitInst(static_cast<ARMWord>(cc) | RSB | SET_CC, rd, rn, op2);
279         }
280
281         void add_r(int rd, int rn, ARMWord op2, Condition cc = AL)
282         {
283             emitInst(static_cast<ARMWord>(cc) | ADD, rd, rn, op2);
284         }
285
286         void adds_r(int rd, int rn, ARMWord op2, Condition cc = AL)
287         {
288             emitInst(static_cast<ARMWord>(cc) | ADD | SET_CC, rd, rn, op2);
289         }
290
291         void adc_r(int rd, int rn, ARMWord op2, Condition cc = AL)
292         {
293             emitInst(static_cast<ARMWord>(cc) | ADC, rd, rn, op2);
294         }
295
296         void adcs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
297         {
298             emitInst(static_cast<ARMWord>(cc) | ADC | SET_CC, rd, rn, op2);
299         }
300
301         void sbc_r(int rd, int rn, ARMWord op2, Condition cc = AL)
302         {
303             emitInst(static_cast<ARMWord>(cc) | SBC, rd, rn, op2);
304         }
305
306         void sbcs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
307         {
308             emitInst(static_cast<ARMWord>(cc) | SBC | SET_CC, rd, rn, op2);
309         }
310
311         void rsc_r(int rd, int rn, ARMWord op2, Condition cc = AL)
312         {
313             emitInst(static_cast<ARMWord>(cc) | RSC, rd, rn, op2);
314         }
315
316         void rscs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
317         {
318             emitInst(static_cast<ARMWord>(cc) | RSC | SET_CC, rd, rn, op2);
319         }
320
321         void tst_r(int rn, ARMWord op2, Condition cc = AL)
322         {
323             emitInst(static_cast<ARMWord>(cc) | TST | SET_CC, 0, rn, op2);
324         }
325
326         void teq_r(int rn, ARMWord op2, Condition cc = AL)
327         {
328             emitInst(static_cast<ARMWord>(cc) | TEQ | SET_CC, 0, rn, op2);
329         }
330
331         void cmp_r(int rn, ARMWord op2, Condition cc = AL)
332         {
333             emitInst(static_cast<ARMWord>(cc) | CMP | SET_CC, 0, rn, op2);
334         }
335
336         void orr_r(int rd, int rn, ARMWord op2, Condition cc = AL)
337         {
338             emitInst(static_cast<ARMWord>(cc) | ORR, rd, rn, op2);
339         }
340
341         void orrs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
342         {
343             emitInst(static_cast<ARMWord>(cc) | ORR | SET_CC, rd, rn, op2);
344         }
345
346         void mov_r(int rd, ARMWord op2, Condition cc = AL)
347         {
348             emitInst(static_cast<ARMWord>(cc) | MOV, rd, ARMRegisters::r0, op2);
349         }
350
351 #if WTF_ARM_ARCH_AT_LEAST(7)
352         void movw_r(int rd, ARMWord op2, Condition cc = AL)
353         {
354             ASSERT((op2 | 0xf0fff) == 0xf0fff);
355             m_buffer.putInt(static_cast<ARMWord>(cc) | MOVW | RD(rd) | op2);
356         }
357
358         void movt_r(int rd, ARMWord op2, Condition cc = AL)
359         {
360             ASSERT((op2 | 0xf0fff) == 0xf0fff);
361             m_buffer.putInt(static_cast<ARMWord>(cc) | MOVT | RD(rd) | op2);
362         }
363 #endif
364
365         void movs_r(int rd, ARMWord op2, Condition cc = AL)
366         {
367             emitInst(static_cast<ARMWord>(cc) | MOV | SET_CC, rd, ARMRegisters::r0, op2);
368         }
369
370         void bic_r(int rd, int rn, ARMWord op2, Condition cc = AL)
371         {
372             emitInst(static_cast<ARMWord>(cc) | BIC, rd, rn, op2);
373         }
374
375         void bics_r(int rd, int rn, ARMWord op2, Condition cc = AL)
376         {
377             emitInst(static_cast<ARMWord>(cc) | BIC | SET_CC, rd, rn, op2);
378         }
379
380         void mvn_r(int rd, ARMWord op2, Condition cc = AL)
381         {
382             emitInst(static_cast<ARMWord>(cc) | MVN, rd, ARMRegisters::r0, op2);
383         }
384
385         void mvns_r(int rd, ARMWord op2, Condition cc = AL)
386         {
387             emitInst(static_cast<ARMWord>(cc) | MVN | SET_CC, rd, ARMRegisters::r0, op2);
388         }
389
390         void mul_r(int rd, int rn, int rm, Condition cc = AL)
391         {
392             m_buffer.putInt(static_cast<ARMWord>(cc) | MUL | RN(rd) | RS(rn) | RM(rm));
393         }
394
395         void muls_r(int rd, int rn, int rm, Condition cc = AL)
396         {
397             m_buffer.putInt(static_cast<ARMWord>(cc) | MUL | SET_CC | RN(rd) | RS(rn) | RM(rm));
398         }
399
400         void mull_r(int rdhi, int rdlo, int rn, int rm, Condition cc = AL)
401         {
402             m_buffer.putInt(static_cast<ARMWord>(cc) | MULL | RN(rdhi) | RD(rdlo) | RS(rn) | RM(rm));
403         }
404
405         void faddd_r(int dd, int dn, int dm, Condition cc = AL)
406         {
407             emitInst(static_cast<ARMWord>(cc) | FADDD, dd, dn, dm);
408         }
409
410         void fdivd_r(int dd, int dn, int dm, Condition cc = AL)
411         {
412             emitInst(static_cast<ARMWord>(cc) | FDIVD, dd, dn, dm);
413         }
414
415         void fsubd_r(int dd, int dn, int dm, Condition cc = AL)
416         {
417             emitInst(static_cast<ARMWord>(cc) | FSUBD, dd, dn, dm);
418         }
419
420         void fmuld_r(int dd, int dn, int dm, Condition cc = AL)
421         {
422             emitInst(static_cast<ARMWord>(cc) | FMULD, dd, dn, dm);
423         }
424
425         void fcmpd_r(int dd, int dm, Condition cc = AL)
426         {
427             emitInst(static_cast<ARMWord>(cc) | FCMPD, dd, 0, dm);
428         }
429
430         void fsqrtd_r(int dd, int dm, Condition cc = AL)
431         {
432             emitInst(static_cast<ARMWord>(cc) | FSQRTD, dd, 0, dm);
433         }
434
435         void ldr_imm(int rd, ARMWord imm, Condition cc = AL)
436         {
437             m_buffer.putIntWithConstantInt(static_cast<ARMWord>(cc) | DTR | DT_LOAD | DT_UP | RN(ARMRegisters::pc) | RD(rd), imm, true);
438         }
439
440         void ldr_un_imm(int rd, ARMWord imm, Condition cc = AL)
441         {
442             m_buffer.putIntWithConstantInt(static_cast<ARMWord>(cc) | DTR | DT_LOAD | DT_UP | RN(ARMRegisters::pc) | RD(rd), imm);
443         }
444
445         void dtr_u(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL)
446         {
447             emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0) | DT_UP, rd, rb, op2);
448         }
449
450         void dtr_ur(bool isLoad, int rd, int rb, int rm, Condition cc = AL)
451         {
452             emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0) | DT_UP | OP2_OFSREG, rd, rb, rm);
453         }
454
455         void dtr_d(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL)
456         {
457             emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0), rd, rb, op2);
458         }
459
460         void dtr_dr(bool isLoad, int rd, int rb, int rm, Condition cc = AL)
461         {
462             emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0) | OP2_OFSREG, rd, rb, rm);
463         }
464
465         void ldrh_r(int rd, int rn, int rm, Condition cc = AL)
466         {
467             emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | DT_UP | DT_PRE, rd, rn, rm);
468         }
469
470         void ldrh_d(int rd, int rb, ARMWord op2, Condition cc = AL)
471         {
472             emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | DT_PRE, rd, rb, op2);
473         }
474
475         void ldrh_u(int rd, int rb, ARMWord op2, Condition cc = AL)
476         {
477             emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | DT_UP | DT_PRE, rd, rb, op2);
478         }
479
480         void strh_r(int rn, int rm, int rd, Condition cc = AL)
481         {
482             emitInst(static_cast<ARMWord>(cc) | STRH | HDT_UH | DT_UP | DT_PRE, rd, rn, rm);
483         }
484
485         void fdtr_u(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL)
486         {
487             ASSERT(op2 <= 0xff);
488             emitInst(static_cast<ARMWord>(cc) | FDTR | DT_UP | (isLoad ? DT_LOAD : 0), rd, rb, op2);
489         }
490
491         void fdtr_d(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL)
492         {
493             ASSERT(op2 <= 0xff);
494             emitInst(static_cast<ARMWord>(cc) | FDTR | (isLoad ? DT_LOAD : 0), rd, rb, op2);
495         }
496
497         void push_r(int reg, Condition cc = AL)
498         {
499             ASSERT(ARMWord(reg) <= 0xf);
500             m_buffer.putInt(cc | DTR | DT_WB | RN(ARMRegisters::sp) | RD(reg) | 0x4);
501         }
502
503         void pop_r(int reg, Condition cc = AL)
504         {
505             ASSERT(ARMWord(reg) <= 0xf);
506             m_buffer.putInt(cc | (DTR ^ DT_PRE) | DT_LOAD | DT_UP | RN(ARMRegisters::sp) | RD(reg) | 0x4);
507         }
508
509         inline void poke_r(int reg, Condition cc = AL)
510         {
511             dtr_d(false, ARMRegisters::sp, 0, reg, cc);
512         }
513
514         inline void peek_r(int reg, Condition cc = AL)
515         {
516             dtr_u(true, reg, ARMRegisters::sp, 0, cc);
517         }
518
519         void fmsr_r(int dd, int rn, Condition cc = AL)
520         {
521             emitInst(static_cast<ARMWord>(cc) | FMSR, rn, dd, 0);
522         }
523
524         void fmrs_r(int rd, int dn, Condition cc = AL)
525         {
526             emitInst(static_cast<ARMWord>(cc) | FMRS, rd, dn, 0);
527         }
528
529         void fsitod_r(int dd, int dm, Condition cc = AL)
530         {
531             emitInst(static_cast<ARMWord>(cc) | FSITOD, dd, 0, dm);
532         }
533
534         void ftosid_r(int fd, int dm, Condition cc = AL)
535         {
536             emitInst(static_cast<ARMWord>(cc) | FTOSID, fd, 0, dm);
537         }
538
539         void fmstat(Condition cc = AL)
540         {
541             m_buffer.putInt(static_cast<ARMWord>(cc) | FMSTAT);
542         }
543
544 #if WTF_ARM_ARCH_AT_LEAST(5)
545         void clz_r(int rd, int rm, Condition cc = AL)
546         {
547             m_buffer.putInt(static_cast<ARMWord>(cc) | CLZ | RD(rd) | RM(rm));
548         }
549 #endif
550
551         void bkpt(ARMWord value)
552         {
553 #if WTF_ARM_ARCH_AT_LEAST(5)
554             m_buffer.putInt(BKPT | ((value & 0xff0) << 4) | (value & 0xf));
555 #else
556             // Cannot access to Zero memory address
557             dtr_dr(true, ARMRegisters::S0, ARMRegisters::S0, ARMRegisters::S0);
558 #endif
559         }
560
561         void bx(int rm, Condition cc = AL)
562         {
563 #if WTF_ARM_ARCH_AT_LEAST(5) || defined(__ARM_ARCH_4T__)
564             emitInst(static_cast<ARMWord>(cc) | BX, 0, 0, RM(rm));
565 #else
566             mov_r(ARMRegisters::pc, RM(rm), cc);
567 #endif
568         }
569
570         JmpSrc blx(int rm, Condition cc = AL)
571         {
572 #if WTF_ARM_ARCH_AT_LEAST(5)
573             int s = m_buffer.uncheckedSize();
574             emitInst(static_cast<ARMWord>(cc) | BLX, 0, 0, RM(rm));
575 #else
576             ASSERT(rm != 14);
577             ensureSpace(2 * sizeof(ARMWord), 0);
578             mov_r(ARMRegisters::lr, ARMRegisters::pc, cc);
579             int s = m_buffer.uncheckedSize();
580             bx(rm, cc);
581 #endif
582             return JmpSrc(s);
583         }
584
585         static ARMWord lsl(int reg, ARMWord value)
586         {
587             ASSERT(reg <= ARMRegisters::pc);
588             ASSERT(value <= 0x1f);
589             return reg | (value << 7) | 0x00;
590         }
591
592         static ARMWord lsr(int reg, ARMWord value)
593         {
594             ASSERT(reg <= ARMRegisters::pc);
595             ASSERT(value <= 0x1f);
596             return reg | (value << 7) | 0x20;
597         }
598
599         static ARMWord asr(int reg, ARMWord value)
600         {
601             ASSERT(reg <= ARMRegisters::pc);
602             ASSERT(value <= 0x1f);
603             return reg | (value << 7) | 0x40;
604         }
605
606         static ARMWord lsl_r(int reg, int shiftReg)
607         {
608             ASSERT(reg <= ARMRegisters::pc);
609             ASSERT(shiftReg <= ARMRegisters::pc);
610             return reg | (shiftReg << 8) | 0x10;
611         }
612
613         static ARMWord lsr_r(int reg, int shiftReg)
614         {
615             ASSERT(reg <= ARMRegisters::pc);
616             ASSERT(shiftReg <= ARMRegisters::pc);
617             return reg | (shiftReg << 8) | 0x30;
618         }
619
620         static ARMWord asr_r(int reg, int shiftReg)
621         {
622             ASSERT(reg <= ARMRegisters::pc);
623             ASSERT(shiftReg <= ARMRegisters::pc);
624             return reg | (shiftReg << 8) | 0x50;
625         }
626
627         // General helpers
628
629         int size()
630         {
631             return m_buffer.size();
632         }
633
634         void ensureSpace(int insnSpace, int constSpace)
635         {
636             m_buffer.ensureSpace(insnSpace, constSpace);
637         }
638
639         int sizeOfConstantPool()
640         {
641             return m_buffer.sizeOfConstantPool();
642         }
643
644         JmpDst label()
645         {
646             return JmpDst(m_buffer.size());
647         }
648
649         JmpDst align(int alignment)
650         {
651             while (!m_buffer.isAligned(alignment))
652                 mov_r(ARMRegisters::r0, ARMRegisters::r0);
653
654             return label();
655         }
656
657         JmpSrc loadBranchTarget(int rd, Condition cc = AL, int useConstantPool = 0)
658         {
659             ensureSpace(sizeof(ARMWord), sizeof(ARMWord));
660             int s = m_buffer.uncheckedSize();
661             ldr_un_imm(rd, InvalidBranchTarget, cc);
662             m_jumps.append(s | (useConstantPool & 0x1));
663             return JmpSrc(s);
664         }
665
666         JmpSrc jmp(Condition cc = AL, int useConstantPool = 0)
667         {
668             return loadBranchTarget(ARMRegisters::pc, cc, useConstantPool);
669         }
670
671         void* executableCopy(ExecutablePool* allocator);
672
673         // Patching helpers
674
675         static ARMWord* getLdrImmAddress(ARMWord* insn)
676         {
677 #if WTF_ARM_ARCH_AT_LEAST(5)
678             // Check for call
679             if ((*insn & 0x0f7f0000) != 0x051f0000) {
680                 // Must be BLX
681                 ASSERT((*insn & 0x012fff30) == 0x012fff30);
682                 insn--;
683             }
684 #endif
685             // Must be an ldr ..., [pc +/- imm]
686             ASSERT((*insn & 0x0f7f0000) == 0x051f0000);
687
688             ARMWord addr = reinterpret_cast<ARMWord>(insn) + DefaultPrefetching * sizeof(ARMWord);
689             if (*insn & DT_UP)
690                 return reinterpret_cast<ARMWord*>(addr + (*insn & SDT_OFFSET_MASK));
691             return reinterpret_cast<ARMWord*>(addr - (*insn & SDT_OFFSET_MASK));
692         }
693
694         static ARMWord* getLdrImmAddressOnPool(ARMWord* insn, uint32_t* constPool)
695         {
696             // Must be an ldr ..., [pc +/- imm]
697             ASSERT((*insn & 0x0f7f0000) == 0x051f0000);
698
699             if (*insn & 0x1)
700                 return reinterpret_cast<ARMWord*>(constPool + ((*insn & SDT_OFFSET_MASK) >> 1));
701             return getLdrImmAddress(insn);
702         }
703
704         static void patchPointerInternal(intptr_t from, void* to)
705         {
706             ARMWord* insn = reinterpret_cast<ARMWord*>(from);
707             ARMWord* addr = getLdrImmAddress(insn);
708             *addr = reinterpret_cast<ARMWord>(to);
709         }
710
711         static ARMWord patchConstantPoolLoad(ARMWord load, ARMWord value)
712         {
713             value = (value << 1) + 1;
714             ASSERT(!(value & ~0xfff));
715             return (load & ~0xfff) | value;
716         }
717
718         static void patchConstantPoolLoad(void* loadAddr, void* constPoolAddr);
719
720         // Patch pointers
721
722         static void linkPointer(void* code, JmpDst from, void* to)
723         {
724             patchPointerInternal(reinterpret_cast<intptr_t>(code) + from.m_offset, to);
725         }
726
727         static void repatchInt32(void* from, int32_t to)
728         {
729             patchPointerInternal(reinterpret_cast<intptr_t>(from), reinterpret_cast<void*>(to));
730         }
731
732         static void repatchPointer(void* from, void* to)
733         {
734             patchPointerInternal(reinterpret_cast<intptr_t>(from), to);
735         }
736
737         static void repatchLoadPtrToLEA(void* from)
738         {
739             // On arm, this is a patch from LDR to ADD. It is restricted conversion,
740             // from special case to special case, altough enough for its purpose
741             ARMWord* insn = reinterpret_cast<ARMWord*>(from);
742             ASSERT((*insn & 0x0ff00f00) == 0x05900000);
743
744             *insn = (*insn & 0xf00ff0ff) | 0x02800000;
745             ExecutableAllocator::cacheFlush(insn, sizeof(ARMWord));
746         }
747
748         // Linkers
749
750         void linkJump(JmpSrc from, JmpDst to)
751         {
752             ARMWord* insn = reinterpret_cast<ARMWord*>(m_buffer.data()) + (from.m_offset / sizeof(ARMWord));
753             ARMWord* addr = getLdrImmAddressOnPool(insn, m_buffer.poolAddress());
754             *addr = static_cast<ARMWord>(to.m_offset);
755         }
756
757         static void linkJump(void* code, JmpSrc from, void* to)
758         {
759             patchPointerInternal(reinterpret_cast<intptr_t>(code) + from.m_offset, to);
760         }
761
762         static void relinkJump(void* from, void* to)
763         {
764             patchPointerInternal(reinterpret_cast<intptr_t>(from) - sizeof(ARMWord), to);
765         }
766
767         static void linkCall(void* code, JmpSrc from, void* to)
768         {
769             patchPointerInternal(reinterpret_cast<intptr_t>(code) + from.m_offset, to);
770         }
771
772         static void relinkCall(void* from, void* to)
773         {
774             patchPointerInternal(reinterpret_cast<intptr_t>(from) - sizeof(ARMWord), to);
775         }
776
777         // Address operations
778
779         static void* getRelocatedAddress(void* code, JmpSrc jump)
780         {
781             return reinterpret_cast<void*>(reinterpret_cast<ARMWord*>(code) + jump.m_offset / sizeof(ARMWord) + 1);
782         }
783
784         static void* getRelocatedAddress(void* code, JmpDst label)
785         {
786             return reinterpret_cast<void*>(reinterpret_cast<ARMWord*>(code) + label.m_offset / sizeof(ARMWord));
787         }
788
789         // Address differences
790
791         static int getDifferenceBetweenLabels(JmpDst from, JmpSrc to)
792         {
793             return (to.m_offset + sizeof(ARMWord)) - from.m_offset;
794         }
795
796         static int getDifferenceBetweenLabels(JmpDst from, JmpDst to)
797         {
798             return to.m_offset - from.m_offset;
799         }
800
801         static unsigned getCallReturnOffset(JmpSrc call)
802         {
803             return call.m_offset + sizeof(ARMWord);
804         }
805
806         // Handle immediates
807
808         static ARMWord getOp2Byte(ARMWord imm)
809         {
810             ASSERT(imm <= 0xff);
811             return OP2_IMMh | (imm & 0x0f) | ((imm & 0xf0) << 4) ;
812         }
813
814         static ARMWord getOp2(ARMWord imm);
815
816 #if WTF_ARM_ARCH_AT_LEAST(7)
817         static ARMWord getImm16Op2(ARMWord imm)
818         {
819             if (imm <= 0xffff)
820                 return (imm & 0xf000) << 4 | (imm & 0xfff);
821             return INVALID_IMM;
822         }
823 #endif
824         ARMWord getImm(ARMWord imm, int tmpReg, bool invert = false);
825         void moveImm(ARMWord imm, int dest);
826         ARMWord encodeComplexImm(ARMWord imm, int dest);
827
828         ARMWord getOffsetForHalfwordDataTransfer(ARMWord imm, int tmpReg)
829         {
830             // Encode immediate data in the instruction if it is possible
831             if (imm <= 0xff)
832                 return getOp2Byte(imm);
833             // Otherwise, store the data in a temporary register
834             return encodeComplexImm(imm, tmpReg);
835         }
836
837         // Memory load/store helpers
838
839         void dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset, bool bytes = false);
840         void baseIndexTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset);
841         void doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset);
842
843         // Constant pool hnadlers
844
845         static ARMWord placeConstantPoolBarrier(int offset)
846         {
847             offset = (offset - sizeof(ARMWord)) >> 2;
848             ASSERT((offset <= BOFFSET_MAX && offset >= BOFFSET_MIN));
849             return AL | B | (offset & BRANCH_MASK);
850         }
851
852     private:
853         ARMWord RM(int reg)
854         {
855             ASSERT(reg <= ARMRegisters::pc);
856             return reg;
857         }
858
859         ARMWord RS(int reg)
860         {
861             ASSERT(reg <= ARMRegisters::pc);
862             return reg << 8;
863         }
864
865         ARMWord RD(int reg)
866         {
867             ASSERT(reg <= ARMRegisters::pc);
868             return reg << 12;
869         }
870
871         ARMWord RN(int reg)
872         {
873             ASSERT(reg <= ARMRegisters::pc);
874             return reg << 16;
875         }
876
877         static ARMWord getConditionalField(ARMWord i)
878         {
879             return i & 0xf0000000;
880         }
881
882         int genInt(int reg, ARMWord imm, bool positive);
883
884         ARMBuffer m_buffer;
885         Jumps m_jumps;
886     };
887
888 } // namespace JSC
889
890 #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
891
892 #endif // ARMAssembler_h