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