[armv7][arm64] Speculative build fix after r159545.
[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     static const RegisterID dataTempRegister = ARMRegisters::ip;
39     static const RegisterID addressTempRegister = ARMRegisters::r6;
40
41     static const ARMRegisters::FPDoubleRegisterID fpTempRegister = ARMRegisters::d7;
42     inline ARMRegisters::FPSingleRegisterID fpTempRegisterAsSingle() { return ARMRegisters::asSingle(fpTempRegister); }
43
44 public:
45     MacroAssemblerARMv7()
46         : m_makeJumpPatchable(false)
47     {
48     }
49
50     typedef ARMv7Assembler::LinkRecord LinkRecord;
51     typedef ARMv7Assembler::JumpType JumpType;
52     typedef ARMv7Assembler::JumpLinkType JumpLinkType;
53     typedef ARMv7Assembler::Condition Condition;
54
55     static const ARMv7Assembler::Condition DefaultCondition = ARMv7Assembler::ConditionInvalid;
56     static const ARMv7Assembler::JumpType DefaultJump = ARMv7Assembler::JumpNoConditionFixedSize;
57
58     static bool isCompactPtrAlignedAddressOffset(ptrdiff_t value)
59     {
60         return value >= -255 && value <= 255;
61     }
62
63     Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink() { return m_assembler.jumpsToLink(); }
64     void* unlinkedCode() { return m_assembler.unlinkedCode(); }
65     bool canCompact(JumpType jumpType) { return m_assembler.canCompact(jumpType); }
66     JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to) { return m_assembler.computeJumpType(jumpType, from, to); }
67     JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to) { return m_assembler.computeJumpType(record, from, to); }
68     void recordLinkOffsets(int32_t regionStart, int32_t regionEnd, int32_t offset) {return m_assembler.recordLinkOffsets(regionStart, regionEnd, offset); }
69     int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return m_assembler.jumpSizeDelta(jumpType, jumpLinkType); }
70     void link(LinkRecord& record, uint8_t* from, uint8_t* to) { return m_assembler.link(record, from, to); }
71
72     struct ArmAddress {
73         enum AddressType {
74             HasOffset,
75             HasIndex,
76         } type;
77         RegisterID base;
78         union {
79             int32_t offset;
80             struct {
81                 RegisterID index;
82                 Scale scale;
83             };
84         } u;
85         
86         explicit ArmAddress(RegisterID base, int32_t offset = 0)
87             : type(HasOffset)
88             , base(base)
89         {
90             u.offset = offset;
91         }
92         
93         explicit ArmAddress(RegisterID base, RegisterID index, Scale scale = TimesOne)
94             : type(HasIndex)
95             , base(base)
96         {
97             u.index = index;
98             u.scale = scale;
99         }
100     };
101     
102 public:
103     static const Scale ScalePtr = TimesFour;
104
105     enum RelationalCondition {
106         Equal = ARMv7Assembler::ConditionEQ,
107         NotEqual = ARMv7Assembler::ConditionNE,
108         Above = ARMv7Assembler::ConditionHI,
109         AboveOrEqual = ARMv7Assembler::ConditionHS,
110         Below = ARMv7Assembler::ConditionLO,
111         BelowOrEqual = ARMv7Assembler::ConditionLS,
112         GreaterThan = ARMv7Assembler::ConditionGT,
113         GreaterThanOrEqual = ARMv7Assembler::ConditionGE,
114         LessThan = ARMv7Assembler::ConditionLT,
115         LessThanOrEqual = ARMv7Assembler::ConditionLE
116     };
117
118     enum ResultCondition {
119         Overflow = ARMv7Assembler::ConditionVS,
120         Signed = ARMv7Assembler::ConditionMI,
121         PositiveOrZero = ARMv7Assembler::ConditionPL,
122         Zero = ARMv7Assembler::ConditionEQ,
123         NonZero = ARMv7Assembler::ConditionNE
124     };
125
126     enum DoubleCondition {
127         // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
128         DoubleEqual = ARMv7Assembler::ConditionEQ,
129         DoubleNotEqual = ARMv7Assembler::ConditionVC, // Not the right flag! check for this & handle differently.
130         DoubleGreaterThan = ARMv7Assembler::ConditionGT,
131         DoubleGreaterThanOrEqual = ARMv7Assembler::ConditionGE,
132         DoubleLessThan = ARMv7Assembler::ConditionLO,
133         DoubleLessThanOrEqual = ARMv7Assembler::ConditionLS,
134         // If either operand is NaN, these conditions always evaluate to true.
135         DoubleEqualOrUnordered = ARMv7Assembler::ConditionVS, // Not the right flag! check for this & handle differently.
136         DoubleNotEqualOrUnordered = ARMv7Assembler::ConditionNE,
137         DoubleGreaterThanOrUnordered = ARMv7Assembler::ConditionHI,
138         DoubleGreaterThanOrEqualOrUnordered = ARMv7Assembler::ConditionHS,
139         DoubleLessThanOrUnordered = ARMv7Assembler::ConditionLT,
140         DoubleLessThanOrEqualOrUnordered = ARMv7Assembler::ConditionLE,
141     };
142
143     static const RegisterID stackPointerRegister = ARMRegisters::sp;
144     static const RegisterID framePointerRegister = ARMRegisters::fp;
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     void load8(const void* address, RegisterID dest)
656     {
657         move(TrustedImmPtr(address), dest);
658         load8(dest, dest);
659     }
660
661     DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
662     {
663         DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
664         load32(ArmAddress(address.base, dataTempRegister), dest);
665         return label;
666     }
667     
668     DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
669     {
670         padBeforePatch();
671
672         RegisterID base = address.base;
673         
674         DataLabelCompact label(this);
675         ASSERT(isCompactPtrAlignedAddressOffset(address.offset));
676
677         m_assembler.ldr(dest, base, address.offset, true, false);
678         return label;
679     }
680
681     void load16(BaseIndex address, RegisterID dest)
682     {
683         m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale);
684     }
685     
686     void load16Signed(BaseIndex address, RegisterID dest)
687     {
688         load16Signed(setupArmAddress(address), dest);
689     }
690     
691     void load16(ImplicitAddress address, RegisterID dest)
692     {
693         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.offset);
694         if (armImm.isValid())
695             m_assembler.ldrh(dest, address.base, armImm);
696         else {
697             move(TrustedImm32(address.offset), dataTempRegister);
698             m_assembler.ldrh(dest, address.base, dataTempRegister);
699         }
700     }
701     
702     void load16Signed(ImplicitAddress, RegisterID)
703     {
704         UNREACHABLE_FOR_PLATFORM();
705     }
706
707     DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
708     {
709         DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
710         store32(src, ArmAddress(address.base, dataTempRegister));
711         return label;
712     }
713
714     void store32(RegisterID src, ImplicitAddress address)
715     {
716         store32(src, setupArmAddress(address));
717     }
718
719     void store32(RegisterID src, BaseIndex address)
720     {
721         store32(src, setupArmAddress(address));
722     }
723
724     void store32(TrustedImm32 imm, ImplicitAddress address)
725     {
726         move(imm, dataTempRegister);
727         store32(dataTempRegister, setupArmAddress(address));
728     }
729
730     void store32(TrustedImm32 imm, BaseIndex address)
731     {
732         move(imm, dataTempRegister);
733         store32(dataTempRegister, setupArmAddress(address));
734     }
735
736     void store32(RegisterID src, const void* address)
737     {
738         move(TrustedImmPtr(address), addressTempRegister);
739         m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
740     }
741
742     void store32(TrustedImm32 imm, const void* address)
743     {
744         move(imm, dataTempRegister);
745         store32(dataTempRegister, address);
746     }
747
748     void store8(RegisterID src, BaseIndex address)
749     {
750         store8(src, setupArmAddress(address));
751     }
752     
753     void store8(RegisterID src, void* address)
754     {
755         move(TrustedImmPtr(address), addressTempRegister);
756         store8(src, ArmAddress(addressTempRegister, 0));
757     }
758     
759     void store8(TrustedImm32 imm, void* address)
760     {
761         move(imm, dataTempRegister);
762         store8(dataTempRegister, address);
763     }
764     
765     void store16(RegisterID src, BaseIndex address)
766     {
767         store16(src, setupArmAddress(address));
768     }
769
770     // Possibly clobbers src, but not on this architecture.
771     void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2)
772     {
773         m_assembler.vmov(dest1, dest2, src);
774     }
775     
776     void moveIntsToDouble(RegisterID src1, RegisterID src2, FPRegisterID dest, FPRegisterID scratch)
777     {
778         UNUSED_PARAM(scratch);
779         m_assembler.vmov(dest, src1, src2);
780     }
781
782     static bool shouldBlindForSpecificArch(uint32_t value)
783     {
784         ARMThumbImmediate immediate = ARMThumbImmediate::makeEncodedImm(value);
785
786         // Couldn't be encoded as an immediate, so assume it's untrusted.
787         if (!immediate.isValid())
788             return true;
789         
790         // If we can encode the immediate, we have less than 16 attacker
791         // controlled bits.
792         if (immediate.isEncodedImm())
793             return false;
794
795         // Don't let any more than 12 bits of an instruction word
796         // be controlled by an attacker.
797         return !immediate.isUInt12();
798     }
799
800     // Floating-point operations:
801
802     static bool supportsFloatingPoint() { return true; }
803     static bool supportsFloatingPointTruncate() { return true; }
804     static bool supportsFloatingPointSqrt() { return true; }
805     static bool supportsFloatingPointAbs() { return true; }
806
807     void loadDouble(ImplicitAddress address, FPRegisterID dest)
808     {
809         RegisterID base = address.base;
810         int32_t offset = address.offset;
811
812         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
813         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
814             add32(TrustedImm32(offset), base, addressTempRegister);
815             base = addressTempRegister;
816             offset = 0;
817         }
818         
819         m_assembler.vldr(dest, base, offset);
820     }
821
822     void loadFloat(ImplicitAddress address, FPRegisterID dest)
823     {
824         RegisterID base = address.base;
825         int32_t offset = address.offset;
826
827         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
828         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
829             add32(TrustedImm32(offset), base, addressTempRegister);
830             base = addressTempRegister;
831             offset = 0;
832         }
833         
834         m_assembler.flds(ARMRegisters::asSingle(dest), base, offset);
835     }
836
837     void loadDouble(BaseIndex address, FPRegisterID dest)
838     {
839         move(address.index, addressTempRegister);
840         lshift32(TrustedImm32(address.scale), addressTempRegister);
841         add32(address.base, addressTempRegister);
842         loadDouble(Address(addressTempRegister, address.offset), dest);
843     }
844     
845     void loadFloat(BaseIndex address, FPRegisterID dest)
846     {
847         move(address.index, addressTempRegister);
848         lshift32(TrustedImm32(address.scale), addressTempRegister);
849         add32(address.base, addressTempRegister);
850         loadFloat(Address(addressTempRegister, address.offset), dest);
851     }
852
853     void moveDouble(FPRegisterID src, FPRegisterID dest)
854     {
855         if (src != dest)
856             m_assembler.vmov(dest, src);
857     }
858
859     void loadDouble(const void* address, FPRegisterID dest)
860     {
861         move(TrustedImmPtr(address), addressTempRegister);
862         m_assembler.vldr(dest, addressTempRegister, 0);
863     }
864
865     void storeDouble(FPRegisterID src, ImplicitAddress address)
866     {
867         RegisterID base = address.base;
868         int32_t offset = address.offset;
869
870         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
871         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
872             add32(TrustedImm32(offset), base, addressTempRegister);
873             base = addressTempRegister;
874             offset = 0;
875         }
876         
877         m_assembler.vstr(src, base, offset);
878     }
879
880     void storeFloat(FPRegisterID src, ImplicitAddress address)
881     {
882         RegisterID base = address.base;
883         int32_t offset = address.offset;
884
885         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
886         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
887             add32(TrustedImm32(offset), base, addressTempRegister);
888             base = addressTempRegister;
889             offset = 0;
890         }
891         
892         m_assembler.fsts(ARMRegisters::asSingle(src), base, offset);
893     }
894
895     void storeDouble(FPRegisterID src, const void* address)
896     {
897         move(TrustedImmPtr(address), addressTempRegister);
898         storeDouble(src, addressTempRegister);
899     }
900
901     void storeDouble(FPRegisterID src, BaseIndex address)
902     {
903         move(address.index, addressTempRegister);
904         lshift32(TrustedImm32(address.scale), addressTempRegister);
905         add32(address.base, addressTempRegister);
906         storeDouble(src, Address(addressTempRegister, address.offset));
907     }
908     
909     void storeFloat(FPRegisterID src, BaseIndex address)
910     {
911         move(address.index, addressTempRegister);
912         lshift32(TrustedImm32(address.scale), addressTempRegister);
913         add32(address.base, addressTempRegister);
914         storeFloat(src, Address(addressTempRegister, address.offset));
915     }
916     
917     void addDouble(FPRegisterID src, FPRegisterID dest)
918     {
919         m_assembler.vadd(dest, dest, src);
920     }
921
922     void addDouble(Address src, FPRegisterID dest)
923     {
924         loadDouble(src, fpTempRegister);
925         addDouble(fpTempRegister, dest);
926     }
927
928     void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
929     {
930         m_assembler.vadd(dest, op1, op2);
931     }
932
933     void addDouble(AbsoluteAddress address, FPRegisterID dest)
934     {
935         loadDouble(address.m_ptr, fpTempRegister);
936         m_assembler.vadd(dest, dest, fpTempRegister);
937     }
938
939     void divDouble(FPRegisterID src, FPRegisterID dest)
940     {
941         m_assembler.vdiv(dest, dest, src);
942     }
943
944     void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
945     {
946         m_assembler.vdiv(dest, op1, op2);
947     }
948
949     void subDouble(FPRegisterID src, FPRegisterID dest)
950     {
951         m_assembler.vsub(dest, dest, src);
952     }
953
954     void subDouble(Address src, FPRegisterID dest)
955     {
956         loadDouble(src, fpTempRegister);
957         subDouble(fpTempRegister, dest);
958     }
959
960     void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
961     {
962         m_assembler.vsub(dest, op1, op2);
963     }
964
965     void mulDouble(FPRegisterID src, FPRegisterID dest)
966     {
967         m_assembler.vmul(dest, dest, src);
968     }
969
970     void mulDouble(Address src, FPRegisterID dest)
971     {
972         loadDouble(src, fpTempRegister);
973         mulDouble(fpTempRegister, dest);
974     }
975
976     void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
977     {
978         m_assembler.vmul(dest, op1, op2);
979     }
980
981     void sqrtDouble(FPRegisterID src, FPRegisterID dest)
982     {
983         m_assembler.vsqrt(dest, src);
984     }
985     
986     void absDouble(FPRegisterID src, FPRegisterID dest)
987     {
988         m_assembler.vabs(dest, src);
989     }
990
991     void negateDouble(FPRegisterID src, FPRegisterID dest)
992     {
993         m_assembler.vneg(dest, src);
994     }
995
996     void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
997     {
998         m_assembler.vmov(fpTempRegister, src, src);
999         m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
1000     }
1001
1002     void convertInt32ToDouble(Address address, FPRegisterID dest)
1003     {
1004         // Fixme: load directly into the fpr!
1005         load32(address, dataTempRegister);
1006         m_assembler.vmov(fpTempRegister, dataTempRegister, dataTempRegister);
1007         m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
1008     }
1009
1010     void convertInt32ToDouble(AbsoluteAddress address, FPRegisterID dest)
1011     {
1012         // Fixme: load directly into the fpr!
1013         load32(address.m_ptr, dataTempRegister);
1014         m_assembler.vmov(fpTempRegister, dataTempRegister, dataTempRegister);
1015         m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
1016     }
1017     
1018     void convertFloatToDouble(FPRegisterID src, FPRegisterID dst)
1019     {
1020         m_assembler.vcvtds(dst, ARMRegisters::asSingle(src));
1021     }
1022     
1023     void convertDoubleToFloat(FPRegisterID src, FPRegisterID dst)
1024     {
1025         m_assembler.vcvtsd(ARMRegisters::asSingle(dst), src);
1026     }
1027
1028     Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
1029     {
1030         m_assembler.vcmp(left, right);
1031         m_assembler.vmrs();
1032
1033         if (cond == DoubleNotEqual) {
1034             // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump.
1035             Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1036             Jump result = makeBranch(ARMv7Assembler::ConditionNE);
1037             unordered.link(this);
1038             return result;
1039         }
1040         if (cond == DoubleEqualOrUnordered) {
1041             Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1042             Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
1043             unordered.link(this);
1044             // We get here if either unordered or equal.
1045             Jump result = jump();
1046             notEqual.link(this);
1047             return result;
1048         }
1049         return makeBranch(cond);
1050     }
1051
1052     enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
1053     Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
1054     {
1055         // Convert into dest.
1056         m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1057         m_assembler.vmov(dest, fpTempRegisterAsSingle());
1058
1059         // Calculate 2x dest.  If the value potentially underflowed, it will have
1060         // clamped to 0x80000000, so 2x dest is zero in this case. In the case of
1061         // overflow the result will be equal to -2.
1062         Jump underflow = branchAdd32(Zero, dest, dest, dataTempRegister);
1063         Jump noOverflow = branch32(NotEqual, dataTempRegister, TrustedImm32(-2));
1064
1065         // For BranchIfTruncateSuccessful, we branch if 'noOverflow' jumps.
1066         underflow.link(this);
1067         if (branchType == BranchIfTruncateSuccessful)
1068             return noOverflow;
1069
1070         // We'll reach the current point in the code on failure, so plant a
1071         // jump here & link the success case.
1072         Jump failure = jump();
1073         noOverflow.link(this);
1074         return failure;
1075     }
1076
1077     Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
1078     {
1079         m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1080         m_assembler.vmov(dest, fpTempRegisterAsSingle());
1081         
1082         Jump overflow = branch32(Equal, dest, TrustedImm32(0x7fffffff));
1083         Jump success = branch32(GreaterThanOrEqual, dest, TrustedImm32(0));
1084         overflow.link(this);
1085
1086         if (branchType == BranchIfTruncateSuccessful)
1087             return success;
1088         
1089         Jump failure = jump();
1090         success.link(this);
1091         return failure;
1092     }
1093
1094     // Result is undefined if the value is outside of the integer range.
1095     void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
1096     {
1097         m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1098         m_assembler.vmov(dest, fpTempRegisterAsSingle());
1099     }
1100
1101     void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
1102     {
1103         m_assembler.vcvt_floatingPointToUnsigned(fpTempRegisterAsSingle(), src);
1104         m_assembler.vmov(dest, fpTempRegisterAsSingle());
1105     }
1106     
1107     // Convert 'src' to an integer, and places the resulting 'dest'.
1108     // If the result is not representable as a 32 bit value, branch.
1109     // May also branch for some values that are representable in 32 bits
1110     // (specifically, in this case, 0).
1111     void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID, bool negZeroCheck = true)
1112     {
1113         m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1114         m_assembler.vmov(dest, fpTempRegisterAsSingle());
1115
1116         // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
1117         m_assembler.vcvt_signedToFloatingPoint(fpTempRegister, fpTempRegisterAsSingle());
1118         failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, fpTempRegister));
1119
1120         // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
1121         if (negZeroCheck)
1122             failureCases.append(branchTest32(Zero, dest));
1123     }
1124
1125     Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID)
1126     {
1127         m_assembler.vcmpz(reg);
1128         m_assembler.vmrs();
1129         Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1130         Jump result = makeBranch(ARMv7Assembler::ConditionNE);
1131         unordered.link(this);
1132         return result;
1133     }
1134
1135     Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID)
1136     {
1137         m_assembler.vcmpz(reg);
1138         m_assembler.vmrs();
1139         Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1140         Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
1141         unordered.link(this);
1142         // We get here if either unordered or equal.
1143         Jump result = jump();
1144         notEqual.link(this);
1145         return result;
1146     }
1147
1148     // Stack manipulation operations:
1149     //
1150     // The ABI is assumed to provide a stack abstraction to memory,
1151     // containing machine word sized units of data.  Push and pop
1152     // operations add and remove a single register sized unit of data
1153     // to or from the stack.  Peek and poke operations read or write
1154     // values on the stack, without moving the current stack position.
1155     
1156     void pop(RegisterID dest)
1157     {
1158         // store postindexed with writeback
1159         m_assembler.ldr(dest, ARMRegisters::sp, sizeof(void*), false, true);
1160     }
1161
1162     void push(RegisterID src)
1163     {
1164         // store preindexed with writeback
1165         m_assembler.str(src, ARMRegisters::sp, -sizeof(void*), true, true);
1166     }
1167
1168     void push(Address address)
1169     {
1170         load32(address, dataTempRegister);
1171         push(dataTempRegister);
1172     }
1173
1174     void push(TrustedImm32 imm)
1175     {
1176         move(imm, dataTempRegister);
1177         push(dataTempRegister);
1178     }
1179
1180     // Register move operations:
1181     //
1182     // Move values in registers.
1183
1184     void move(TrustedImm32 imm, RegisterID dest)
1185     {
1186         uint32_t value = imm.m_value;
1187
1188         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(value);
1189
1190         if (armImm.isValid())
1191             m_assembler.mov(dest, armImm);
1192         else if ((armImm = ARMThumbImmediate::makeEncodedImm(~value)).isValid())
1193             m_assembler.mvn(dest, armImm);
1194         else {
1195             m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(value));
1196             if (value & 0xffff0000)
1197                 m_assembler.movt(dest, ARMThumbImmediate::makeUInt16(value >> 16));
1198         }
1199     }
1200
1201     void move(RegisterID src, RegisterID dest)
1202     {
1203         if (src != dest)
1204             m_assembler.mov(dest, src);
1205     }
1206
1207     void move(TrustedImmPtr imm, RegisterID dest)
1208     {
1209         move(TrustedImm32(imm), dest);
1210     }
1211
1212     void swap(RegisterID reg1, RegisterID reg2)
1213     {
1214         move(reg1, dataTempRegister);
1215         move(reg2, reg1);
1216         move(dataTempRegister, reg2);
1217     }
1218
1219     void signExtend32ToPtr(RegisterID src, RegisterID dest)
1220     {
1221         move(src, dest);
1222     }
1223
1224     void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
1225     {
1226         move(src, dest);
1227     }
1228
1229     // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
1230     static RelationalCondition invert(RelationalCondition cond)
1231     {
1232         return static_cast<RelationalCondition>(cond ^ 1);
1233     }
1234
1235     void nop()
1236     {
1237         m_assembler.nop();
1238     }
1239     
1240     void memoryFence()
1241     {
1242         m_assembler.dmbSY();
1243     }
1244     
1245     static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
1246     {
1247         ARMv7Assembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
1248     }
1249     
1250     static ptrdiff_t maxJumpReplacementSize()
1251     {
1252         return ARMv7Assembler::maxJumpReplacementSize();
1253     }
1254
1255     // Forwards / external control flow operations:
1256     //
1257     // This set of jump and conditional branch operations return a Jump
1258     // object which may linked at a later point, allow forwards jump,
1259     // or jumps that will require external linkage (after the code has been
1260     // relocated).
1261     //
1262     // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
1263     // respecitvely, for unsigned comparisons the names b, a, be, and ae are
1264     // used (representing the names 'below' and 'above').
1265     //
1266     // Operands to the comparision are provided in the expected order, e.g.
1267     // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
1268     // treated as a signed 32bit value, is less than or equal to 5.
1269     //
1270     // jz and jnz test whether the first operand is equal to zero, and take
1271     // an optional second operand of a mask under which to perform the test.
1272 private:
1273
1274     // Should we be using TEQ for equal/not-equal?
1275     void compare32(RegisterID left, TrustedImm32 right)
1276     {
1277         int32_t imm = right.m_value;
1278         if (!imm)
1279             m_assembler.tst(left, left);
1280         else {
1281             ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
1282             if (armImm.isValid())
1283                 m_assembler.cmp(left, armImm);
1284             else if ((armImm = ARMThumbImmediate::makeEncodedImm(-imm)).isValid())
1285                 m_assembler.cmn(left, armImm);
1286             else {
1287                 move(TrustedImm32(imm), dataTempRegister);
1288                 m_assembler.cmp(left, dataTempRegister);
1289             }
1290         }
1291     }
1292
1293     void test32(RegisterID reg, TrustedImm32 mask)
1294     {
1295         int32_t imm = mask.m_value;
1296
1297         if (imm == -1)
1298             m_assembler.tst(reg, reg);
1299         else {
1300             ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
1301             if (armImm.isValid())
1302                 m_assembler.tst(reg, armImm);
1303             else {
1304                 move(mask, dataTempRegister);
1305                 m_assembler.tst(reg, dataTempRegister);
1306             }
1307         }
1308     }
1309
1310 public:
1311     Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
1312     {
1313         m_assembler.cmp(left, right);
1314         return Jump(makeBranch(cond));
1315     }
1316
1317     Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1318     {
1319         compare32(left, right);
1320         return Jump(makeBranch(cond));
1321     }
1322
1323     Jump branch32(RelationalCondition cond, RegisterID left, Address right)
1324     {
1325         load32(right, dataTempRegister);
1326         return branch32(cond, left, dataTempRegister);
1327     }
1328
1329     Jump branch32(RelationalCondition cond, Address left, RegisterID right)
1330     {
1331         load32(left, dataTempRegister);
1332         return branch32(cond, dataTempRegister, right);
1333     }
1334
1335     Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
1336     {
1337         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1338         load32(left, addressTempRegister);
1339         return branch32(cond, addressTempRegister, right);
1340     }
1341
1342     Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1343     {
1344         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1345         load32(left, addressTempRegister);
1346         return branch32(cond, addressTempRegister, right);
1347     }
1348
1349     Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1350     {
1351         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1352         load32WithUnalignedHalfWords(left, addressTempRegister);
1353         return branch32(cond, addressTempRegister, right);
1354     }
1355
1356     Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
1357     {
1358         load32(left.m_ptr, dataTempRegister);
1359         return branch32(cond, dataTempRegister, right);
1360     }
1361
1362     Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
1363     {
1364         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1365         load32(left.m_ptr, addressTempRegister);
1366         return branch32(cond, addressTempRegister, right);
1367     }
1368
1369     Jump branch8(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1370     {
1371         compare32(left, right);
1372         return Jump(makeBranch(cond));
1373     }
1374
1375     Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
1376     {
1377         ASSERT(!(0xffffff00 & right.m_value));
1378         // use addressTempRegister incase the branch8 we call uses dataTempRegister. :-/
1379         load8(left, addressTempRegister);
1380         return branch8(cond, addressTempRegister, right);
1381     }
1382
1383     Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1384     {
1385         ASSERT(!(0xffffff00 & right.m_value));
1386         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1387         load8(left, addressTempRegister);
1388         return branch32(cond, addressTempRegister, right);
1389     }
1390     
1391     Jump branch8(RelationalCondition cond, AbsoluteAddress address, TrustedImm32 right)
1392     {
1393         // Use addressTempRegister instead of dataTempRegister, since branch32 uses dataTempRegister.
1394         move(TrustedImmPtr(address.m_ptr), addressTempRegister);
1395         load8(Address(addressTempRegister), addressTempRegister);
1396         return branch32(cond, addressTempRegister, right);
1397     }
1398     
1399     Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
1400     {
1401         m_assembler.tst(reg, mask);
1402         return Jump(makeBranch(cond));
1403     }
1404
1405     Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1406     {
1407         test32(reg, mask);
1408         return Jump(makeBranch(cond));
1409     }
1410
1411     Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1412     {
1413         // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1414         load32(address, addressTempRegister);
1415         return branchTest32(cond, addressTempRegister, mask);
1416     }
1417
1418     Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1419     {
1420         // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1421         load32(address, addressTempRegister);
1422         return branchTest32(cond, addressTempRegister, mask);
1423     }
1424
1425     Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1426     {
1427         // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1428         load8(address, addressTempRegister);
1429         return branchTest32(cond, addressTempRegister, mask);
1430     }
1431
1432     Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
1433     {
1434         // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1435         move(TrustedImmPtr(address.m_ptr), addressTempRegister);
1436         load8(Address(addressTempRegister), addressTempRegister);
1437         return branchTest32(cond, addressTempRegister, mask);
1438     }
1439
1440     void jump(RegisterID target)
1441     {
1442         m_assembler.bx(target);
1443     }
1444
1445     // Address is a memory location containing the address to jump to
1446     void jump(Address address)
1447     {
1448         load32(address, dataTempRegister);
1449         m_assembler.bx(dataTempRegister);
1450     }
1451     
1452     void jump(AbsoluteAddress address)
1453     {
1454         move(TrustedImmPtr(address.m_ptr), dataTempRegister);
1455         load32(Address(dataTempRegister), dataTempRegister);
1456         m_assembler.bx(dataTempRegister);
1457     }
1458
1459
1460     // Arithmetic control flow operations:
1461     //
1462     // This set of conditional branch operations branch based
1463     // on the result of an arithmetic operation.  The operation
1464     // is performed as normal, storing the result.
1465     //
1466     // * jz operations branch if the result is zero.
1467     // * jo operations branch if the (signed) arithmetic
1468     //   operation caused an overflow to occur.
1469     
1470     Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1471     {
1472         m_assembler.add_S(dest, op1, op2);
1473         return Jump(makeBranch(cond));
1474     }
1475
1476     Jump branchAdd32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
1477     {
1478         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1479         if (armImm.isValid())
1480             m_assembler.add_S(dest, op1, armImm);
1481         else {
1482             move(imm, dataTempRegister);
1483             m_assembler.add_S(dest, op1, dataTempRegister);
1484         }
1485         return Jump(makeBranch(cond));
1486     }
1487
1488     Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
1489     {
1490         return branchAdd32(cond, dest, src, dest);
1491     }
1492
1493     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1494     {
1495         return branchAdd32(cond, dest, imm, dest);
1496     }
1497
1498     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
1499     {
1500         // Move the high bits of the address into addressTempRegister,
1501         // and load the value into dataTempRegister.
1502         move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
1503         m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
1504
1505         // Do the add.
1506         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1507         if (armImm.isValid())
1508             m_assembler.add_S(dataTempRegister, dataTempRegister, armImm);
1509         else {
1510             // If the operand does not fit into an immediate then load it temporarily
1511             // into addressTempRegister; since we're overwriting addressTempRegister
1512             // we'll need to reload it with the high bits of the address afterwards.
1513             move(imm, addressTempRegister);
1514             m_assembler.add_S(dataTempRegister, dataTempRegister, addressTempRegister);
1515             move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
1516         }
1517
1518         // Store the result.
1519         m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
1520
1521         return Jump(makeBranch(cond));
1522     }
1523
1524     Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
1525     {
1526         m_assembler.smull(dest, dataTempRegister, src1, src2);
1527
1528         if (cond == Overflow) {
1529             m_assembler.asr(addressTempRegister, dest, 31);
1530             return branch32(NotEqual, addressTempRegister, dataTempRegister);
1531         }
1532
1533         return branchTest32(cond, dest);
1534     }
1535
1536     Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
1537     {
1538         return branchMul32(cond, src, dest, dest);
1539     }
1540
1541     Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
1542     {
1543         move(imm, dataTempRegister);
1544         return branchMul32(cond, dataTempRegister, src, dest);
1545     }
1546
1547     Jump branchNeg32(ResultCondition cond, RegisterID srcDest)
1548     {
1549         ARMThumbImmediate zero = ARMThumbImmediate::makeUInt12(0);
1550         m_assembler.sub_S(srcDest, zero, srcDest);
1551         return Jump(makeBranch(cond));
1552     }
1553
1554     Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
1555     {
1556         m_assembler.orr_S(dest, dest, src);
1557         return Jump(makeBranch(cond));
1558     }
1559
1560     Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1561     {
1562         m_assembler.sub_S(dest, op1, op2);
1563         return Jump(makeBranch(cond));
1564     }
1565
1566     Jump branchSub32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
1567     {
1568         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1569         if (armImm.isValid())
1570             m_assembler.sub_S(dest, op1, armImm);
1571         else {
1572             move(imm, dataTempRegister);
1573             m_assembler.sub_S(dest, op1, dataTempRegister);
1574         }
1575         return Jump(makeBranch(cond));
1576     }
1577     
1578     Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
1579     {
1580         return branchSub32(cond, dest, src, dest);
1581     }
1582
1583     Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1584     {
1585         return branchSub32(cond, dest, imm, dest);
1586     }
1587     
1588     void relativeTableJump(RegisterID index, int scale)
1589     {
1590         ASSERT(scale >= 0 && scale <= 31);
1591
1592         // dataTempRegister will point after the jump if index register contains zero
1593         move(ARMRegisters::pc, dataTempRegister);
1594         m_assembler.add(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(9));
1595
1596         ShiftTypeAndAmount shift(SRType_LSL, scale);
1597         m_assembler.add(dataTempRegister, dataTempRegister, index, shift);
1598         jump(dataTempRegister);
1599     }
1600
1601     // Miscellaneous operations:
1602
1603     void breakpoint(uint8_t imm = 0)
1604     {
1605         m_assembler.bkpt(imm);
1606     }
1607
1608     ALWAYS_INLINE Call nearCall()
1609     {
1610         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1611         return Call(m_assembler.blx(dataTempRegister), Call::LinkableNear);
1612     }
1613
1614     ALWAYS_INLINE Call call()
1615     {
1616         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1617         return Call(m_assembler.blx(dataTempRegister), Call::Linkable);
1618     }
1619
1620     ALWAYS_INLINE Call call(RegisterID target)
1621     {
1622         return Call(m_assembler.blx(target), Call::None);
1623     }
1624
1625     ALWAYS_INLINE Call call(Address address)
1626     {
1627         load32(address, dataTempRegister);
1628         return Call(m_assembler.blx(dataTempRegister), Call::None);
1629     }
1630
1631     ALWAYS_INLINE void ret()
1632     {
1633         m_assembler.bx(linkRegister);
1634     }
1635
1636     void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
1637     {
1638         m_assembler.cmp(left, right);
1639         m_assembler.it(armV7Condition(cond), false);
1640         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1641         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1642     }
1643
1644     void compare32(RelationalCondition cond, Address left, RegisterID right, RegisterID dest)
1645     {
1646         load32(left, dataTempRegister);
1647         compare32(cond, dataTempRegister, right, dest);
1648     }
1649
1650     void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest)
1651     {
1652         load8(left, addressTempRegister);
1653         compare32(cond, addressTempRegister, right, dest);
1654     }
1655
1656     void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1657     {
1658         compare32(left, right);
1659         m_assembler.it(armV7Condition(cond), false);
1660         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1661         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1662     }
1663
1664     // FIXME:
1665     // The mask should be optional... paerhaps the argument order should be
1666     // dest-src, operations always have a dest? ... possibly not true, considering
1667     // asm ops like test, or pseudo ops like pop().
1668     void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1669     {
1670         load32(address, dataTempRegister);
1671         test32(dataTempRegister, mask);
1672         m_assembler.it(armV7Condition(cond), false);
1673         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1674         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1675     }
1676
1677     void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1678     {
1679         load8(address, dataTempRegister);
1680         test32(dataTempRegister, mask);
1681         m_assembler.it(armV7Condition(cond), false);
1682         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1683         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1684     }
1685
1686     ALWAYS_INLINE DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dst)
1687     {
1688         padBeforePatch();
1689         moveFixedWidthEncoding(imm, dst);
1690         return DataLabel32(this);
1691     }
1692
1693     ALWAYS_INLINE DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst)
1694     {
1695         padBeforePatch();
1696         moveFixedWidthEncoding(TrustedImm32(imm), dst);
1697         return DataLabelPtr(this);
1698     }
1699
1700     ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1701     {
1702         dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1703         return branch32(cond, left, dataTempRegister);
1704     }
1705
1706     ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1707     {
1708         load32(left, addressTempRegister);
1709         dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1710         return branch32(cond, addressTempRegister, dataTempRegister);
1711     }
1712     
1713     PatchableJump patchableBranchPtr(RelationalCondition cond, Address left, TrustedImmPtr right = TrustedImmPtr(0))
1714     {
1715         m_makeJumpPatchable = true;
1716         Jump result = branch32(cond, left, TrustedImm32(right));
1717         m_makeJumpPatchable = false;
1718         return PatchableJump(result);
1719     }
1720     
1721     PatchableJump patchableBranchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1722     {
1723         m_makeJumpPatchable = true;
1724         Jump result = branchTest32(cond, reg, mask);
1725         m_makeJumpPatchable = false;
1726         return PatchableJump(result);
1727     }
1728
1729     PatchableJump patchableBranch32(RelationalCondition cond, RegisterID reg, TrustedImm32 imm)
1730     {
1731         m_makeJumpPatchable = true;
1732         Jump result = branch32(cond, reg, imm);
1733         m_makeJumpPatchable = false;
1734         return PatchableJump(result);
1735     }
1736
1737     PatchableJump patchableBranchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1738     {
1739         m_makeJumpPatchable = true;
1740         Jump result = branchPtrWithPatch(cond, left, dataLabel, initialRightValue);
1741         m_makeJumpPatchable = false;
1742         return PatchableJump(result);
1743     }
1744
1745     PatchableJump patchableJump()
1746     {
1747         padBeforePatch();
1748         m_makeJumpPatchable = true;
1749         Jump result = jump();
1750         m_makeJumpPatchable = false;
1751         return PatchableJump(result);
1752     }
1753
1754     ALWAYS_INLINE DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
1755     {
1756         DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
1757         store32(dataTempRegister, address);
1758         return label;
1759     }
1760     ALWAYS_INLINE DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(TrustedImmPtr(0), address); }
1761
1762
1763     ALWAYS_INLINE Call tailRecursiveCall()
1764     {
1765         // Like a normal call, but don't link.
1766         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1767         return Call(m_assembler.bx(dataTempRegister), Call::Linkable);
1768     }
1769
1770     ALWAYS_INLINE Call makeTailRecursiveCall(Jump oldJump)
1771     {
1772         oldJump.link(this);
1773         return tailRecursiveCall();
1774     }
1775
1776     
1777     int executableOffsetFor(int location)
1778     {
1779         return m_assembler.executableOffsetFor(location);
1780     }
1781
1782     static FunctionPtr readCallTarget(CodeLocationCall call)
1783     {
1784         return FunctionPtr(reinterpret_cast<void(*)()>(ARMv7Assembler::readCallTarget(call.dataLocation())));
1785     }
1786     
1787     static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; }
1788     
1789     static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label)
1790     {
1791         const unsigned twoWordOpSize = 4;
1792         return label.labelAtOffset(-twoWordOpSize * 2);
1793     }
1794     
1795     static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID rd, void* initialValue)
1796     {
1797 #if OS(LINUX) || OS(QNX)
1798         ARMv7Assembler::revertJumpTo_movT3movtcmpT2(instructionStart.dataLocation(), rd, dataTempRegister, reinterpret_cast<uintptr_t>(initialValue));
1799 #else
1800         UNUSED_PARAM(rd);
1801         ARMv7Assembler::revertJumpTo_movT3(instructionStart.dataLocation(), dataTempRegister, ARMThumbImmediate::makeUInt16(reinterpret_cast<uintptr_t>(initialValue) & 0xffff));
1802 #endif
1803     }
1804     
1805     static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr)
1806     {
1807         UNREACHABLE_FOR_PLATFORM();
1808         return CodeLocationLabel();
1809     }
1810     
1811     static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel, Address, void*)
1812     {
1813         UNREACHABLE_FOR_PLATFORM();
1814     }
1815
1816 #if USE(MASM_PROBE)
1817     struct CPUState {
1818         #define DECLARE_REGISTER(_type, _regName) \
1819             _type _regName;
1820         FOR_EACH_CPU_REGISTER(DECLARE_REGISTER)
1821         #undef DECLARE_REGISTER
1822     };
1823
1824     struct ProbeContext;
1825     typedef void (*ProbeFunction)(struct ProbeContext*);
1826
1827     struct ProbeContext {
1828         ProbeFunction probeFunction;
1829         void* arg1;
1830         void* arg2;
1831         CPUState cpu;
1832
1833         void dump(const char* indentation = 0);
1834     private:
1835         void dumpCPURegisters(const char* indentation);
1836     };
1837
1838     // For details about probe(), see comment in MacroAssemblerX86_64.h.
1839     void probe(ProbeFunction, void* arg1 = 0, void* arg2 = 0);
1840 #endif // USE(MASM_PROBE)
1841
1842 protected:
1843     ALWAYS_INLINE Jump jump()
1844     {
1845         m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint.
1846         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1847         return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpNoConditionFixedSize : ARMv7Assembler::JumpNoCondition);
1848     }
1849
1850     ALWAYS_INLINE Jump makeBranch(ARMv7Assembler::Condition cond)
1851     {
1852         m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint.
1853         m_assembler.it(cond, true, true);
1854         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1855         return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpConditionFixedSize : ARMv7Assembler::JumpCondition, cond);
1856     }
1857     ALWAYS_INLINE Jump makeBranch(RelationalCondition cond) { return makeBranch(armV7Condition(cond)); }
1858     ALWAYS_INLINE Jump makeBranch(ResultCondition cond) { return makeBranch(armV7Condition(cond)); }
1859     ALWAYS_INLINE Jump makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); }
1860
1861     ArmAddress setupArmAddress(BaseIndex address)
1862     {
1863         if (address.offset) {
1864             ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1865             if (imm.isValid())
1866                 m_assembler.add(addressTempRegister, address.base, imm);
1867             else {
1868                 move(TrustedImm32(address.offset), addressTempRegister);
1869                 m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1870             }
1871
1872             return ArmAddress(addressTempRegister, address.index, address.scale);
1873         } else
1874             return ArmAddress(address.base, address.index, address.scale);
1875     }
1876
1877     ArmAddress setupArmAddress(Address address)
1878     {
1879         if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1880             return ArmAddress(address.base, address.offset);
1881
1882         move(TrustedImm32(address.offset), addressTempRegister);
1883         return ArmAddress(address.base, addressTempRegister);
1884     }
1885
1886     ArmAddress setupArmAddress(ImplicitAddress address)
1887     {
1888         if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1889             return ArmAddress(address.base, address.offset);
1890
1891         move(TrustedImm32(address.offset), addressTempRegister);
1892         return ArmAddress(address.base, addressTempRegister);
1893     }
1894
1895     RegisterID makeBaseIndexBase(BaseIndex address)
1896     {
1897         if (!address.offset)
1898             return address.base;
1899
1900         ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1901         if (imm.isValid())
1902             m_assembler.add(addressTempRegister, address.base, imm);
1903         else {
1904             move(TrustedImm32(address.offset), addressTempRegister);
1905             m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1906         }
1907
1908         return addressTempRegister;
1909     }
1910
1911     void moveFixedWidthEncoding(TrustedImm32 imm, RegisterID dst)
1912     {
1913         uint32_t value = imm.m_value;
1914         m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff));
1915         m_assembler.movt(dst, ARMThumbImmediate::makeUInt16(value >> 16));
1916     }
1917
1918     ARMv7Assembler::Condition armV7Condition(RelationalCondition cond)
1919     {
1920         return static_cast<ARMv7Assembler::Condition>(cond);
1921     }
1922
1923     ARMv7Assembler::Condition armV7Condition(ResultCondition cond)
1924     {
1925         return static_cast<ARMv7Assembler::Condition>(cond);
1926     }
1927
1928     ARMv7Assembler::Condition armV7Condition(DoubleCondition cond)
1929     {
1930         return static_cast<ARMv7Assembler::Condition>(cond);
1931     }
1932     
1933 private:
1934     friend class LinkBuffer;
1935     friend class RepatchBuffer;
1936
1937     static void linkCall(void* code, Call call, FunctionPtr function)
1938     {
1939         ARMv7Assembler::linkCall(code, call.m_label, function.value());
1940     }
1941
1942     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
1943     {
1944         ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1945     }
1946
1947     static void repatchCall(CodeLocationCall call, FunctionPtr destination)
1948     {
1949         ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1950     }
1951
1952 #if USE(MASM_PROBE)
1953     inline TrustedImm32 trustedImm32FromPtr(void* ptr)
1954     {
1955         return TrustedImm32(TrustedImmPtr(ptr));
1956     }
1957
1958     inline TrustedImm32 trustedImm32FromPtr(ProbeFunction function)
1959     {
1960         return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function)));
1961     }
1962
1963     inline TrustedImm32 trustedImm32FromPtr(void (*function)())
1964     {
1965         return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function)));
1966     }
1967 #endif
1968
1969     bool m_makeJumpPatchable;
1970 };
1971
1972 } // namespace JSC
1973
1974 #endif // ENABLE(ASSEMBLER)
1975
1976 #endif // MacroAssemblerARMv7_h