Unreviewed, rolling out r149349 and r149354.
[WebKit-https.git] / Source / JavaScriptCore / assembler / MacroAssemblerARMv7.h
1 /*
2  * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2010 University of Szeged
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 APPLE INC. ``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 APPLE INC. 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 MacroAssemblerARMv7_h
28 #define MacroAssemblerARMv7_h
29
30 #if ENABLE(ASSEMBLER)
31
32 #include "ARMv7Assembler.h"
33 #include "AbstractMacroAssembler.h"
34
35 namespace JSC {
36
37 class MacroAssemblerARMv7 : public AbstractMacroAssembler<ARMv7Assembler> {
38     // FIXME: switch dataTempRegister & addressTempRegister, or possibly use r7?
39     //        - dTR is likely used more than aTR, and we'll get better instruction
40     //        encoding if it's in the low 8 registers.
41     static const RegisterID dataTempRegister = ARMRegisters::ip;
42     static const RegisterID addressTempRegister = ARMRegisters::r3;
43
44     static const ARMRegisters::FPDoubleRegisterID fpTempRegister = ARMRegisters::d7;
45     inline ARMRegisters::FPSingleRegisterID fpTempRegisterAsSingle() { return ARMRegisters::asSingle(fpTempRegister); }
46
47 public:
48     MacroAssemblerARMv7()
49         : m_makeJumpPatchable(false)
50     {
51     }
52
53     typedef ARMv7Assembler::LinkRecord LinkRecord;
54     typedef ARMv7Assembler::JumpType JumpType;
55     typedef ARMv7Assembler::JumpLinkType JumpLinkType;
56
57     static bool isCompactPtrAlignedAddressOffset(ptrdiff_t value)
58     {
59         return value >= -255 && value <= 255;
60     }
61
62     Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink() { return m_assembler.jumpsToLink(); }
63     void* unlinkedCode() { return m_assembler.unlinkedCode(); }
64     bool canCompact(JumpType jumpType) { return m_assembler.canCompact(jumpType); }
65     JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to) { return m_assembler.computeJumpType(jumpType, from, to); }
66     JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to) { return m_assembler.computeJumpType(record, from, to); }
67     void recordLinkOffsets(int32_t regionStart, int32_t regionEnd, int32_t offset) {return m_assembler.recordLinkOffsets(regionStart, regionEnd, offset); }
68     int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return m_assembler.jumpSizeDelta(jumpType, jumpLinkType); }
69     void link(LinkRecord& record, uint8_t* from, uint8_t* to) { return m_assembler.link(record, from, to); }
70
71     struct ArmAddress {
72         enum AddressType {
73             HasOffset,
74             HasIndex,
75         } type;
76         RegisterID base;
77         union {
78             int32_t offset;
79             struct {
80                 RegisterID index;
81                 Scale scale;
82             };
83         } u;
84         
85         explicit ArmAddress(RegisterID base, int32_t offset = 0)
86             : type(HasOffset)
87             , base(base)
88         {
89             u.offset = offset;
90         }
91         
92         explicit ArmAddress(RegisterID base, RegisterID index, Scale scale = TimesOne)
93             : type(HasIndex)
94             , base(base)
95         {
96             u.index = index;
97             u.scale = scale;
98         }
99     };
100     
101 public:
102     typedef ARMRegisters::FPDoubleRegisterID FPRegisterID;
103
104     static const Scale ScalePtr = TimesFour;
105
106     enum RelationalCondition {
107         Equal = ARMv7Assembler::ConditionEQ,
108         NotEqual = ARMv7Assembler::ConditionNE,
109         Above = ARMv7Assembler::ConditionHI,
110         AboveOrEqual = ARMv7Assembler::ConditionHS,
111         Below = ARMv7Assembler::ConditionLO,
112         BelowOrEqual = ARMv7Assembler::ConditionLS,
113         GreaterThan = ARMv7Assembler::ConditionGT,
114         GreaterThanOrEqual = ARMv7Assembler::ConditionGE,
115         LessThan = ARMv7Assembler::ConditionLT,
116         LessThanOrEqual = ARMv7Assembler::ConditionLE
117     };
118
119     enum ResultCondition {
120         Overflow = ARMv7Assembler::ConditionVS,
121         Signed = ARMv7Assembler::ConditionMI,
122         PositiveOrZero = ARMv7Assembler::ConditionPL,
123         Zero = ARMv7Assembler::ConditionEQ,
124         NonZero = ARMv7Assembler::ConditionNE
125     };
126
127     enum DoubleCondition {
128         // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
129         DoubleEqual = ARMv7Assembler::ConditionEQ,
130         DoubleNotEqual = ARMv7Assembler::ConditionVC, // Not the right flag! check for this & handle differently.
131         DoubleGreaterThan = ARMv7Assembler::ConditionGT,
132         DoubleGreaterThanOrEqual = ARMv7Assembler::ConditionGE,
133         DoubleLessThan = ARMv7Assembler::ConditionLO,
134         DoubleLessThanOrEqual = ARMv7Assembler::ConditionLS,
135         // If either operand is NaN, these conditions always evaluate to true.
136         DoubleEqualOrUnordered = ARMv7Assembler::ConditionVS, // Not the right flag! check for this & handle differently.
137         DoubleNotEqualOrUnordered = ARMv7Assembler::ConditionNE,
138         DoubleGreaterThanOrUnordered = ARMv7Assembler::ConditionHI,
139         DoubleGreaterThanOrEqualOrUnordered = ARMv7Assembler::ConditionHS,
140         DoubleLessThanOrUnordered = ARMv7Assembler::ConditionLT,
141         DoubleLessThanOrEqualOrUnordered = ARMv7Assembler::ConditionLE,
142     };
143
144     static const RegisterID stackPointerRegister = ARMRegisters::sp;
145     static const RegisterID linkRegister = ARMRegisters::lr;
146
147     // Integer arithmetic operations:
148     //
149     // Operations are typically two operand - operation(source, srcDst)
150     // For many operations the source may be an TrustedImm32, the srcDst operand
151     // may often be a memory location (explictly described using an Address
152     // object).
153
154     void add32(RegisterID src, RegisterID dest)
155     {
156         m_assembler.add(dest, dest, src);
157     }
158
159     void add32(TrustedImm32 imm, RegisterID dest)
160     {
161         add32(imm, dest, dest);
162     }
163     
164     void add32(AbsoluteAddress src, RegisterID dest)
165     {
166         load32(src.m_ptr, dataTempRegister);
167         add32(dataTempRegister, dest);
168     }
169
170     void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
171     {
172         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
173         if (armImm.isValid())
174             m_assembler.add(dest, src, armImm);
175         else {
176             move(imm, dataTempRegister);
177             m_assembler.add(dest, src, dataTempRegister);
178         }
179     }
180
181     void add32(TrustedImm32 imm, Address address)
182     {
183         load32(address, dataTempRegister);
184
185         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
186         if (armImm.isValid())
187             m_assembler.add(dataTempRegister, dataTempRegister, armImm);
188         else {
189             // Hrrrm, since dataTempRegister holds the data loaded,
190             // use addressTempRegister to hold the immediate.
191             move(imm, addressTempRegister);
192             m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister);
193         }
194
195         store32(dataTempRegister, address);
196     }
197
198     void add32(Address src, RegisterID dest)
199     {
200         load32(src, dataTempRegister);
201         add32(dataTempRegister, dest);
202     }
203
204     void add32(TrustedImm32 imm, AbsoluteAddress address)
205     {
206         load32(address.m_ptr, dataTempRegister);
207
208         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
209         if (armImm.isValid())
210             m_assembler.add(dataTempRegister, dataTempRegister, armImm);
211         else {
212             // Hrrrm, since dataTempRegister holds the data loaded,
213             // use addressTempRegister to hold the immediate.
214             move(imm, addressTempRegister);
215             m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister);
216         }
217
218         store32(dataTempRegister, address.m_ptr);
219     }
220
221     void add64(TrustedImm32 imm, AbsoluteAddress address)
222     {
223         move(TrustedImmPtr(address.m_ptr), addressTempRegister);
224
225         m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(0));
226         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
227         if (armImm.isValid())
228             m_assembler.add_S(dataTempRegister, dataTempRegister, armImm);
229         else {
230             move(imm, addressTempRegister);
231             m_assembler.add_S(dataTempRegister, dataTempRegister, addressTempRegister);
232             move(TrustedImmPtr(address.m_ptr), addressTempRegister);
233         }
234         m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(0));
235
236         m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(4));
237         m_assembler.adc(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(imm.m_value >> 31));
238         m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(4));
239     }
240
241     void and32(RegisterID op1, RegisterID op2, RegisterID dest)
242     {
243         m_assembler.ARM_and(dest, op1, op2);
244     }
245
246     void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
247     {
248         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
249         if (armImm.isValid())
250             m_assembler.ARM_and(dest, src, armImm);
251         else {
252             move(imm, dataTempRegister);
253             m_assembler.ARM_and(dest, src, dataTempRegister);
254         }
255     }
256
257     void and32(RegisterID src, RegisterID dest)
258     {
259         and32(dest, src, dest);
260     }
261
262     void and32(TrustedImm32 imm, RegisterID dest)
263     {
264         and32(imm, dest, dest);
265     }
266
267     void and32(Address src, RegisterID dest)
268     {
269         load32(src, dataTempRegister);
270         and32(dataTempRegister, dest);
271     }
272
273     void countLeadingZeros32(RegisterID src, RegisterID dest)
274     {
275         m_assembler.clz(dest, src);
276     }
277
278     void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
279     {
280         // Clamp the shift to the range 0..31
281         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
282         ASSERT(armImm.isValid());
283         m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
284
285         m_assembler.lsl(dest, src, dataTempRegister);
286     }
287
288     void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
289     {
290         m_assembler.lsl(dest, src, imm.m_value & 0x1f);
291     }
292
293     void lshift32(RegisterID shiftAmount, RegisterID dest)
294     {
295         lshift32(dest, shiftAmount, dest);
296     }
297
298     void lshift32(TrustedImm32 imm, RegisterID dest)
299     {
300         lshift32(dest, imm, dest);
301     }
302
303     void mul32(RegisterID src, RegisterID dest)
304     {
305         m_assembler.smull(dest, dataTempRegister, dest, src);
306     }
307
308     void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
309     {
310         move(imm, dataTempRegister);
311         m_assembler.smull(dest, dataTempRegister, src, dataTempRegister);
312     }
313
314     void neg32(RegisterID srcDest)
315     {
316         m_assembler.neg(srcDest, srcDest);
317     }
318
319     void or32(RegisterID src, RegisterID dest)
320     {
321         m_assembler.orr(dest, dest, src);
322     }
323     
324     void or32(RegisterID src, AbsoluteAddress dest)
325     {
326         move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
327         load32(addressTempRegister, dataTempRegister);
328         or32(src, dataTempRegister);
329         store32(dataTempRegister, addressTempRegister);
330     }
331
332     void or32(TrustedImm32 imm, RegisterID dest)
333     {
334         or32(imm, dest, dest);
335     }
336
337     void or32(RegisterID op1, RegisterID op2, RegisterID dest)
338     {
339         m_assembler.orr(dest, op1, op2);
340     }
341
342     void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
343     {
344         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
345         if (armImm.isValid())
346             m_assembler.orr(dest, src, armImm);
347         else {
348             move(imm, dataTempRegister);
349             m_assembler.orr(dest, src, dataTempRegister);
350         }
351     }
352
353     void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
354     {
355         // Clamp the shift to the range 0..31
356         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
357         ASSERT(armImm.isValid());
358         m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
359
360         m_assembler.asr(dest, src, dataTempRegister);
361     }
362
363     void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
364     {
365         m_assembler.asr(dest, src, imm.m_value & 0x1f);
366     }
367
368     void rshift32(RegisterID shiftAmount, RegisterID dest)
369     {
370         rshift32(dest, shiftAmount, dest);
371     }
372     
373     void rshift32(TrustedImm32 imm, RegisterID dest)
374     {
375         rshift32(dest, imm, dest);
376     }
377
378     void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
379     {
380         // Clamp the shift to the range 0..31
381         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
382         ASSERT(armImm.isValid());
383         m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
384         
385         m_assembler.lsr(dest, src, dataTempRegister);
386     }
387     
388     void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
389     {
390         m_assembler.lsr(dest, src, imm.m_value & 0x1f);
391     }
392
393     void urshift32(RegisterID shiftAmount, RegisterID dest)
394     {
395         urshift32(dest, shiftAmount, dest);
396     }
397     
398     void urshift32(TrustedImm32 imm, RegisterID dest)
399     {
400         urshift32(dest, imm, dest);
401     }
402
403     void sub32(RegisterID src, RegisterID dest)
404     {
405         m_assembler.sub(dest, dest, src);
406     }
407
408     void sub32(TrustedImm32 imm, RegisterID dest)
409     {
410         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
411         if (armImm.isValid())
412             m_assembler.sub(dest, dest, armImm);
413         else {
414             move(imm, dataTempRegister);
415             m_assembler.sub(dest, dest, dataTempRegister);
416         }
417     }
418
419     void sub32(TrustedImm32 imm, Address address)
420     {
421         load32(address, dataTempRegister);
422
423         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
424         if (armImm.isValid())
425             m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
426         else {
427             // Hrrrm, since dataTempRegister holds the data loaded,
428             // use addressTempRegister to hold the immediate.
429             move(imm, addressTempRegister);
430             m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
431         }
432
433         store32(dataTempRegister, address);
434     }
435
436     void sub32(Address src, RegisterID dest)
437     {
438         load32(src, dataTempRegister);
439         sub32(dataTempRegister, dest);
440     }
441
442     void sub32(TrustedImm32 imm, AbsoluteAddress address)
443     {
444         load32(address.m_ptr, dataTempRegister);
445
446         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
447         if (armImm.isValid())
448             m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
449         else {
450             // Hrrrm, since dataTempRegister holds the data loaded,
451             // use addressTempRegister to hold the immediate.
452             move(imm, addressTempRegister);
453             m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
454         }
455
456         store32(dataTempRegister, address.m_ptr);
457     }
458
459     void xor32(RegisterID op1, RegisterID op2, RegisterID dest)
460     {
461         m_assembler.eor(dest, op1, op2);
462     }
463
464     void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
465     {
466         if (imm.m_value == -1) {
467             m_assembler.mvn(dest, src);
468             return;
469         }
470
471         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
472         if (armImm.isValid())
473             m_assembler.eor(dest, src, armImm);
474         else {
475             move(imm, dataTempRegister);
476             m_assembler.eor(dest, src, dataTempRegister);
477         }
478     }
479
480     void xor32(RegisterID src, RegisterID dest)
481     {
482         xor32(dest, src, dest);
483     }
484
485     void xor32(TrustedImm32 imm, RegisterID dest)
486     {
487         if (imm.m_value == -1)
488             m_assembler.mvn(dest, dest);
489         else
490             xor32(imm, dest, dest);
491     }
492     
493
494     // Memory access operations:
495     //
496     // Loads are of the form load(address, destination) and stores of the form
497     // store(source, address).  The source for a store may be an TrustedImm32.  Address
498     // operand objects to loads and store will be implicitly constructed if a
499     // register is passed.
500
501 private:
502     void load32(ArmAddress address, RegisterID dest)
503     {
504         if (address.type == ArmAddress::HasIndex)
505             m_assembler.ldr(dest, address.base, address.u.index, address.u.scale);
506         else if (address.u.offset >= 0) {
507             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
508             ASSERT(armImm.isValid());
509             m_assembler.ldr(dest, address.base, armImm);
510         } else {
511             ASSERT(address.u.offset >= -255);
512             m_assembler.ldr(dest, address.base, address.u.offset, true, false);
513         }
514     }
515
516     void load16(ArmAddress address, RegisterID dest)
517     {
518         if (address.type == ArmAddress::HasIndex)
519             m_assembler.ldrh(dest, address.base, address.u.index, address.u.scale);
520         else if (address.u.offset >= 0) {
521             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
522             ASSERT(armImm.isValid());
523             m_assembler.ldrh(dest, address.base, armImm);
524         } else {
525             ASSERT(address.u.offset >= -255);
526             m_assembler.ldrh(dest, address.base, address.u.offset, true, false);
527         }
528     }
529     
530     void load16Signed(ArmAddress address, RegisterID dest)
531     {
532         ASSERT(address.type == ArmAddress::HasIndex);
533         m_assembler.ldrsh(dest, address.base, address.u.index, address.u.scale);
534     }
535
536     void load8(ArmAddress address, RegisterID dest)
537     {
538         if (address.type == ArmAddress::HasIndex)
539             m_assembler.ldrb(dest, address.base, address.u.index, address.u.scale);
540         else if (address.u.offset >= 0) {
541             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
542             ASSERT(armImm.isValid());
543             m_assembler.ldrb(dest, address.base, armImm);
544         } else {
545             ASSERT(address.u.offset >= -255);
546             m_assembler.ldrb(dest, address.base, address.u.offset, true, false);
547         }
548     }
549     
550     void load8Signed(ArmAddress address, RegisterID dest)
551     {
552         ASSERT(address.type == ArmAddress::HasIndex);
553         m_assembler.ldrsb(dest, address.base, address.u.index, address.u.scale);
554     }
555
556 protected:
557     void store32(RegisterID src, ArmAddress address)
558     {
559         if (address.type == ArmAddress::HasIndex)
560             m_assembler.str(src, address.base, address.u.index, address.u.scale);
561         else if (address.u.offset >= 0) {
562             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
563             ASSERT(armImm.isValid());
564             m_assembler.str(src, address.base, armImm);
565         } else {
566             ASSERT(address.u.offset >= -255);
567             m_assembler.str(src, address.base, address.u.offset, true, false);
568         }
569     }
570
571 private:
572     void store8(RegisterID src, ArmAddress address)
573     {
574         if (address.type == ArmAddress::HasIndex)
575             m_assembler.strb(src, address.base, address.u.index, address.u.scale);
576         else if (address.u.offset >= 0) {
577             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
578             ASSERT(armImm.isValid());
579             m_assembler.strb(src, address.base, armImm);
580         } else {
581             ASSERT(address.u.offset >= -255);
582             m_assembler.strb(src, address.base, address.u.offset, true, false);
583         }
584     }
585     
586     void store16(RegisterID src, ArmAddress address)
587     {
588         if (address.type == ArmAddress::HasIndex)
589             m_assembler.strh(src, address.base, address.u.index, address.u.scale);
590         else if (address.u.offset >= 0) {
591             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
592             ASSERT(armImm.isValid());
593             m_assembler.strh(src, address.base, armImm);
594         } else {
595             ASSERT(address.u.offset >= -255);
596             m_assembler.strh(src, address.base, address.u.offset, true, false);
597         }
598     }
599
600 public:
601     void load32(ImplicitAddress address, RegisterID dest)
602     {
603         load32(setupArmAddress(address), dest);
604     }
605
606     void load32(BaseIndex address, RegisterID dest)
607     {
608         load32(setupArmAddress(address), dest);
609     }
610
611     void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
612     {
613         load32(setupArmAddress(address), dest);
614     }
615
616     void load16Unaligned(BaseIndex address, RegisterID dest)
617     {
618         load16(setupArmAddress(address), dest);
619     }
620
621     void load32(const void* address, RegisterID dest)
622     {
623         move(TrustedImmPtr(address), addressTempRegister);
624         m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
625     }
626     
627     ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
628     {
629         ConvertibleLoadLabel result(this);
630         ASSERT(address.offset >= 0 && address.offset <= 255);
631         m_assembler.ldrWide8BitImmediate(dest, address.base, address.offset);
632         return result;
633     }
634
635     void load8(ImplicitAddress address, RegisterID dest)
636     {
637         load8(setupArmAddress(address), dest);
638     }
639
640     void load8Signed(ImplicitAddress, RegisterID)
641     {
642         UNREACHABLE_FOR_PLATFORM();
643     }
644
645     void load8(BaseIndex address, RegisterID dest)
646     {
647         load8(setupArmAddress(address), dest);
648     }
649     
650     void load8Signed(BaseIndex address, RegisterID dest)
651     {
652         load8Signed(setupArmAddress(address), dest);
653     }
654
655     DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
656     {
657         DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
658         load32(ArmAddress(address.base, dataTempRegister), dest);
659         return label;
660     }
661     
662     DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
663     {
664         padBeforePatch();
665
666         RegisterID base = address.base;
667         
668         DataLabelCompact label(this);
669         ASSERT(isCompactPtrAlignedAddressOffset(address.offset));
670
671         m_assembler.ldr(dest, base, address.offset, true, false);
672         return label;
673     }
674
675     void load16(BaseIndex address, RegisterID dest)
676     {
677         m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale);
678     }
679     
680     void load16Signed(BaseIndex address, RegisterID dest)
681     {
682         load16Signed(setupArmAddress(address), dest);
683     }
684     
685     void load16(ImplicitAddress address, RegisterID dest)
686     {
687         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.offset);
688         if (armImm.isValid())
689             m_assembler.ldrh(dest, address.base, armImm);
690         else {
691             move(TrustedImm32(address.offset), dataTempRegister);
692             m_assembler.ldrh(dest, address.base, dataTempRegister);
693         }
694     }
695     
696     void load16Signed(ImplicitAddress, RegisterID)
697     {
698         UNREACHABLE_FOR_PLATFORM();
699     }
700
701     DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
702     {
703         DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
704         store32(src, ArmAddress(address.base, dataTempRegister));
705         return label;
706     }
707
708     void store32(RegisterID src, ImplicitAddress address)
709     {
710         store32(src, setupArmAddress(address));
711     }
712
713     void store32(RegisterID src, BaseIndex address)
714     {
715         store32(src, setupArmAddress(address));
716     }
717
718     void store32(TrustedImm32 imm, ImplicitAddress address)
719     {
720         move(imm, dataTempRegister);
721         store32(dataTempRegister, setupArmAddress(address));
722     }
723
724     void store32(TrustedImm32 imm, BaseIndex address)
725     {
726         move(imm, dataTempRegister);
727         store32(dataTempRegister, setupArmAddress(address));
728     }
729
730     void store32(RegisterID src, const void* address)
731     {
732         move(TrustedImmPtr(address), addressTempRegister);
733         m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
734     }
735
736     void store32(TrustedImm32 imm, const void* address)
737     {
738         move(imm, dataTempRegister);
739         store32(dataTempRegister, address);
740     }
741
742     void store8(RegisterID src, BaseIndex address)
743     {
744         store8(src, setupArmAddress(address));
745     }
746     
747     void store8(RegisterID src, void* address)
748     {
749         move(TrustedImmPtr(address), addressTempRegister);
750         store8(src, ArmAddress(addressTempRegister, 0));
751     }
752     
753     void store8(TrustedImm32 imm, void* address)
754     {
755         move(imm, dataTempRegister);
756         store8(dataTempRegister, address);
757     }
758     
759     void store16(RegisterID src, BaseIndex address)
760     {
761         store16(src, setupArmAddress(address));
762     }
763
764     // Possibly clobbers src, but not on this architecture.
765     void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2)
766     {
767         m_assembler.vmov(dest1, dest2, src);
768     }
769     
770     void moveIntsToDouble(RegisterID src1, RegisterID src2, FPRegisterID dest, FPRegisterID scratch)
771     {
772         UNUSED_PARAM(scratch);
773         m_assembler.vmov(dest, src1, src2);
774     }
775
776 #if ENABLE(JIT_CONSTANT_BLINDING)
777     static bool shouldBlindForSpecificArch(uint32_t value)
778     {
779         ARMThumbImmediate immediate = ARMThumbImmediate::makeEncodedImm(value);
780
781         // Couldn't be encoded as an immediate, so assume it's untrusted.
782         if (!immediate.isValid())
783             return true;
784         
785         // If we can encode the immediate, we have less than 16 attacker
786         // controlled bits.
787         if (immediate.isEncodedImm())
788             return false;
789
790         // Don't let any more than 12 bits of an instruction word
791         // be controlled by an attacker.
792         return !immediate.isUInt12();
793     }
794 #endif
795
796     // Floating-point operations:
797
798     static bool supportsFloatingPoint() { return true; }
799     static bool supportsFloatingPointTruncate() { return true; }
800     static bool supportsFloatingPointSqrt() { return true; }
801     static bool supportsFloatingPointAbs() { return true; }
802
803     void loadDouble(ImplicitAddress address, FPRegisterID dest)
804     {
805         RegisterID base = address.base;
806         int32_t offset = address.offset;
807
808         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
809         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
810             add32(TrustedImm32(offset), base, addressTempRegister);
811             base = addressTempRegister;
812             offset = 0;
813         }
814         
815         m_assembler.vldr(dest, base, offset);
816     }
817
818     void loadFloat(ImplicitAddress address, FPRegisterID dest)
819     {
820         RegisterID base = address.base;
821         int32_t offset = address.offset;
822
823         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
824         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
825             add32(TrustedImm32(offset), base, addressTempRegister);
826             base = addressTempRegister;
827             offset = 0;
828         }
829         
830         m_assembler.flds(ARMRegisters::asSingle(dest), base, offset);
831     }
832
833     void loadDouble(BaseIndex address, FPRegisterID dest)
834     {
835         move(address.index, addressTempRegister);
836         lshift32(TrustedImm32(address.scale), addressTempRegister);
837         add32(address.base, addressTempRegister);
838         loadDouble(Address(addressTempRegister, address.offset), dest);
839     }
840     
841     void loadFloat(BaseIndex address, FPRegisterID dest)
842     {
843         move(address.index, addressTempRegister);
844         lshift32(TrustedImm32(address.scale), addressTempRegister);
845         add32(address.base, addressTempRegister);
846         loadFloat(Address(addressTempRegister, address.offset), dest);
847     }
848
849     void moveDouble(FPRegisterID src, FPRegisterID dest)
850     {
851         if (src != dest)
852             m_assembler.vmov(dest, src);
853     }
854
855     void loadDouble(const void* address, FPRegisterID dest)
856     {
857         move(TrustedImmPtr(address), addressTempRegister);
858         m_assembler.vldr(dest, addressTempRegister, 0);
859     }
860
861     void storeDouble(FPRegisterID src, ImplicitAddress address)
862     {
863         RegisterID base = address.base;
864         int32_t offset = address.offset;
865
866         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
867         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
868             add32(TrustedImm32(offset), base, addressTempRegister);
869             base = addressTempRegister;
870             offset = 0;
871         }
872         
873         m_assembler.vstr(src, base, offset);
874     }
875
876     void storeFloat(FPRegisterID src, ImplicitAddress address)
877     {
878         RegisterID base = address.base;
879         int32_t offset = address.offset;
880
881         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
882         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
883             add32(TrustedImm32(offset), base, addressTempRegister);
884             base = addressTempRegister;
885             offset = 0;
886         }
887         
888         m_assembler.fsts(ARMRegisters::asSingle(src), base, offset);
889     }
890
891     void storeDouble(FPRegisterID src, const void* address)
892     {
893         move(TrustedImmPtr(address), addressTempRegister);
894         storeDouble(src, addressTempRegister);
895     }
896
897     void storeDouble(FPRegisterID src, BaseIndex address)
898     {
899         move(address.index, addressTempRegister);
900         lshift32(TrustedImm32(address.scale), addressTempRegister);
901         add32(address.base, addressTempRegister);
902         storeDouble(src, Address(addressTempRegister, address.offset));
903     }
904     
905     void storeFloat(FPRegisterID src, BaseIndex address)
906     {
907         move(address.index, addressTempRegister);
908         lshift32(TrustedImm32(address.scale), addressTempRegister);
909         add32(address.base, addressTempRegister);
910         storeFloat(src, Address(addressTempRegister, address.offset));
911     }
912     
913     void addDouble(FPRegisterID src, FPRegisterID dest)
914     {
915         m_assembler.vadd(dest, dest, src);
916     }
917
918     void addDouble(Address src, FPRegisterID dest)
919     {
920         loadDouble(src, fpTempRegister);
921         addDouble(fpTempRegister, dest);
922     }
923
924     void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
925     {
926         m_assembler.vadd(dest, op1, op2);
927     }
928
929     void addDouble(AbsoluteAddress address, FPRegisterID dest)
930     {
931         loadDouble(address.m_ptr, fpTempRegister);
932         m_assembler.vadd(dest, dest, fpTempRegister);
933     }
934
935     void divDouble(FPRegisterID src, FPRegisterID dest)
936     {
937         m_assembler.vdiv(dest, dest, src);
938     }
939
940     void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
941     {
942         m_assembler.vdiv(dest, op1, op2);
943     }
944
945     void subDouble(FPRegisterID src, FPRegisterID dest)
946     {
947         m_assembler.vsub(dest, dest, src);
948     }
949
950     void subDouble(Address src, FPRegisterID dest)
951     {
952         loadDouble(src, fpTempRegister);
953         subDouble(fpTempRegister, dest);
954     }
955
956     void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
957     {
958         m_assembler.vsub(dest, op1, op2);
959     }
960
961     void mulDouble(FPRegisterID src, FPRegisterID dest)
962     {
963         m_assembler.vmul(dest, dest, src);
964     }
965
966     void mulDouble(Address src, FPRegisterID dest)
967     {
968         loadDouble(src, fpTempRegister);
969         mulDouble(fpTempRegister, dest);
970     }
971
972     void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
973     {
974         m_assembler.vmul(dest, op1, op2);
975     }
976
977     void sqrtDouble(FPRegisterID src, FPRegisterID dest)
978     {
979         m_assembler.vsqrt(dest, src);
980     }
981     
982     void absDouble(FPRegisterID src, FPRegisterID dest)
983     {
984         m_assembler.vabs(dest, src);
985     }
986
987     void negateDouble(FPRegisterID src, FPRegisterID dest)
988     {
989         m_assembler.vneg(dest, src);
990     }
991
992     void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
993     {
994         m_assembler.vmov(fpTempRegister, src, src);
995         m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
996     }
997
998     void convertInt32ToDouble(Address address, FPRegisterID dest)
999     {
1000         // Fixme: load directly into the fpr!
1001         load32(address, dataTempRegister);
1002         m_assembler.vmov(fpTempRegister, dataTempRegister, dataTempRegister);
1003         m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
1004     }
1005
1006     void convertInt32ToDouble(AbsoluteAddress address, FPRegisterID dest)
1007     {
1008         // Fixme: load directly into the fpr!
1009         load32(address.m_ptr, dataTempRegister);
1010         m_assembler.vmov(fpTempRegister, dataTempRegister, dataTempRegister);
1011         m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
1012     }
1013     
1014     void convertFloatToDouble(FPRegisterID src, FPRegisterID dst)
1015     {
1016         m_assembler.vcvtds(dst, ARMRegisters::asSingle(src));
1017     }
1018     
1019     void convertDoubleToFloat(FPRegisterID src, FPRegisterID dst)
1020     {
1021         m_assembler.vcvtsd(ARMRegisters::asSingle(dst), src);
1022     }
1023
1024     Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
1025     {
1026         m_assembler.vcmp(left, right);
1027         m_assembler.vmrs();
1028
1029         if (cond == DoubleNotEqual) {
1030             // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump.
1031             Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1032             Jump result = makeBranch(ARMv7Assembler::ConditionNE);
1033             unordered.link(this);
1034             return result;
1035         }
1036         if (cond == DoubleEqualOrUnordered) {
1037             Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1038             Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
1039             unordered.link(this);
1040             // We get here if either unordered or equal.
1041             Jump result = jump();
1042             notEqual.link(this);
1043             return result;
1044         }
1045         return makeBranch(cond);
1046     }
1047
1048     enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
1049     Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
1050     {
1051         // Convert into dest.
1052         m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1053         m_assembler.vmov(dest, fpTempRegisterAsSingle());
1054
1055         // Calculate 2x dest.  If the value potentially underflowed, it will have
1056         // clamped to 0x80000000, so 2x dest is zero in this case. In the case of
1057         // overflow the result will be equal to -2.
1058         Jump underflow = branchAdd32(Zero, dest, dest, dataTempRegister);
1059         Jump noOverflow = branch32(NotEqual, dataTempRegister, TrustedImm32(-2));
1060
1061         // For BranchIfTruncateSuccessful, we branch if 'noOverflow' jumps.
1062         underflow.link(this);
1063         if (branchType == BranchIfTruncateSuccessful)
1064             return noOverflow;
1065
1066         // We'll reach the current point in the code on failure, so plant a
1067         // jump here & link the success case.
1068         Jump failure = jump();
1069         noOverflow.link(this);
1070         return failure;
1071     }
1072
1073     Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
1074     {
1075         m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1076         m_assembler.vmov(dest, fpTempRegisterAsSingle());
1077         
1078         Jump overflow = branch32(Equal, dest, TrustedImm32(0x7fffffff));
1079         Jump success = branch32(GreaterThanOrEqual, dest, TrustedImm32(0));
1080         overflow.link(this);
1081
1082         if (branchType == BranchIfTruncateSuccessful)
1083             return success;
1084         
1085         Jump failure = jump();
1086         success.link(this);
1087         return failure;
1088     }
1089
1090     // Result is undefined if the value is outside of the integer range.
1091     void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
1092     {
1093         m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1094         m_assembler.vmov(dest, fpTempRegisterAsSingle());
1095     }
1096
1097     void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
1098     {
1099         m_assembler.vcvt_floatingPointToUnsigned(fpTempRegisterAsSingle(), src);
1100         m_assembler.vmov(dest, fpTempRegisterAsSingle());
1101     }
1102     
1103     // Convert 'src' to an integer, and places the resulting 'dest'.
1104     // If the result is not representable as a 32 bit value, branch.
1105     // May also branch for some values that are representable in 32 bits
1106     // (specifically, in this case, 0).
1107     void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID, bool negZeroCheck = true)
1108     {
1109         m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1110         m_assembler.vmov(dest, fpTempRegisterAsSingle());
1111
1112         // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
1113         m_assembler.vcvt_signedToFloatingPoint(fpTempRegister, fpTempRegisterAsSingle());
1114         failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, fpTempRegister));
1115
1116         // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
1117         if (negZeroCheck)
1118             failureCases.append(branchTest32(Zero, dest));
1119     }
1120
1121     Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID)
1122     {
1123         m_assembler.vcmpz(reg);
1124         m_assembler.vmrs();
1125         Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1126         Jump result = makeBranch(ARMv7Assembler::ConditionNE);
1127         unordered.link(this);
1128         return result;
1129     }
1130
1131     Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID)
1132     {
1133         m_assembler.vcmpz(reg);
1134         m_assembler.vmrs();
1135         Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1136         Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
1137         unordered.link(this);
1138         // We get here if either unordered or equal.
1139         Jump result = jump();
1140         notEqual.link(this);
1141         return result;
1142     }
1143
1144     // Stack manipulation operations:
1145     //
1146     // The ABI is assumed to provide a stack abstraction to memory,
1147     // containing machine word sized units of data.  Push and pop
1148     // operations add and remove a single register sized unit of data
1149     // to or from the stack.  Peek and poke operations read or write
1150     // values on the stack, without moving the current stack position.
1151     
1152     void pop(RegisterID dest)
1153     {
1154         // store postindexed with writeback
1155         m_assembler.ldr(dest, ARMRegisters::sp, sizeof(void*), false, true);
1156     }
1157
1158     void push(RegisterID src)
1159     {
1160         // store preindexed with writeback
1161         m_assembler.str(src, ARMRegisters::sp, -sizeof(void*), true, true);
1162     }
1163
1164     void push(Address address)
1165     {
1166         load32(address, dataTempRegister);
1167         push(dataTempRegister);
1168     }
1169
1170     void push(TrustedImm32 imm)
1171     {
1172         move(imm, dataTempRegister);
1173         push(dataTempRegister);
1174     }
1175
1176     // Register move operations:
1177     //
1178     // Move values in registers.
1179
1180     void move(TrustedImm32 imm, RegisterID dest)
1181     {
1182         uint32_t value = imm.m_value;
1183
1184         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(value);
1185
1186         if (armImm.isValid())
1187             m_assembler.mov(dest, armImm);
1188         else if ((armImm = ARMThumbImmediate::makeEncodedImm(~value)).isValid())
1189             m_assembler.mvn(dest, armImm);
1190         else {
1191             m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(value));
1192             if (value & 0xffff0000)
1193                 m_assembler.movt(dest, ARMThumbImmediate::makeUInt16(value >> 16));
1194         }
1195     }
1196
1197     void move(RegisterID src, RegisterID dest)
1198     {
1199         if (src != dest)
1200             m_assembler.mov(dest, src);
1201     }
1202
1203     void move(TrustedImmPtr imm, RegisterID dest)
1204     {
1205         move(TrustedImm32(imm), dest);
1206     }
1207
1208     void swap(RegisterID reg1, RegisterID reg2)
1209     {
1210         move(reg1, dataTempRegister);
1211         move(reg2, reg1);
1212         move(dataTempRegister, reg2);
1213     }
1214
1215     void signExtend32ToPtr(RegisterID src, RegisterID dest)
1216     {
1217         move(src, dest);
1218     }
1219
1220     void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
1221     {
1222         move(src, dest);
1223     }
1224
1225     // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
1226     static RelationalCondition invert(RelationalCondition cond)
1227     {
1228         return static_cast<RelationalCondition>(cond ^ 1);
1229     }
1230
1231     void nop()
1232     {
1233         m_assembler.nop();
1234     }
1235     
1236     static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
1237     {
1238         ARMv7Assembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
1239     }
1240     
1241     static ptrdiff_t maxJumpReplacementSize()
1242     {
1243         return ARMv7Assembler::maxJumpReplacementSize();
1244     }
1245
1246     // Forwards / external control flow operations:
1247     //
1248     // This set of jump and conditional branch operations return a Jump
1249     // object which may linked at a later point, allow forwards jump,
1250     // or jumps that will require external linkage (after the code has been
1251     // relocated).
1252     //
1253     // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
1254     // respecitvely, for unsigned comparisons the names b, a, be, and ae are
1255     // used (representing the names 'below' and 'above').
1256     //
1257     // Operands to the comparision are provided in the expected order, e.g.
1258     // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
1259     // treated as a signed 32bit value, is less than or equal to 5.
1260     //
1261     // jz and jnz test whether the first operand is equal to zero, and take
1262     // an optional second operand of a mask under which to perform the test.
1263 private:
1264
1265     // Should we be using TEQ for equal/not-equal?
1266     void compare32(RegisterID left, TrustedImm32 right)
1267     {
1268         int32_t imm = right.m_value;
1269         if (!imm)
1270             m_assembler.tst(left, left);
1271         else {
1272             ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
1273             if (armImm.isValid())
1274                 m_assembler.cmp(left, armImm);
1275             else if ((armImm = ARMThumbImmediate::makeEncodedImm(-imm)).isValid())
1276                 m_assembler.cmn(left, armImm);
1277             else {
1278                 move(TrustedImm32(imm), dataTempRegister);
1279                 m_assembler.cmp(left, dataTempRegister);
1280             }
1281         }
1282     }
1283
1284     void test32(RegisterID reg, TrustedImm32 mask)
1285     {
1286         int32_t imm = mask.m_value;
1287
1288         if (imm == -1)
1289             m_assembler.tst(reg, reg);
1290         else {
1291             ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
1292             if (armImm.isValid())
1293                 m_assembler.tst(reg, armImm);
1294             else {
1295                 move(mask, dataTempRegister);
1296                 m_assembler.tst(reg, dataTempRegister);
1297             }
1298         }
1299     }
1300
1301 public:
1302     Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
1303     {
1304         m_assembler.cmp(left, right);
1305         return Jump(makeBranch(cond));
1306     }
1307
1308     Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1309     {
1310         compare32(left, right);
1311         return Jump(makeBranch(cond));
1312     }
1313
1314     Jump branch32(RelationalCondition cond, RegisterID left, Address right)
1315     {
1316         load32(right, dataTempRegister);
1317         return branch32(cond, left, dataTempRegister);
1318     }
1319
1320     Jump branch32(RelationalCondition cond, Address left, RegisterID right)
1321     {
1322         load32(left, dataTempRegister);
1323         return branch32(cond, dataTempRegister, right);
1324     }
1325
1326     Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
1327     {
1328         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1329         load32(left, addressTempRegister);
1330         return branch32(cond, addressTempRegister, right);
1331     }
1332
1333     Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1334     {
1335         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1336         load32(left, addressTempRegister);
1337         return branch32(cond, addressTempRegister, right);
1338     }
1339
1340     Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1341     {
1342         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1343         load32WithUnalignedHalfWords(left, addressTempRegister);
1344         return branch32(cond, addressTempRegister, right);
1345     }
1346
1347     Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
1348     {
1349         load32(left.m_ptr, dataTempRegister);
1350         return branch32(cond, dataTempRegister, right);
1351     }
1352
1353     Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
1354     {
1355         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1356         load32(left.m_ptr, addressTempRegister);
1357         return branch32(cond, addressTempRegister, right);
1358     }
1359
1360     Jump branch8(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1361     {
1362         compare32(left, right);
1363         return Jump(makeBranch(cond));
1364     }
1365
1366     Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
1367     {
1368         ASSERT(!(0xffffff00 & right.m_value));
1369         // use addressTempRegister incase the branch8 we call uses dataTempRegister. :-/
1370         load8(left, addressTempRegister);
1371         return branch8(cond, addressTempRegister, right);
1372     }
1373
1374     Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1375     {
1376         ASSERT(!(0xffffff00 & right.m_value));
1377         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1378         load8(left, addressTempRegister);
1379         return branch32(cond, addressTempRegister, right);
1380     }
1381     
1382     Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
1383     {
1384         m_assembler.tst(reg, mask);
1385         return Jump(makeBranch(cond));
1386     }
1387
1388     Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1389     {
1390         test32(reg, mask);
1391         return Jump(makeBranch(cond));
1392     }
1393
1394     Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1395     {
1396         // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1397         load32(address, addressTempRegister);
1398         return branchTest32(cond, addressTempRegister, mask);
1399     }
1400
1401     Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1402     {
1403         // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1404         load32(address, addressTempRegister);
1405         return branchTest32(cond, addressTempRegister, mask);
1406     }
1407
1408     Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1409     {
1410         // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1411         load8(address, addressTempRegister);
1412         return branchTest32(cond, addressTempRegister, mask);
1413     }
1414
1415     Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
1416     {
1417         // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1418         move(TrustedImmPtr(address.m_ptr), addressTempRegister);
1419         load8(Address(addressTempRegister), addressTempRegister);
1420         return branchTest32(cond, addressTempRegister, mask);
1421     }
1422
1423     void jump(RegisterID target)
1424     {
1425         m_assembler.bx(target);
1426     }
1427
1428     // Address is a memory location containing the address to jump to
1429     void jump(Address address)
1430     {
1431         load32(address, dataTempRegister);
1432         m_assembler.bx(dataTempRegister);
1433     }
1434     
1435     void jump(AbsoluteAddress address)
1436     {
1437         move(TrustedImmPtr(address.m_ptr), dataTempRegister);
1438         load32(Address(dataTempRegister), dataTempRegister);
1439         m_assembler.bx(dataTempRegister);
1440     }
1441
1442
1443     // Arithmetic control flow operations:
1444     //
1445     // This set of conditional branch operations branch based
1446     // on the result of an arithmetic operation.  The operation
1447     // is performed as normal, storing the result.
1448     //
1449     // * jz operations branch if the result is zero.
1450     // * jo operations branch if the (signed) arithmetic
1451     //   operation caused an overflow to occur.
1452     
1453     Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1454     {
1455         m_assembler.add_S(dest, op1, op2);
1456         return Jump(makeBranch(cond));
1457     }
1458
1459     Jump branchAdd32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
1460     {
1461         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1462         if (armImm.isValid())
1463             m_assembler.add_S(dest, op1, armImm);
1464         else {
1465             move(imm, dataTempRegister);
1466             m_assembler.add_S(dest, op1, dataTempRegister);
1467         }
1468         return Jump(makeBranch(cond));
1469     }
1470
1471     Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
1472     {
1473         return branchAdd32(cond, dest, src, dest);
1474     }
1475
1476     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1477     {
1478         return branchAdd32(cond, dest, imm, dest);
1479     }
1480
1481     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
1482     {
1483         // Move the high bits of the address into addressTempRegister,
1484         // and load the value into dataTempRegister.
1485         move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
1486         m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
1487
1488         // Do the add.
1489         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1490         if (armImm.isValid())
1491             m_assembler.add_S(dataTempRegister, dataTempRegister, armImm);
1492         else {
1493             // If the operand does not fit into an immediate then load it temporarily
1494             // into addressTempRegister; since we're overwriting addressTempRegister
1495             // we'll need to reload it with the high bits of the address afterwards.
1496             move(imm, addressTempRegister);
1497             m_assembler.add_S(dataTempRegister, dataTempRegister, addressTempRegister);
1498             move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
1499         }
1500
1501         // Store the result.
1502         m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
1503
1504         return Jump(makeBranch(cond));
1505     }
1506
1507     Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
1508     {
1509         m_assembler.smull(dest, dataTempRegister, src1, src2);
1510
1511         if (cond == Overflow) {
1512             m_assembler.asr(addressTempRegister, dest, 31);
1513             return branch32(NotEqual, addressTempRegister, dataTempRegister);
1514         }
1515
1516         return branchTest32(cond, dest);
1517     }
1518
1519     Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
1520     {
1521         return branchMul32(cond, src, dest, dest);
1522     }
1523
1524     Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
1525     {
1526         move(imm, dataTempRegister);
1527         return branchMul32(cond, dataTempRegister, src, dest);
1528     }
1529
1530     Jump branchNeg32(ResultCondition cond, RegisterID srcDest)
1531     {
1532         ARMThumbImmediate zero = ARMThumbImmediate::makeUInt12(0);
1533         m_assembler.sub_S(srcDest, zero, srcDest);
1534         return Jump(makeBranch(cond));
1535     }
1536
1537     Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
1538     {
1539         m_assembler.orr_S(dest, dest, src);
1540         return Jump(makeBranch(cond));
1541     }
1542
1543     Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1544     {
1545         m_assembler.sub_S(dest, op1, op2);
1546         return Jump(makeBranch(cond));
1547     }
1548
1549     Jump branchSub32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
1550     {
1551         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1552         if (armImm.isValid())
1553             m_assembler.sub_S(dest, op1, armImm);
1554         else {
1555             move(imm, dataTempRegister);
1556             m_assembler.sub_S(dest, op1, dataTempRegister);
1557         }
1558         return Jump(makeBranch(cond));
1559     }
1560     
1561     Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
1562     {
1563         return branchSub32(cond, dest, src, dest);
1564     }
1565
1566     Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1567     {
1568         return branchSub32(cond, dest, imm, dest);
1569     }
1570     
1571     void relativeTableJump(RegisterID index, int scale)
1572     {
1573         ASSERT(scale >= 0 && scale <= 31);
1574
1575         // dataTempRegister will point after the jump if index register contains zero
1576         move(ARMRegisters::pc, dataTempRegister);
1577         m_assembler.add(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(9));
1578
1579         ShiftTypeAndAmount shift(SRType_LSL, scale);
1580         m_assembler.add(dataTempRegister, dataTempRegister, index, shift);
1581         jump(dataTempRegister);
1582     }
1583
1584     // Miscellaneous operations:
1585
1586     void breakpoint(uint8_t imm = 0)
1587     {
1588         m_assembler.bkpt(imm);
1589     }
1590
1591     ALWAYS_INLINE Call nearCall()
1592     {
1593         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1594         return Call(m_assembler.blx(dataTempRegister), Call::LinkableNear);
1595     }
1596
1597     ALWAYS_INLINE Call call()
1598     {
1599         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1600         return Call(m_assembler.blx(dataTempRegister), Call::Linkable);
1601     }
1602
1603     ALWAYS_INLINE Call call(RegisterID target)
1604     {
1605         return Call(m_assembler.blx(target), Call::None);
1606     }
1607
1608     ALWAYS_INLINE Call call(Address address)
1609     {
1610         load32(address, dataTempRegister);
1611         return Call(m_assembler.blx(dataTempRegister), Call::None);
1612     }
1613
1614     ALWAYS_INLINE void ret()
1615     {
1616         m_assembler.bx(linkRegister);
1617     }
1618
1619     void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
1620     {
1621         m_assembler.cmp(left, right);
1622         m_assembler.it(armV7Condition(cond), false);
1623         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1624         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1625     }
1626
1627     void compare32(RelationalCondition cond, Address left, RegisterID right, RegisterID dest)
1628     {
1629         load32(left, dataTempRegister);
1630         compare32(cond, dataTempRegister, right, dest);
1631     }
1632
1633     void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest)
1634     {
1635         load8(left, addressTempRegister);
1636         compare32(cond, addressTempRegister, right, dest);
1637     }
1638
1639     void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1640     {
1641         compare32(left, right);
1642         m_assembler.it(armV7Condition(cond), false);
1643         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1644         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1645     }
1646
1647     // FIXME:
1648     // The mask should be optional... paerhaps the argument order should be
1649     // dest-src, operations always have a dest? ... possibly not true, considering
1650     // asm ops like test, or pseudo ops like pop().
1651     void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1652     {
1653         load32(address, dataTempRegister);
1654         test32(dataTempRegister, mask);
1655         m_assembler.it(armV7Condition(cond), false);
1656         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1657         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1658     }
1659
1660     void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1661     {
1662         load8(address, dataTempRegister);
1663         test32(dataTempRegister, mask);
1664         m_assembler.it(armV7Condition(cond), false);
1665         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1666         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1667     }
1668
1669     ALWAYS_INLINE DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dst)
1670     {
1671         padBeforePatch();
1672         moveFixedWidthEncoding(imm, dst);
1673         return DataLabel32(this);
1674     }
1675
1676     ALWAYS_INLINE DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst)
1677     {
1678         padBeforePatch();
1679         moveFixedWidthEncoding(TrustedImm32(imm), dst);
1680         return DataLabelPtr(this);
1681     }
1682
1683     ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1684     {
1685         dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1686         return branch32(cond, left, dataTempRegister);
1687     }
1688
1689     ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1690     {
1691         load32(left, addressTempRegister);
1692         dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1693         return branch32(cond, addressTempRegister, dataTempRegister);
1694     }
1695     
1696     PatchableJump patchableBranchPtr(RelationalCondition cond, Address left, TrustedImmPtr right = TrustedImmPtr(0))
1697     {
1698         m_makeJumpPatchable = true;
1699         Jump result = branch32(cond, left, TrustedImm32(right));
1700         m_makeJumpPatchable = false;
1701         return PatchableJump(result);
1702     }
1703     
1704     PatchableJump patchableBranchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1705     {
1706         m_makeJumpPatchable = true;
1707         Jump result = branchTest32(cond, reg, mask);
1708         m_makeJumpPatchable = false;
1709         return PatchableJump(result);
1710     }
1711
1712     PatchableJump patchableBranch32(RelationalCondition cond, RegisterID reg, TrustedImm32 imm)
1713     {
1714         m_makeJumpPatchable = true;
1715         Jump result = branch32(cond, reg, imm);
1716         m_makeJumpPatchable = false;
1717         return PatchableJump(result);
1718     }
1719
1720     PatchableJump patchableBranchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1721     {
1722         m_makeJumpPatchable = true;
1723         Jump result = branchPtrWithPatch(cond, left, dataLabel, initialRightValue);
1724         m_makeJumpPatchable = false;
1725         return PatchableJump(result);
1726     }
1727
1728     PatchableJump patchableJump()
1729     {
1730         padBeforePatch();
1731         m_makeJumpPatchable = true;
1732         Jump result = jump();
1733         m_makeJumpPatchable = false;
1734         return PatchableJump(result);
1735     }
1736
1737     ALWAYS_INLINE DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
1738     {
1739         DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
1740         store32(dataTempRegister, address);
1741         return label;
1742     }
1743     ALWAYS_INLINE DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(TrustedImmPtr(0), address); }
1744
1745
1746     ALWAYS_INLINE Call tailRecursiveCall()
1747     {
1748         // Like a normal call, but don't link.
1749         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1750         return Call(m_assembler.bx(dataTempRegister), Call::Linkable);
1751     }
1752
1753     ALWAYS_INLINE Call makeTailRecursiveCall(Jump oldJump)
1754     {
1755         oldJump.link(this);
1756         return tailRecursiveCall();
1757     }
1758
1759     
1760     int executableOffsetFor(int location)
1761     {
1762         return m_assembler.executableOffsetFor(location);
1763     }
1764
1765     static FunctionPtr readCallTarget(CodeLocationCall call)
1766     {
1767         return FunctionPtr(reinterpret_cast<void(*)()>(ARMv7Assembler::readCallTarget(call.dataLocation())));
1768     }
1769     
1770     static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; }
1771     
1772     static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label)
1773     {
1774         const unsigned twoWordOpSize = 4;
1775         return label.labelAtOffset(-twoWordOpSize * 2);
1776     }
1777     
1778     static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID rd, void* initialValue)
1779     {
1780 #if OS(LINUX) || OS(QNX)
1781         ARMv7Assembler::revertJumpTo_movT3movtcmpT2(instructionStart.dataLocation(), rd, dataTempRegister, reinterpret_cast<uintptr_t>(initialValue));
1782 #else
1783         UNUSED_PARAM(rd);
1784         ARMv7Assembler::revertJumpTo_movT3(instructionStart.dataLocation(), dataTempRegister, ARMThumbImmediate::makeUInt16(reinterpret_cast<uintptr_t>(initialValue) & 0xffff));
1785 #endif
1786     }
1787     
1788     static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr)
1789     {
1790         UNREACHABLE_FOR_PLATFORM();
1791         return CodeLocationLabel();
1792     }
1793     
1794     static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel, Address, void*)
1795     {
1796         UNREACHABLE_FOR_PLATFORM();
1797     }
1798
1799 protected:
1800     ALWAYS_INLINE Jump jump()
1801     {
1802         m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint.
1803         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1804         return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpNoConditionFixedSize : ARMv7Assembler::JumpNoCondition);
1805     }
1806
1807     ALWAYS_INLINE Jump makeBranch(ARMv7Assembler::Condition cond)
1808     {
1809         m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint.
1810         m_assembler.it(cond, true, true);
1811         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1812         return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpConditionFixedSize : ARMv7Assembler::JumpCondition, cond);
1813     }
1814     ALWAYS_INLINE Jump makeBranch(RelationalCondition cond) { return makeBranch(armV7Condition(cond)); }
1815     ALWAYS_INLINE Jump makeBranch(ResultCondition cond) { return makeBranch(armV7Condition(cond)); }
1816     ALWAYS_INLINE Jump makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); }
1817
1818     ArmAddress setupArmAddress(BaseIndex address)
1819     {
1820         if (address.offset) {
1821             ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1822             if (imm.isValid())
1823                 m_assembler.add(addressTempRegister, address.base, imm);
1824             else {
1825                 move(TrustedImm32(address.offset), addressTempRegister);
1826                 m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1827             }
1828
1829             return ArmAddress(addressTempRegister, address.index, address.scale);
1830         } else
1831             return ArmAddress(address.base, address.index, address.scale);
1832     }
1833
1834     ArmAddress setupArmAddress(Address address)
1835     {
1836         if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1837             return ArmAddress(address.base, address.offset);
1838
1839         move(TrustedImm32(address.offset), addressTempRegister);
1840         return ArmAddress(address.base, addressTempRegister);
1841     }
1842
1843     ArmAddress setupArmAddress(ImplicitAddress address)
1844     {
1845         if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1846             return ArmAddress(address.base, address.offset);
1847
1848         move(TrustedImm32(address.offset), addressTempRegister);
1849         return ArmAddress(address.base, addressTempRegister);
1850     }
1851
1852     RegisterID makeBaseIndexBase(BaseIndex address)
1853     {
1854         if (!address.offset)
1855             return address.base;
1856
1857         ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1858         if (imm.isValid())
1859             m_assembler.add(addressTempRegister, address.base, imm);
1860         else {
1861             move(TrustedImm32(address.offset), addressTempRegister);
1862             m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1863         }
1864
1865         return addressTempRegister;
1866     }
1867
1868     void moveFixedWidthEncoding(TrustedImm32 imm, RegisterID dst)
1869     {
1870         uint32_t value = imm.m_value;
1871         m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff));
1872         m_assembler.movt(dst, ARMThumbImmediate::makeUInt16(value >> 16));
1873     }
1874
1875     ARMv7Assembler::Condition armV7Condition(RelationalCondition cond)
1876     {
1877         return static_cast<ARMv7Assembler::Condition>(cond);
1878     }
1879
1880     ARMv7Assembler::Condition armV7Condition(ResultCondition cond)
1881     {
1882         return static_cast<ARMv7Assembler::Condition>(cond);
1883     }
1884
1885     ARMv7Assembler::Condition armV7Condition(DoubleCondition cond)
1886     {
1887         return static_cast<ARMv7Assembler::Condition>(cond);
1888     }
1889     
1890 private:
1891     friend class LinkBuffer;
1892     friend class RepatchBuffer;
1893
1894     static void linkCall(void* code, Call call, FunctionPtr function)
1895     {
1896         ARMv7Assembler::linkCall(code, call.m_label, function.value());
1897     }
1898
1899     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
1900     {
1901         ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1902     }
1903
1904     static void repatchCall(CodeLocationCall call, FunctionPtr destination)
1905     {
1906         ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1907     }
1908
1909     bool m_makeJumpPatchable;
1910 };
1911
1912 } // namespace JSC
1913
1914 #endif // ENABLE(ASSEMBLER)
1915
1916 #endif // MacroAssemblerARMv7_h