Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / assembler / assembler / ARMAssembler.h
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sw=4 et tw=79:
3  *
4  * ***** BEGIN LICENSE BLOCK *****
5  * Copyright (C) 2009, 2010 University of Szeged
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  * 
29  * ***** END LICENSE BLOCK ***** */
30
31 #ifndef ARMAssembler_h
32 #define ARMAssembler_h
33
34 #include "assembler/wtf/Platform.h"
35
36 // Some debug code uses s(n)printf for instruction logging.
37 #include <stdio.h>
38
39 #if ENABLE_ASSEMBLER && WTF_CPU_ARM_TRADITIONAL
40
41 #include "AssemblerBufferWithConstantPool.h"
42 #include "assembler/wtf/Assertions.h"
43
44 #include "methodjit/Logging.h"
45 #define IPFX    "        %s"
46 #define ISPFX   "        "
47 #ifdef JS_METHODJIT_SPEW
48 # define MAYBE_PAD (isOOLPath ? ">  " : "")
49 # define FIXME_INSN_PRINTING                                \
50     do {                                                   \
51         js::JaegerSpew(js::JSpew_Insns,                    \
52                        IPFX "FIXME insn printing %s:%d\n", \
53                        MAYBE_PAD,                          \
54                        __FILE__, __LINE__);                \
55     } while (0)
56 #else
57 # define MAYBE_PAD ""
58 # define FIXME_INSN_PRINTING ((void) 0)
59 #endif
60
61 // TODO: We don't print the condition code in our JaegerSpew lines. Doing this
62 // is awkward whilst maintaining a consistent field width.
63
64 namespace JSC {
65
66     typedef uint32_t ARMWord;
67
68     namespace ARMRegisters {
69         typedef enum {
70             r0 = 0,
71             r1,
72             r2,
73             r3,
74             S0 = r3,
75             r4,
76             r5,
77             r6,
78             r7,
79             r8,
80             S1 = r8,
81             r9,
82             r10,
83             r11,
84             r12,
85             ip = r12,
86             r13,
87             sp = r13,
88             r14,
89             lr = r14,
90             r15,
91             pc = r15
92         } RegisterID;
93
94         typedef enum {
95             d0,
96             d1,
97             d2,
98             d3,
99             SD0 = d3,
100             d4,
101             d5,
102             d6,
103             d7,
104             d8,
105             d9,
106             d10,
107             d11,
108             d12,
109             d13,
110             d14,
111             d15,
112             d16,
113             d17,
114             d18,
115             d19,
116             d20,
117             d21,
118             d22,
119             d23,
120             d24,
121             d25,
122             d26,
123             d27,
124             d28,
125             d29,
126             d30,
127             d31
128         } FPRegisterID;
129
130     } // namespace ARMRegisters
131
132     class ARMAssembler {
133     public:
134         
135 #ifdef JS_METHODJIT_SPEW
136         bool isOOLPath;
137         // Assign a default value to keep Valgrind quiet.
138         ARMAssembler() : isOOLPath(false) { }
139 #else
140         ARMAssembler() { }
141 #endif
142
143         typedef ARMRegisters::RegisterID RegisterID;
144         typedef ARMRegisters::FPRegisterID FPRegisterID;
145         typedef AssemblerBufferWithConstantPool<2048, 4, 4, ARMAssembler> ARMBuffer;
146         typedef SegmentedVector<int, 64> Jumps;
147
148         unsigned char *buffer() const { return m_buffer.buffer(); }
149         bool oom() const { return m_buffer.oom(); }
150
151         // ARM conditional constants
152         typedef enum {
153             EQ = 0x00000000, // Zero
154             NE = 0x10000000, // Non-zero
155             CS = 0x20000000,
156             CC = 0x30000000,
157             MI = 0x40000000,
158             PL = 0x50000000,
159             VS = 0x60000000,
160             VC = 0x70000000,
161             HI = 0x80000000,
162             LS = 0x90000000,
163             GE = 0xa0000000,
164             LT = 0xb0000000,
165             GT = 0xc0000000,
166             LE = 0xd0000000,
167             AL = 0xe0000000
168         } Condition;
169
170         // ARM instruction constants
171         enum {
172             AND = (0x0 << 21),
173             EOR = (0x1 << 21),
174             SUB = (0x2 << 21),
175             RSB = (0x3 << 21),
176             ADD = (0x4 << 21),
177             ADC = (0x5 << 21),
178             SBC = (0x6 << 21),
179             RSC = (0x7 << 21),
180             TST = (0x8 << 21),
181             TEQ = (0x9 << 21),
182             CMP = (0xa << 21),
183             CMN = (0xb << 21),
184             ORR = (0xc << 21),
185             MOV = (0xd << 21),
186             BIC = (0xe << 21),
187             MVN = (0xf << 21),
188             MUL = 0x00000090,
189             MULL = 0x00c00090,
190             FCPYD = 0x0eb00b40,
191             FADDD = 0x0e300b00,
192             FNEGD = 0x0eb10b40,
193             FDIVD = 0x0e800b00,
194             FSUBD = 0x0e300b40,
195             FMULD = 0x0e200b00,
196             FCMPD = 0x0eb40b40,
197             FSQRTD = 0x0eb10bc0,
198             DTR = 0x05000000,
199             LDRH = 0x00100090,
200             STRH = 0x00000090,
201             STMDB = 0x09200000,
202             LDMIA = 0x08b00000,
203             FDTR = 0x0d000b00,
204             B = 0x0a000000,
205             BL = 0x0b000000
206 #if WTF_ARM_ARCH_VERSION >= 5 || defined(__ARM_ARCH_4T__)
207            ,BX = 0x012fff10
208 #endif
209            ,FMSR = 0x0e000a10,
210             FMRS = 0x0e100a10,
211             FSITOD = 0x0eb80bc0,
212             FTOSID = 0x0ebd0b40,
213             FTOSIZD = 0x0ebd0bc0,
214             FMSTAT = 0x0ef1fa10
215 #if WTF_ARM_ARCH_VERSION >= 5
216            ,CLZ = 0x016f0f10,
217             BKPT = 0xe1200070,
218             BLX = 0x012fff30
219 #endif
220 #if WTF_ARM_ARCH_VERSION >= 7
221            ,MOVW = 0x03000000,
222             MOVT = 0x03400000
223 #endif
224         };
225
226         enum {
227             OP2_IMM = (1 << 25),
228             OP2_IMMh = (1 << 22),
229             OP2_INV_IMM = (1 << 26),
230             SET_CC = (1 << 20),
231             OP2_OFSREG = (1 << 25),
232             DT_UP = (1 << 23),
233             DT_BYTE = (1 << 22),
234             DT_WB = (1 << 21),
235             // This flag is inlcuded in LDR and STR
236             DT_PRE = (1 << 24),
237             HDT_UH = (1 << 5),
238             DT_LOAD = (1 << 20)
239         };
240
241         // Masks of ARM instructions
242         enum {
243             BRANCH_MASK = 0x00ffffff,
244             NONARM = 0xf0000000,
245             SDT_MASK = 0x0c000000,
246             SDT_OFFSET_MASK = 0xfff
247         };
248
249         enum {
250             BOFFSET_MIN = -0x00800000,
251             BOFFSET_MAX = 0x007fffff,
252             SDT = 0x04000000
253         };
254
255         enum {
256             padForAlign8  = (int)0x00,
257             padForAlign16 = (int)0x0000,
258             padForAlign32 = (int)0xe12fff7f  // 'bkpt 0xffff'
259         };
260
261         typedef enum {
262             LSL = 0,
263             LSR = 1,
264             ASR = 2,
265             ROR = 3
266         } Shift;
267
268         static const ARMWord INVALID_IMM = 0xf0000000;
269         static const ARMWord InvalidBranchTarget = 0xffffffff;
270         static const int DefaultPrefetching = 2;
271
272         class JmpSrc {
273             friend class ARMAssembler;
274         public:
275             JmpSrc()
276                 : m_offset(-1)
277             {
278             }
279
280         private:
281             JmpSrc(int offset)
282                 : m_offset(offset)
283             {
284             }
285
286             int m_offset;
287         };
288
289         class JmpDst {
290             friend class ARMAssembler;
291         public:
292             JmpDst()
293                 : m_offset(-1)
294                 , m_used(false)
295             {
296             }
297
298             bool isUsed() const { return m_used; }
299             void used() { m_used = true; }
300             bool isValid() const { return m_offset != -1; }
301         private:
302             JmpDst(int offset)
303                 : m_offset(offset)
304                 , m_used(false)
305             {
306                 ASSERT(m_offset == offset);
307             }
308
309             int m_offset : 31;
310             bool m_used : 1;
311         };
312
313         // Instruction formating
314
315         void emitInst(ARMWord op, int rd, int rn, ARMWord op2)
316         {
317             ASSERT ( ((op2 & ~OP2_IMM) <= 0xfff) || (((op2 & ~OP2_IMMh) <= 0xfff)) );
318             m_buffer.putInt(op | RN(rn) | RD(rd) | op2);
319         }
320
321         void and_r(int rd, int rn, ARMWord op2, Condition cc = AL)
322         {
323             spewInsWithOp2("and", cc, rd, rn, op2);
324             emitInst(static_cast<ARMWord>(cc) | AND, rd, rn, op2);
325         }
326
327         void ands_r(int rd, int rn, ARMWord op2, Condition cc = AL)
328         {
329             spewInsWithOp2("ands", cc, rd, rn, op2);
330             emitInst(static_cast<ARMWord>(cc) | AND | SET_CC, rd, rn, op2);
331         }
332
333         void eor_r(int rd, int rn, ARMWord op2, Condition cc = AL)
334         {
335             spewInsWithOp2("eor", cc, rd, rn, op2);
336             emitInst(static_cast<ARMWord>(cc) | EOR, rd, rn, op2);
337         }
338
339         void eors_r(int rd, int rn, ARMWord op2, Condition cc = AL)
340         {
341             spewInsWithOp2("eors", cc, rd, rn, op2);
342             emitInst(static_cast<ARMWord>(cc) | EOR | SET_CC, rd, rn, op2);
343         }
344
345         void sub_r(int rd, int rn, ARMWord op2, Condition cc = AL)
346         {
347             spewInsWithOp2("sub", cc, rd, rn, op2);
348             emitInst(static_cast<ARMWord>(cc) | SUB, rd, rn, op2);
349         }
350
351         void subs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
352         {
353             spewInsWithOp2("subs", cc, rd, rn, op2);
354             emitInst(static_cast<ARMWord>(cc) | SUB | SET_CC, rd, rn, op2);
355         }
356
357         void rsb_r(int rd, int rn, ARMWord op2, Condition cc = AL)
358         {
359             spewInsWithOp2("rsb", cc, rd, rn, op2);
360             emitInst(static_cast<ARMWord>(cc) | RSB, rd, rn, op2);
361         }
362
363         void rsbs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
364         {
365             spewInsWithOp2("rsbs", cc, rd, rn, op2);
366             emitInst(static_cast<ARMWord>(cc) | RSB | SET_CC, rd, rn, op2);
367         }
368
369         void add_r(int rd, int rn, ARMWord op2, Condition cc = AL)
370         {
371             spewInsWithOp2("add", cc, rd, rn, op2);
372             emitInst(static_cast<ARMWord>(cc) | ADD, rd, rn, op2);
373         }
374
375         void adds_r(int rd, int rn, ARMWord op2, Condition cc = AL)
376         {
377             spewInsWithOp2("adds", cc, rd, rn, op2);
378             emitInst(static_cast<ARMWord>(cc) | ADD | SET_CC, rd, rn, op2);
379         }
380
381         void adc_r(int rd, int rn, ARMWord op2, Condition cc = AL)
382         {
383             spewInsWithOp2("adc", cc, rd, rn, op2);
384             emitInst(static_cast<ARMWord>(cc) | ADC, rd, rn, op2);
385         }
386
387         void adcs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
388         {
389             spewInsWithOp2("adcs", cc, rd, rn, op2);
390             emitInst(static_cast<ARMWord>(cc) | ADC | SET_CC, rd, rn, op2);
391         }
392
393         void sbc_r(int rd, int rn, ARMWord op2, Condition cc = AL)
394         {
395             spewInsWithOp2("sbc", cc, rd, rn, op2);
396             emitInst(static_cast<ARMWord>(cc) | SBC, rd, rn, op2);
397         }
398
399         void sbcs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
400         {
401             spewInsWithOp2("sbcs", cc, rd, rn, op2);
402             emitInst(static_cast<ARMWord>(cc) | SBC | SET_CC, rd, rn, op2);
403         }
404
405         void rsc_r(int rd, int rn, ARMWord op2, Condition cc = AL)
406         {
407             spewInsWithOp2("rsc", cc, rd, rn, op2);
408             emitInst(static_cast<ARMWord>(cc) | RSC, rd, rn, op2);
409         }
410
411         void rscs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
412         {
413             spewInsWithOp2("rscs", cc, rd, rn, op2);
414             emitInst(static_cast<ARMWord>(cc) | RSC | SET_CC, rd, rn, op2);
415         }
416
417         void tst_r(int rn, ARMWord op2, Condition cc = AL)
418         {
419             spewInsWithOp2("tst", cc, rn, op2);
420             emitInst(static_cast<ARMWord>(cc) | TST | SET_CC, 0, rn, op2);
421         }
422
423         void teq_r(int rn, ARMWord op2, Condition cc = AL)
424         {
425             spewInsWithOp2("teq", cc, rn, op2);
426             emitInst(static_cast<ARMWord>(cc) | TEQ | SET_CC, 0, rn, op2);
427         }
428
429         void cmp_r(int rn, ARMWord op2, Condition cc = AL)
430         {
431             spewInsWithOp2("cmp", cc, rn, op2);
432             emitInst(static_cast<ARMWord>(cc) | CMP | SET_CC, 0, rn, op2);
433         }
434
435         void cmn_r(int rn, ARMWord op2, Condition cc = AL)
436         {
437             spewInsWithOp2("cmn", cc, rn, op2);
438             emitInst(static_cast<ARMWord>(cc) | CMN | SET_CC, 0, rn, op2);
439         }
440
441         void orr_r(int rd, int rn, ARMWord op2, Condition cc = AL)
442         {
443             spewInsWithOp2("orr", cc, rd, rn, op2);
444             emitInst(static_cast<ARMWord>(cc) | ORR, rd, rn, op2);
445         }
446
447         void orrs_r(int rd, int rn, ARMWord op2, Condition cc = AL)
448         {
449             spewInsWithOp2("orrs", cc, rd, rn, op2);
450             emitInst(static_cast<ARMWord>(cc) | ORR | SET_CC, rd, rn, op2);
451         }
452
453         void mov_r(int rd, ARMWord op2, Condition cc = AL)
454         {
455             spewInsWithOp2("mov", cc, rd, op2);
456             emitInst(static_cast<ARMWord>(cc) | MOV, rd, ARMRegisters::r0, op2);
457         }
458
459 #if WTF_ARM_ARCH_VERSION >= 7
460         void movw_r(int rd, ARMWord op2, Condition cc = AL)
461         {
462             ASSERT((op2 | 0xf0fff) == 0xf0fff);
463             js::JaegerSpew(js::JSpew_Insns,
464                     IPFX    "%-15s %s, 0x%04x\n", MAYBE_PAD, "movw", nameGpReg(rd), (op2 & 0xfff) | ((op2 >> 4) & 0xf000));
465             m_buffer.putInt(static_cast<ARMWord>(cc) | MOVW | RD(rd) | op2);
466         }
467
468         void movt_r(int rd, ARMWord op2, Condition cc = AL)
469         {
470             ASSERT((op2 | 0xf0fff) == 0xf0fff);
471             js::JaegerSpew(js::JSpew_Insns,
472                     IPFX    "%-15s %s, 0x%04x\n", MAYBE_PAD, "movt", nameGpReg(rd), (op2 & 0xfff) | ((op2 >> 4) & 0xf000));
473             m_buffer.putInt(static_cast<ARMWord>(cc) | MOVT | RD(rd) | op2);
474         }
475 #endif
476
477         void movs_r(int rd, ARMWord op2, Condition cc = AL)
478         {
479             spewInsWithOp2("movs", cc, rd, op2);
480             emitInst(static_cast<ARMWord>(cc) | MOV | SET_CC, rd, ARMRegisters::r0, op2);
481         }
482
483         void bic_r(int rd, int rn, ARMWord op2, Condition cc = AL)
484         {
485             spewInsWithOp2("bic", cc, rd, rn, op2);
486             emitInst(static_cast<ARMWord>(cc) | BIC, rd, rn, op2);
487         }
488
489         void bics_r(int rd, int rn, ARMWord op2, Condition cc = AL)
490         {
491             spewInsWithOp2("bics", cc, rd, rn, op2);
492             emitInst(static_cast<ARMWord>(cc) | BIC | SET_CC, rd, rn, op2);
493         }
494
495         void mvn_r(int rd, ARMWord op2, Condition cc = AL)
496         {
497             spewInsWithOp2("mvn", cc, rd, op2);
498             emitInst(static_cast<ARMWord>(cc) | MVN, rd, ARMRegisters::r0, op2);
499         }
500
501         void mvns_r(int rd, ARMWord op2, Condition cc = AL)
502         {
503             spewInsWithOp2("mvns", cc, rd, op2);
504             emitInst(static_cast<ARMWord>(cc) | MVN | SET_CC, rd, ARMRegisters::r0, op2);
505         }
506
507         void mul_r(int rd, int rn, int rm, Condition cc = AL)
508         {
509             spewInsWithOp2("mul", cc, rd, rn, static_cast<ARMWord>(rm));
510             m_buffer.putInt(static_cast<ARMWord>(cc) | MUL | RN(rd) | RS(rn) | RM(rm));
511         }
512
513         void muls_r(int rd, int rn, int rm, Condition cc = AL)
514         {
515             spewInsWithOp2("muls", cc, rd, rn, static_cast<ARMWord>(rm));
516             m_buffer.putInt(static_cast<ARMWord>(cc) | MUL | SET_CC | RN(rd) | RS(rn) | RM(rm));
517         }
518
519         void mull_r(int rdhi, int rdlo, int rn, int rm, Condition cc = AL)
520         {
521             js::JaegerSpew(js::JSpew_Insns,
522                     IPFX   "%-15s %s, %s, %s, %s\n", MAYBE_PAD, "mull", nameGpReg(rdlo), nameGpReg(rdhi), nameGpReg(rn), nameGpReg(rm));
523             m_buffer.putInt(static_cast<ARMWord>(cc) | MULL | RN(rdhi) | RD(rdlo) | RS(rn) | RM(rm));
524         }
525
526         void fcpyd_r(int dd, int dm, Condition cc = AL)
527         {
528             js::JaegerSpew(js::JSpew_Insns,
529                     IPFX   "%-15s %s, %s, %s\n", MAYBE_PAD, "vmov.f64", nameFpRegD(dd), nameFpRegD(dm));
530             // TODO: emitInst doesn't work for VFP instructions, though it
531             // seems to work for current usage.
532             emitInst(static_cast<ARMWord>(cc) | FCPYD, dd, dd, dm);
533         }
534
535         void faddd_r(int dd, int dn, int dm, Condition cc = AL)
536         {
537             js::JaegerSpew(js::JSpew_Insns,
538                     IPFX   "%-15s %s, %s, %s\n", MAYBE_PAD, "vadd.f64", nameFpRegD(dd), nameFpRegD(dn), nameFpRegD(dm));
539             // TODO: emitInst doesn't work for VFP instructions, though it
540             // seems to work for current usage.
541             emitInst(static_cast<ARMWord>(cc) | FADDD, dd, dn, dm);
542         }
543
544         void fnegd_r(int dd, int dm, Condition cc = AL)
545         {
546             js::JaegerSpew(js::JSpew_Insns,
547                     IPFX   "%-15s %s, %s, %s, %s\n", MAYBE_PAD, "fnegd", nameFpRegD(dd), nameFpRegD(dm));
548             m_buffer.putInt(static_cast<ARMWord>(cc) | FNEGD | DD(dd) | DM(dm));
549         }
550
551         void fdivd_r(int dd, int dn, int dm, Condition cc = AL)
552         {
553             js::JaegerSpew(js::JSpew_Insns,
554                     IPFX   "%-15s %s, %s, %s\n", MAYBE_PAD, "vdiv.f64", nameFpRegD(dd), nameFpRegD(dn), nameFpRegD(dm));
555             // TODO: emitInst doesn't work for VFP instructions, though it
556             // seems to work for current usage.
557             emitInst(static_cast<ARMWord>(cc) | FDIVD, dd, dn, dm);
558         }
559
560         void fsubd_r(int dd, int dn, int dm, Condition cc = AL)
561         {
562             js::JaegerSpew(js::JSpew_Insns,
563                     IPFX   "%-15s %s, %s, %s\n", MAYBE_PAD, "vsub.f64", nameFpRegD(dd), nameFpRegD(dn), nameFpRegD(dm));
564             // TODO: emitInst doesn't work for VFP instructions, though it
565             // seems to work for current usage.
566             emitInst(static_cast<ARMWord>(cc) | FSUBD, dd, dn, dm);
567         }
568
569         void fmuld_r(int dd, int dn, int dm, Condition cc = AL)
570         {
571             js::JaegerSpew(js::JSpew_Insns,
572                     IPFX   "%-15s %s, %s, %s\n", MAYBE_PAD, "vmul.f64", nameFpRegD(dd), nameFpRegD(dn), nameFpRegD(dm));
573             // TODO: emitInst doesn't work for VFP instructions, though it
574             // seems to work for current usage.
575             emitInst(static_cast<ARMWord>(cc) | FMULD, dd, dn, dm);
576         }
577
578         void fcmpd_r(int dd, int dm, Condition cc = AL)
579         {
580             js::JaegerSpew(js::JSpew_Insns,
581                     IPFX   "%-15s %s, %s\n", MAYBE_PAD, "vcmp.f64", nameFpRegD(dd), nameFpRegD(dm));
582             // TODO: emitInst doesn't work for VFP instructions, though it
583             // seems to work for current usage.
584             emitInst(static_cast<ARMWord>(cc) | FCMPD, dd, 0, dm);
585         }
586
587         void fsqrtd_r(int dd, int dm, Condition cc = AL)
588         {
589             js::JaegerSpew(js::JSpew_Insns,
590                     IPFX   "%-15s %s, %s\n", MAYBE_PAD, "vsqrt.f64", nameFpRegD(dd), nameFpRegD(dm));
591             // TODO: emitInst doesn't work for VFP instructions, though it
592             // seems to work for current usage.
593             emitInst(static_cast<ARMWord>(cc) | FSQRTD, dd, 0, dm);
594         }
595
596         void ldr_imm(int rd, ARMWord imm, Condition cc = AL)
597         {
598             char mnemonic[16];
599             snprintf(mnemonic, 16, "ldr%s", nameCC(cc));
600             js::JaegerSpew(js::JSpew_Insns,
601                     IPFX    "%-15s %s, =0x%x @ (%d) (reusable pool entry)\n", MAYBE_PAD, mnemonic, nameGpReg(rd), imm, static_cast<int32_t>(imm));
602             m_buffer.putIntWithConstantInt(static_cast<ARMWord>(cc) | DTR | DT_LOAD | DT_UP | RN(ARMRegisters::pc) | RD(rd), imm, true);
603         }
604
605         void ldr_un_imm(int rd, ARMWord imm, Condition cc = AL)
606         {
607             char mnemonic[16];
608             snprintf(mnemonic, 16, "ldr%s", nameCC(cc));
609             js::JaegerSpew(js::JSpew_Insns,
610                     IPFX    "%-15s %s, =0x%x @ (%d)\n", MAYBE_PAD, mnemonic, nameGpReg(rd), imm, static_cast<int32_t>(imm));
611             m_buffer.putIntWithConstantInt(static_cast<ARMWord>(cc) | DTR | DT_LOAD | DT_UP | RN(ARMRegisters::pc) | RD(rd), imm);
612         }
613
614         // Data transfers like this:
615         //  LDR rd, [rb, +offset]
616         //  STR rd, [rb, +offset]
617         void dtr_u(bool isLoad, int rd, int rb, ARMWord offset, Condition cc = AL)
618         {
619             char const * mnemonic = (isLoad) ? ("ldr") : ("str");
620             js::JaegerSpew(js::JSpew_Insns,
621                     IPFX   "%-15s %s, [%s, #+%u]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), offset);
622             emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0) | DT_UP, rd, rb, offset);
623         }
624
625         // Data transfers like this:
626         //  LDR rd, [rb, +rm]
627         //  STR rd, [rb, +rm]
628         void dtr_ur(bool isLoad, int rd, int rb, int rm, Condition cc = AL)
629         {
630             char const * mnemonic = (isLoad) ? ("ldr") : ("str");
631             js::JaegerSpew(js::JSpew_Insns,
632                     IPFX   "%-15s %s, [%s, +%s]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), nameGpReg(rm));
633             emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0) | DT_UP | OP2_OFSREG, rd, rb, rm);
634         }
635
636         // Data transfers like this:
637         //  LDR rd, [rb, -offset]
638         //  STR rd, [rb, -offset]
639         void dtr_d(bool isLoad, int rd, int rb, ARMWord offset, Condition cc = AL)
640         {
641             char const * mnemonic = (isLoad) ? ("ldr") : ("str");
642             js::JaegerSpew(js::JSpew_Insns,
643                     IPFX   "%-15s %s, [%s, #-%u]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), offset);
644             emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0), rd, rb, offset);
645         }
646
647         // Data transfers like this:
648         //  LDR rd, [rb, -rm]
649         //  STR rd, [rb, -rm]
650         void dtr_dr(bool isLoad, int rd, int rb, int rm, Condition cc = AL)
651         {
652             char const * mnemonic = (isLoad) ? ("ldr") : ("str");
653             js::JaegerSpew(js::JSpew_Insns,
654                     IPFX   "%-15s %s, [%s, -%s]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), nameGpReg(rm));
655             emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0) | OP2_OFSREG, rd, rb, rm);
656         }
657
658         // Data transfers like this:
659         //  LDRB rd, [rb, +offset]
660         //  STRB rd, [rb, +offset]
661         void dtrb_u(bool isLoad, int rd, int rb, ARMWord offset, Condition cc = AL)
662         {
663             char const * mnemonic = (isLoad) ? ("ldrb") : ("strb");
664             js::JaegerSpew(js::JSpew_Insns,
665                     IPFX   "%-15s %s, [%s, #+%u]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), offset);
666             emitInst(static_cast<ARMWord>(cc) | DTR | DT_BYTE | (isLoad ? DT_LOAD : 0) | DT_UP, rd, rb, offset);
667         }
668
669         // Data transfers like this:
670         //  LDRB rd, [rb, +rm]
671         //  STRB rd, [rb, +rm]
672         void dtrb_ur(bool isLoad, int rd, int rb, int rm, Condition cc = AL)
673         {
674             char const * mnemonic = (isLoad) ? ("ldrb") : ("strb");
675             js::JaegerSpew(js::JSpew_Insns,
676                     IPFX   "%-15s %s, [%s, +%s]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), nameGpReg(rm));
677             emitInst(static_cast<ARMWord>(cc) | DTR | DT_BYTE | (isLoad ? DT_LOAD : 0) | DT_UP | OP2_OFSREG, rd, rb, rm);
678         }
679
680         // Data transfers like this:
681         //  LDRB rd, [rb, -offset]
682         //  STRB rd, [rb, -offset]
683         void dtrb_d(bool isLoad, int rd, int rb, ARMWord offset, Condition cc = AL)
684         {
685             char const * mnemonic = (isLoad) ? ("ldrb") : ("strb");
686             js::JaegerSpew(js::JSpew_Insns,
687                     IPFX   "%-15s %s, [%s, #-%u]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), offset);
688             emitInst(static_cast<ARMWord>(cc) | DTR | DT_BYTE | (isLoad ? DT_LOAD : 0), rd, rb, offset);
689         }
690
691         // Data transfers like this:
692         //  LDRB rd, [rb, -rm]
693         //  STRB rd, [rb, -rm]
694         void dtrb_dr(bool isLoad, int rd, int rb, int rm, Condition cc = AL)
695         {
696             char const * mnemonic = (isLoad) ? ("ldrb") : ("strb");
697             js::JaegerSpew(js::JSpew_Insns,
698                     IPFX   "%-15s %s, [%s, -%s]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), nameGpReg(rm));
699             emitInst(static_cast<ARMWord>(cc) | DTR | DT_BYTE | (isLoad ? DT_LOAD : 0) | OP2_OFSREG, rd, rb, rm);
700         }
701
702         void ldrh_r(int rd, int rb, int rm, Condition cc = AL)
703         {
704             js::JaegerSpew(js::JSpew_Insns,
705                     IPFX   "%-15s %s, [%s, +%s]\n", MAYBE_PAD, "ldrh", nameGpReg(rd), nameGpReg(rb), nameGpReg(rm));
706             emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | DT_UP | DT_PRE, rd, rb, rm);
707         }
708
709         void ldrh_d(int rd, int rb, ARMWord offset, Condition cc = AL)
710         {
711             js::JaegerSpew(js::JSpew_Insns,
712                     IPFX   "%-15s %s, [%s, #-%u]\n", MAYBE_PAD, "ldrh", nameGpReg(rd), nameGpReg(rb), offset);
713             emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | DT_PRE, rd, rb, offset);
714         }
715
716         void ldrh_u(int rd, int rb, ARMWord offset, Condition cc = AL)
717         {
718             js::JaegerSpew(js::JSpew_Insns,
719                     IPFX   "%-15s %s, [%s, #+%u]\n", MAYBE_PAD, "ldrh", nameGpReg(rd), nameGpReg(rb), offset);
720             emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | DT_UP | DT_PRE, rd, rb, offset);
721         }
722
723         void strh_r(int rb, int rm, int rd, Condition cc = AL)
724         {
725             js::JaegerSpew(js::JSpew_Insns,
726                     IPFX   "%-15s %s, [%s, +%s]\n", MAYBE_PAD, "strh", nameGpReg(rd), nameGpReg(rb), nameGpReg(rm));
727             emitInst(static_cast<ARMWord>(cc) | STRH | HDT_UH | DT_UP | DT_PRE, rd, rb, rm);
728         }
729
730         void fdtr_u(bool isLoad, int dd, int rn, ARMWord offset, Condition cc = AL)
731         {
732             char const * ins = isLoad ? "vldr.f64" : "vstr.f64";
733             js::JaegerSpew(js::JSpew_Insns,
734                     IPFX   "%-15s %s, [%s, #+%u]\n", MAYBE_PAD, ins, nameFpRegD(dd), nameGpReg(rn), offset);
735             ASSERT(offset <= 0xff);
736             emitInst(static_cast<ARMWord>(cc) | FDTR | DT_UP | (isLoad ? DT_LOAD : 0), dd, rn, offset);
737         }
738
739         void fdtr_d(bool isLoad, int dd, int rn, ARMWord offset, Condition cc = AL)
740         {
741             char const * ins = isLoad ? "vldr.f64" : "vstr.f64";
742             js::JaegerSpew(js::JSpew_Insns,
743                     IPFX   "%-15s %s, [%s, #-%u]\n", MAYBE_PAD, ins, nameFpRegD(dd), nameGpReg(rn), offset);
744             ASSERT(offset <= 0xff);
745             emitInst(static_cast<ARMWord>(cc) | FDTR | (isLoad ? DT_LOAD : 0), dd, rn, offset);
746         }
747
748         void push_r(int reg, Condition cc = AL)
749         {
750             js::JaegerSpew(js::JSpew_Insns,
751                     IPFX   "%-15s {%s}\n", MAYBE_PAD, "push", nameGpReg(reg));
752             ASSERT(ARMWord(reg) <= 0xf);
753             m_buffer.putInt(cc | DTR | DT_WB | RN(ARMRegisters::sp) | RD(reg) | 0x4);
754         }
755
756         void pop_r(int reg, Condition cc = AL)
757         {
758             js::JaegerSpew(js::JSpew_Insns,
759                     IPFX   "%-15s {%s}\n", MAYBE_PAD, "pop", nameGpReg(reg));
760             ASSERT(ARMWord(reg) <= 0xf);
761             m_buffer.putInt(cc | (DTR ^ DT_PRE) | DT_LOAD | DT_UP | RN(ARMRegisters::sp) | RD(reg) | 0x4);
762         }
763
764         inline void poke_r(int reg, Condition cc = AL)
765         {
766             dtr_d(false, ARMRegisters::sp, 0, reg, cc);
767         }
768
769         inline void peek_r(int reg, Condition cc = AL)
770         {
771             dtr_u(true, reg, ARMRegisters::sp, 0, cc);
772         }
773
774         void fmsr_r(int dd, int rn, Condition cc = AL)
775         {
776             // TODO: emitInst doesn't work for VFP instructions, though it
777             // seems to work for current usage.
778             emitInst(static_cast<ARMWord>(cc) | FMSR, rn, dd, 0);
779         }
780
781         void fmrs_r(int rd, int dn, Condition cc = AL)
782         {
783             // TODO: emitInst doesn't work for VFP instructions, though it
784             // seems to work for current usage.
785             emitInst(static_cast<ARMWord>(cc) | FMRS, rd, dn, 0);
786         }
787
788         void fsitod_r(int dd, int dm, Condition cc = AL)
789         {
790             // TODO: emitInst doesn't work for VFP instructions, though it
791             // seems to work for current usage.
792             emitInst(static_cast<ARMWord>(cc) | FSITOD, dd, 0, dm);
793         }
794
795         void ftosid_r(int fd, int dm, Condition cc = AL)
796         {
797             // TODO: emitInst doesn't work for VFP instructions, though it
798             // seems to work for current usage.
799             emitInst(static_cast<ARMWord>(cc) | FTOSID, fd, 0, dm);
800         }
801
802         void ftosizd_r(int fd, int dm, Condition cc = AL)
803         {
804             // TODO: emitInst doesn't work for VFP instructions, though it
805             // seems to work for current usage.
806             emitInst(static_cast<ARMWord>(cc) | FTOSIZD, fd, 0, dm);
807         }
808
809         void fmstat(Condition cc = AL)
810         {
811             // TODO: emitInst doesn't work for VFP instructions, though it
812             // seems to work for current usage.
813             m_buffer.putInt(static_cast<ARMWord>(cc) | FMSTAT);
814         }
815
816 #if WTF_ARM_ARCH_VERSION >= 5
817         void clz_r(int rd, int rm, Condition cc = AL)
818         {
819             spewInsWithOp2("clz", cc, rd, static_cast<ARMWord>(rm));
820             m_buffer.putInt(static_cast<ARMWord>(cc) | CLZ | RD(rd) | RM(rm));
821         }
822 #endif
823
824         void bkpt(ARMWord value)
825         {
826 #if WTF_ARM_ARCH_VERSION >= 5
827             js::JaegerSpew(js::JSpew_Insns,
828                     IPFX   "%-15s #0x%04x\n", MAYBE_PAD, "bkpt", value);
829             m_buffer.putInt(BKPT | ((value & 0xfff0) << 4) | (value & 0xf));
830 #else
831             // Cannot access to Zero memory address
832             dtr_dr(true, ARMRegisters::S0, ARMRegisters::S0, ARMRegisters::S0);
833 #endif
834         }
835
836         void bx(int rm, Condition cc = AL)
837         {
838 #if WTF_ARM_ARCH_VERSION >= 5 || defined(__ARM_ARCH_4T__)
839             js::JaegerSpew(
840                     js::JSpew_Insns,
841                     IPFX    "bx%-13s %s\n", MAYBE_PAD, nameCC(cc), nameGpReg(rm));
842             emitInst(static_cast<ARMWord>(cc) | BX, 0, 0, RM(rm));
843 #else
844             mov_r(ARMRegisters::pc, RM(rm), cc);
845 #endif
846         }
847
848         JmpSrc blx(int rm, Condition cc = AL)
849         {
850 #if WTF_ARM_ARCH_AT_LEAST(5)
851             int s = m_buffer.uncheckedSize();
852             js::JaegerSpew(
853                     js::JSpew_Insns,
854                     IPFX    "blx%-12s %s\n", MAYBE_PAD, nameCC(cc), nameGpReg(rm));
855             emitInst(static_cast<ARMWord>(cc) | BLX, 0, 0, RM(rm));
856 #else
857             ASSERT(rm != 14);
858             ensureSpace(2 * sizeof(ARMWord), 0);
859             mov_r(ARMRegisters::lr, ARMRegisters::pc, cc);
860             int s = m_buffer.uncheckedSize();
861             bx(rm, cc);
862 #endif
863             return JmpSrc(s);
864         }
865
866         static ARMWord lsl(int reg, ARMWord value)
867         {
868             ASSERT(reg <= ARMRegisters::pc);
869             ASSERT(value <= 0x1f);
870             return reg | (value << 7) | (LSL << 5);
871         }
872
873         static ARMWord lsr(int reg, ARMWord value)
874         {
875             ASSERT(reg <= ARMRegisters::pc);
876             ASSERT(value <= 0x1f);
877             return reg | (value << 7) | (LSR << 5);
878         }
879
880         static ARMWord asr(int reg, ARMWord value)
881         {
882             ASSERT(reg <= ARMRegisters::pc);
883             ASSERT(value <= 0x1f);
884             return reg | (value << 7) | (ASR << 5);
885         }
886
887         static ARMWord lsl_r(int reg, int shiftReg)
888         {
889             ASSERT(reg <= ARMRegisters::pc);
890             ASSERT(shiftReg <= ARMRegisters::pc);
891             return reg | (shiftReg << 8) | (LSL << 5) | 0x10;
892         }
893
894         static ARMWord lsr_r(int reg, int shiftReg)
895         {
896             ASSERT(reg <= ARMRegisters::pc);
897             ASSERT(shiftReg <= ARMRegisters::pc);
898             return reg | (shiftReg << 8) | (LSR << 5) | 0x10;
899         }
900
901         static ARMWord asr_r(int reg, int shiftReg)
902         {
903             ASSERT(reg <= ARMRegisters::pc);
904             ASSERT(shiftReg <= ARMRegisters::pc);
905             return reg | (shiftReg << 8) | (ASR << 5) | 0x10;
906         }
907
908         // General helpers
909
910         void forceFlushConstantPool()
911         {
912             m_buffer.flushWithoutBarrier(true);
913         }
914
915         int size()
916         {
917             return m_buffer.size();
918         }
919
920         void ensureSpace(int insnSpace, int constSpace)
921         {
922             m_buffer.ensureSpace(insnSpace, constSpace);
923         }
924
925         void ensureSpace(int space)
926         {
927             m_buffer.ensureSpace(space);
928         }
929
930         int sizeOfConstantPool()
931         {
932             return m_buffer.sizeOfConstantPool();
933         }
934
935 #ifdef DEBUG
936         void allowPoolFlush(bool allowFlush)
937         {
938             m_buffer.allowPoolFlush(allowFlush);
939         }
940 #endif
941
942         JmpDst label()
943         {
944             JmpDst label(m_buffer.size());
945             js::JaegerSpew(js::JSpew_Insns, IPFX "#label     ((%d))\n", MAYBE_PAD, label.m_offset);
946             return label;
947         }
948
949         JmpDst align(int alignment)
950         {
951             while (!m_buffer.isAligned(alignment))
952                 mov_r(ARMRegisters::r0, ARMRegisters::r0);
953
954             return label();
955         }
956
957         JmpSrc loadBranchTarget(int rd, Condition cc = AL, int useConstantPool = 0)
958         {
959             // The 'useConstantPool' flag really just indicates where we have
960             // to use the constant pool, for repatching. We might still use it,
961             // so ensure there's space for a pool constant irrespective of
962             // 'useConstantPool'.
963             ensureSpace(sizeof(ARMWord), sizeof(ARMWord));
964             int s = m_buffer.uncheckedSize();
965             ldr_un_imm(rd, InvalidBranchTarget, cc);
966             m_jumps.append(s | (useConstantPool & 0x1));
967             return JmpSrc(s);
968         }
969
970         JmpSrc jmp(Condition cc = AL, int useConstantPool = 0)
971         {
972             return loadBranchTarget(ARMRegisters::pc, cc, useConstantPool);
973         }
974
975         void* executableCopy(ExecutablePool* allocator);
976         void* executableCopy(void* buffer);
977         void fixUpOffsets(void* buffer);
978
979         // Patching helpers
980
981         static ARMWord* getLdrImmAddress(ARMWord* insn)
982         {
983 #if WTF_ARM_ARCH_AT_LEAST(5)
984             // Check for call
985             if ((*insn & 0x0f7f0000) != 0x051f0000) {
986                 // Must be BLX
987                 ASSERT((*insn & 0x012fff30) == 0x012fff30);
988                 insn--;
989             }
990 #endif
991             // Must be an ldr ..., [pc +/- imm]
992             ASSERT((*insn & 0x0f7f0000) == 0x051f0000);
993
994             ARMWord addr = reinterpret_cast<ARMWord>(insn) + DefaultPrefetching * sizeof(ARMWord);
995             if (*insn & DT_UP)
996                 return reinterpret_cast<ARMWord*>(addr + (*insn & SDT_OFFSET_MASK));
997             return reinterpret_cast<ARMWord*>(addr - (*insn & SDT_OFFSET_MASK));
998         }
999
1000         static ARMWord* getLdrImmAddressOnPool(ARMWord* insn, uint32_t* constPool)
1001         {
1002             // Must be an ldr ..., [pc +/- imm]
1003             ASSERT((*insn & 0x0f7f0000) == 0x051f0000);
1004
1005             if (*insn & 0x1)
1006                 return reinterpret_cast<ARMWord*>(constPool + ((*insn & SDT_OFFSET_MASK) >> 1));
1007             return getLdrImmAddress(insn);
1008         }
1009
1010         static void patchPointerInternal(intptr_t from, void* to)
1011         {
1012             ARMWord* insn = reinterpret_cast<ARMWord*>(from);
1013             ARMWord* addr = getLdrImmAddress(insn);
1014             *addr = reinterpret_cast<ARMWord>(to);
1015         }
1016
1017         static ARMWord patchConstantPoolLoad(ARMWord load, ARMWord value)
1018         {
1019             value = (value << 1) + 1;
1020             ASSERT(!(value & ~0xfff));
1021             return (load & ~0xfff) | value;
1022         }
1023
1024         static void patchConstantPoolLoad(void* loadAddr, void* constPoolAddr);
1025
1026         // Patch pointers
1027
1028         static void linkPointer(void* code, JmpDst from, void* to)
1029         {
1030             js::JaegerSpew(js::JSpew_Insns,
1031                            ISPFX "##linkPointer     ((%p + %#x)) points to ((%p))\n",
1032                            code, from.m_offset, to);
1033
1034             patchPointerInternal(reinterpret_cast<intptr_t>(code) + from.m_offset, to);
1035         }
1036
1037         static void repatchInt32(void* from, int32_t to)
1038         {
1039             js::JaegerSpew(js::JSpew_Insns,
1040                            ISPFX "##repatchInt32    ((%p)) holds ((%p))\n",
1041                            from, to);
1042
1043             patchPointerInternal(reinterpret_cast<intptr_t>(from), reinterpret_cast<void*>(to));
1044         }
1045
1046         static void repatchPointer(void* from, void* to)
1047         {
1048             js::JaegerSpew(js::JSpew_Insns,
1049                            ISPFX "##repatchPointer  ((%p)) points to ((%p))\n",
1050                            from, to);
1051
1052             patchPointerInternal(reinterpret_cast<intptr_t>(from), to);
1053         }
1054
1055         static void repatchLoadPtrToLEA(void* from)
1056         {
1057             // On arm, this is a patch from LDR to ADD. It is restricted conversion,
1058             // from special case to special case, altough enough for its purpose
1059             ARMWord* insn = reinterpret_cast<ARMWord*>(from);
1060             ASSERT((*insn & 0x0ff00f00) == 0x05900000);
1061
1062             *insn = (*insn & 0xf00ff0ff) | 0x02800000;
1063             ExecutableAllocator::cacheFlush(insn, sizeof(ARMWord));
1064         }
1065
1066         static void repatchLEAToLoadPtr(void* from)
1067         {
1068             // Like repatchLoadPtrToLEA, this is specialized for our purpose.
1069             ARMWord* insn = reinterpret_cast<ARMWord*>(from);
1070             if ((*insn & 0x0ff00f00) == 0x05900000)
1071                 return; // Valid ldr instruction
1072             ASSERT((*insn & 0x0ff00000) == 0x02800000); // Valid add instruction
1073             ASSERT((*insn & 0x00000f00) == 0x00000000); // Simple-to-handle immediates (no rotate)
1074
1075             *insn = (*insn &  0xf00ff0ff) | 0x05900000;
1076             ExecutableAllocator::cacheFlush(insn, sizeof(ARMWord));
1077         }
1078
1079         // Linkers
1080
1081         void linkJump(JmpSrc from, JmpDst to)
1082         {
1083             ARMWord  code = reinterpret_cast<ARMWord>(m_buffer.data());
1084             ARMWord* insn = reinterpret_cast<ARMWord*>(code + from.m_offset);
1085             ARMWord* addr = getLdrImmAddressOnPool(insn, m_buffer.poolAddress());
1086
1087             js::JaegerSpew(js::JSpew_Insns,
1088                            IPFX "##linkJump         ((%#x)) jumps to ((%#x))\n", MAYBE_PAD,
1089                            from.m_offset, to.m_offset);
1090
1091             *addr = to.m_offset;
1092         }
1093
1094         static void linkJump(void* code, JmpSrc from, void* to)
1095         {
1096             js::JaegerSpew(js::JSpew_Insns,
1097                            ISPFX "##linkJump        ((%p + %#x)) jumps to ((%p))\n",
1098                            code, from.m_offset, to);
1099
1100             patchPointerInternal(reinterpret_cast<intptr_t>(code) + from.m_offset, to);
1101         }
1102
1103         static void relinkJump(void* from, void* to)
1104         {
1105             js::JaegerSpew(js::JSpew_Insns,
1106                            ISPFX "##relinkJump      ((%p)) jumps to ((%p))\n",
1107                            from, to);
1108
1109             patchPointerInternal(reinterpret_cast<intptr_t>(from), to);
1110         }
1111
1112         static bool canRelinkJump(void* from, void* to)
1113         {
1114             return true;
1115         }
1116
1117         static void linkCall(void* code, JmpSrc from, void* to)
1118         {
1119             js::JaegerSpew(js::JSpew_Insns,
1120                            ISPFX "##linkCall        ((%p + %#x)) jumps to ((%p))\n",
1121                            code, from.m_offset, to);
1122
1123             patchPointerInternal(reinterpret_cast<intptr_t>(code) + from.m_offset, to);
1124         }
1125
1126         static void relinkCall(void* from, void* to)
1127         {
1128             js::JaegerSpew(js::JSpew_Insns,
1129                            ISPFX "##relinkCall      ((%p)) jumps to ((%p))\n",
1130                            from, to);
1131
1132             patchPointerInternal(reinterpret_cast<intptr_t>(from), to);
1133         }
1134
1135         // Address operations
1136
1137         static void* getRelocatedAddress(void* code, JmpSrc jump)
1138         {
1139             return reinterpret_cast<void*>(reinterpret_cast<ARMWord*>(code) + jump.m_offset / sizeof(ARMWord));
1140         }
1141
1142         static void* getRelocatedAddress(void* code, JmpDst label)
1143         {
1144             return reinterpret_cast<void*>(reinterpret_cast<ARMWord*>(code) + label.m_offset / sizeof(ARMWord));
1145         }
1146
1147         // Address differences
1148
1149         static int getDifferenceBetweenLabels(JmpDst from, JmpSrc to)
1150         {
1151             return to.m_offset - from.m_offset;
1152         }
1153
1154         static int getDifferenceBetweenLabels(JmpDst from, JmpDst to)
1155         {
1156             return to.m_offset - from.m_offset;
1157         }
1158
1159         static unsigned getCallReturnOffset(JmpSrc call)
1160         {
1161             return call.m_offset + sizeof(ARMWord);
1162         }
1163
1164         // Handle immediates
1165
1166         static ARMWord getOp2Byte(ARMWord imm)
1167         {
1168             ASSERT(imm <= 0xff);
1169             return OP2_IMMh | (imm & 0x0f) | ((imm & 0xf0) << 4) ;
1170         }
1171
1172         static ARMWord getOp2(ARMWord imm);
1173
1174 #if WTF_ARM_ARCH_VERSION >= 7
1175         static ARMWord getImm16Op2(ARMWord imm)
1176         {
1177             if (imm <= 0xffff)
1178                 return (imm & 0xf000) << 4 | (imm & 0xfff);
1179             return INVALID_IMM;
1180         }
1181 #endif
1182         ARMWord getImm(ARMWord imm, int tmpReg, bool invert = false);
1183         void moveImm(ARMWord imm, int dest);
1184         ARMWord encodeComplexImm(ARMWord imm, int dest);
1185
1186         ARMWord getOffsetForHalfwordDataTransfer(ARMWord imm, int tmpReg)
1187         {
1188             // Encode immediate data in the instruction if it is possible
1189             if (imm <= 0xff)
1190                 return getOp2Byte(imm);
1191             // Otherwise, store the data in a temporary register
1192             return encodeComplexImm(imm, tmpReg);
1193         }
1194
1195         // Memory load/store helpers
1196
1197         void dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset);
1198         void dataTransfer8(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset);
1199         void baseIndexTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset);
1200         void doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset);
1201
1202         // Constant pool hnadlers
1203
1204         static ARMWord placeConstantPoolBarrier(int offset)
1205         {
1206             offset = (offset - sizeof(ARMWord)) >> 2;
1207             ASSERT((offset <= BOFFSET_MAX && offset >= BOFFSET_MIN));
1208             return AL | B | (offset & BRANCH_MASK);
1209         }
1210
1211     private:
1212         static char const * nameGpReg(int reg)
1213         {
1214             ASSERT(reg <= 16);
1215             ASSERT(reg >= 0);
1216             static char const * names[] = {
1217                 "r0", "r1", "r2", "r3",
1218                 "r4", "r5", "r6", "r7",
1219                 "r8", "r9", "r10", "r11",
1220                 "ip", "sp", "lr", "pc"
1221             };
1222             return names[reg];
1223         }
1224
1225         static char const * nameFpRegD(int reg)
1226         {
1227             ASSERT(reg <= 31);
1228             ASSERT(reg >= 0);
1229             static char const * names[] = {
1230                  "d0",   "d1",   "d2",   "d3",
1231                  "d4",   "d5",   "d6",   "d7",
1232                  "d8",   "d9",  "d10",  "d11",
1233                 "d12",  "d13",  "d14",  "d15",
1234                 "d16",  "d17",  "d18",  "d19",
1235                 "d20",  "d21",  "d22",  "d23",
1236                 "d24",  "d25",  "d26",  "d27",
1237                 "d28",  "d29",  "d30",  "d31"
1238             };
1239             return names[reg];
1240         }
1241
1242         static char const * nameCC(Condition cc)
1243         {
1244             ASSERT(cc <= AL);
1245             ASSERT(cc >= 0);
1246             ASSERT((cc & 0x0fffffff) == 0);
1247
1248             uint32_t    ccIndex = cc >> 28;
1249             static char const * names[] = {
1250                 "eq", "ne",
1251                 "cs", "cc",
1252                 "mi", "pl",
1253                 "vs", "vc",
1254                 "hi", "ls",
1255                 "ge", "lt",
1256                 "gt", "le",
1257                 "  "        // AL is the default, so don't show it.
1258             };
1259             return names[ccIndex];
1260         }
1261
1262         // Decodes operand 2 immediate values (for debug output and assertions).
1263         inline uint32_t decOp2Imm(uint32_t op2)
1264         {
1265             ASSERT((op2 & ~0xfff) == 0);
1266
1267             uint32_t    imm8 = op2 & 0xff;
1268             uint32_t    rot = ((op2 >> 7) & 0x1e);
1269
1270             // 'rot' is a right-rotate count.
1271
1272             uint32_t    imm = (imm8 >> rot);
1273             if (rot > 0) {
1274                 imm |= (imm8 << (32-rot));
1275             }
1276
1277             return imm;
1278         }
1279
1280         // Format the operand 2 argument for debug spew. The operand can be
1281         // either an immediate or a register specifier.
1282         void fmtOp2(char * out, ARMWord op2)
1283         {
1284             static char const * const shifts[4] = {"LSL", "LSR", "ASR", "ROR"};
1285
1286             if ((op2 & OP2_IMM) || (op2 & OP2_IMMh)) {
1287                 // Immediate values.
1288                 
1289                 uint32_t    imm = decOp2Imm(op2 & ~(OP2_IMM | OP2_IMMh));
1290                 sprintf(out, "#0x%x @ (%d)", imm, static_cast<int32_t>(imm));
1291             } else {
1292                 // Register values.
1293
1294                 char const *    rm = nameGpReg(op2 & 0xf);
1295                 Shift           type = static_cast<Shift>((op2 >> 5) & 0x3);
1296
1297                 // Bit 4 specifies barrel-shifter parameters in operand 2.
1298                 if (op2 & (1<<4)) {
1299                     // Register-shifted register.
1300                     // Example: "r0, LSL r6"
1301                     char const *    rs = nameGpReg((op2 >> 8) & 0xf);
1302                     sprintf(out, "%s, %s %s", rm, shifts[type], rs);
1303                 } else {
1304                     // Immediate-shifted register.
1305                     // Example: "r0, ASR #31"
1306                     uint32_t        imm = (op2 >> 7) & 0x1f;
1307                     
1308                     // Deal with special encodings.
1309                     if ((type == LSL) && (imm == 0)) {
1310                         // "LSL #0" doesn't shift at all (and is the default).
1311                         sprintf(out, "%s", rm);
1312                         return;
1313                     }
1314
1315                     if ((type == ROR) && (imm == 0)) {
1316                         // "ROR #0" is a special case ("RRX").
1317                         sprintf(out, "%s, RRX", rm);
1318                         return;
1319                     }
1320
1321                     if (((type == LSR) || (type == ASR)) && (imm == 0)) {
1322                         // Both LSR and ASR have a range of 1-32, with 32
1323                         // encoded as 0.                  
1324                         imm = 32;
1325                     }
1326
1327                     // Print the result.
1328
1329                     sprintf(out, "%s, %s #%u", rm, shifts[type], imm);
1330                 }
1331             }
1332         }
1333
1334         void spewInsWithOp2(char const * ins, Condition cc, int rd, int rn, ARMWord op2)
1335         {
1336             char    mnemonic[16];
1337             snprintf(mnemonic, 16, "%s%s", ins, nameCC(cc));
1338
1339             char    op2_fmt[48];
1340             fmtOp2(op2_fmt, op2);
1341
1342             js::JaegerSpew(js::JSpew_Insns,
1343                     IPFX   "%-15s %s, %s, %s\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rn), op2_fmt);
1344         }
1345
1346         void spewInsWithOp2(char const * ins, Condition cc, int r, ARMWord op2)
1347         {
1348             char    mnemonic[16];
1349             snprintf(mnemonic, 16, "%s%s", ins, nameCC(cc));
1350
1351             char    op2_fmt[48];
1352             fmtOp2(op2_fmt, op2);
1353
1354             js::JaegerSpew(js::JSpew_Insns,
1355                     IPFX   "%-15s %s, %s\n", MAYBE_PAD, mnemonic, nameGpReg(r), op2_fmt);
1356         }
1357
1358         ARMWord RM(int reg)
1359         {
1360             ASSERT(reg <= ARMRegisters::pc);
1361             return reg;
1362         }
1363
1364         ARMWord RS(int reg)
1365         {
1366             ASSERT(reg <= ARMRegisters::pc);
1367             return reg << 8;
1368         }
1369
1370         ARMWord RD(int reg)
1371         {
1372             ASSERT(reg <= ARMRegisters::pc);
1373             return reg << 12;
1374         }
1375
1376         ARMWord RN(int reg)
1377         {
1378             ASSERT(reg <= ARMRegisters::pc);
1379             return reg << 16;
1380         }
1381
1382         ARMWord DD(int reg)
1383         {
1384             ASSERT(reg <= ARMRegisters::d31);
1385             // Endoded as bits [22,15:12].
1386             return ((reg << 12) | (reg << 18)) & 0x0040f000;
1387         }
1388
1389         ARMWord DN(int reg)
1390         {
1391             ASSERT(reg <= ARMRegisters::d31);
1392             // Endoded as bits [7,19:16].
1393             return ((reg << 16) | (reg << 3)) & 0x000f0080;
1394         }
1395
1396         ARMWord DM(int reg)
1397         {
1398             ASSERT(reg <= ARMRegisters::d31);
1399             // Encoded as bits [5,3:0].
1400             return ((reg << 1) & 0x20) | (reg & 0xf);
1401         }
1402
1403         static ARMWord getConditionalField(ARMWord i)
1404         {
1405             return i & 0xf0000000;
1406         }
1407
1408         int genInt(int reg, ARMWord imm, bool positive);
1409
1410         ARMBuffer m_buffer;
1411         Jumps m_jumps;
1412     };
1413
1414 } // namespace JSC
1415
1416 #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
1417
1418 #endif // ARMAssembler_h