initial import
[vuplus_webkit] / 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     typedef ARMv7Assembler::LinkRecord LinkRecord;
49     typedef ARMv7Assembler::JumpType JumpType;
50     typedef ARMv7Assembler::JumpLinkType JumpLinkType;
51     // Magic number is the biggest useful offset we can get on ARMv7 with
52     // a LDR_imm_T2 encoding
53     static const int MaximumCompactPtrAlignedAddressOffset = 124;
54
55     MacroAssemblerARMv7()
56         : m_inUninterruptedSequence(false)
57     {
58     }
59     
60     void beginUninterruptedSequence() { m_inUninterruptedSequence = true; }
61     void endUninterruptedSequence() { m_inUninterruptedSequence = false; }
62     Vector<LinkRecord>& 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         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 linkRegister = ARMRegisters::lr;
145
146     // Integer arithmetic operations:
147     //
148     // Operations are typically two operand - operation(source, srcDst)
149     // For many operations the source may be an TrustedImm32, the srcDst operand
150     // may often be a memory location (explictly described using an Address
151     // object).
152
153     void add32(RegisterID src, RegisterID dest)
154     {
155         m_assembler.add(dest, dest, src);
156     }
157
158     void add32(TrustedImm32 imm, RegisterID dest)
159     {
160         add32(imm, dest, dest);
161     }
162
163     void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
164     {
165         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
166         if (armImm.isValid())
167             m_assembler.add(dest, src, armImm);
168         else {
169             move(imm, dataTempRegister);
170             m_assembler.add(dest, src, dataTempRegister);
171         }
172     }
173
174     void add32(TrustedImm32 imm, Address address)
175     {
176         load32(address, dataTempRegister);
177
178         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
179         if (armImm.isValid())
180             m_assembler.add(dataTempRegister, dataTempRegister, armImm);
181         else {
182             // Hrrrm, since dataTempRegister holds the data loaded,
183             // use addressTempRegister to hold the immediate.
184             move(imm, addressTempRegister);
185             m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister);
186         }
187
188         store32(dataTempRegister, address);
189     }
190
191     void add32(Address src, RegisterID dest)
192     {
193         load32(src, dataTempRegister);
194         add32(dataTempRegister, dest);
195     }
196
197     void add32(TrustedImm32 imm, AbsoluteAddress address)
198     {
199         load32(address.m_ptr, dataTempRegister);
200
201         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
202         if (armImm.isValid())
203             m_assembler.add(dataTempRegister, dataTempRegister, armImm);
204         else {
205             // Hrrrm, since dataTempRegister holds the data loaded,
206             // use addressTempRegister to hold the immediate.
207             move(imm, addressTempRegister);
208             m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister);
209         }
210
211         store32(dataTempRegister, address.m_ptr);
212     }
213
214     void and32(RegisterID src, RegisterID dest)
215     {
216         m_assembler.ARM_and(dest, dest, src);
217     }
218
219     void and32(TrustedImm32 imm, RegisterID dest)
220     {
221         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
222         if (armImm.isValid())
223             m_assembler.ARM_and(dest, dest, armImm);
224         else {
225             move(imm, dataTempRegister);
226             m_assembler.ARM_and(dest, dest, dataTempRegister);
227         }
228     }
229
230     void countLeadingZeros32(RegisterID src, RegisterID dest)
231     {
232         m_assembler.clz(dest, src);
233     }
234
235     void lshift32(RegisterID shift_amount, RegisterID dest)
236     {
237         // Clamp the shift to the range 0..31
238         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
239         ASSERT(armImm.isValid());
240         m_assembler.ARM_and(dataTempRegister, shift_amount, armImm);
241
242         m_assembler.lsl(dest, dest, dataTempRegister);
243     }
244
245     void lshift32(TrustedImm32 imm, RegisterID dest)
246     {
247         m_assembler.lsl(dest, dest, imm.m_value & 0x1f);
248     }
249
250     void mul32(RegisterID src, RegisterID dest)
251     {
252         m_assembler.smull(dest, dataTempRegister, dest, src);
253     }
254
255     void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
256     {
257         move(imm, dataTempRegister);
258         m_assembler.smull(dest, dataTempRegister, src, dataTempRegister);
259     }
260
261     void neg32(RegisterID srcDest)
262     {
263         m_assembler.neg(srcDest, srcDest);
264     }
265
266     void not32(RegisterID srcDest)
267     {
268         m_assembler.mvn(srcDest, srcDest);
269     }
270
271     void or32(RegisterID src, RegisterID dest)
272     {
273         m_assembler.orr(dest, dest, src);
274     }
275
276     void or32(TrustedImm32 imm, RegisterID dest)
277     {
278         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
279         if (armImm.isValid())
280             m_assembler.orr(dest, dest, armImm);
281         else {
282             move(imm, dataTempRegister);
283             m_assembler.orr(dest, dest, dataTempRegister);
284         }
285     }
286
287     void rshift32(RegisterID shift_amount, RegisterID dest)
288     {
289         // Clamp the shift to the range 0..31
290         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
291         ASSERT(armImm.isValid());
292         m_assembler.ARM_and(dataTempRegister, shift_amount, armImm);
293
294         m_assembler.asr(dest, dest, dataTempRegister);
295     }
296
297     void rshift32(TrustedImm32 imm, RegisterID dest)
298     {
299         rshift32(dest, imm, dest);
300     }
301
302     void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
303     {
304         m_assembler.asr(dest, src, imm.m_value & 0x1f);
305     }
306     
307     void urshift32(RegisterID shift_amount, RegisterID dest)
308     {
309         // Clamp the shift to the range 0..31
310         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
311         ASSERT(armImm.isValid());
312         m_assembler.ARM_and(dataTempRegister, shift_amount, armImm);
313         
314         m_assembler.lsr(dest, dest, dataTempRegister);
315     }
316     
317     void urshift32(TrustedImm32 imm, RegisterID dest)
318     {
319         m_assembler.lsr(dest, dest, imm.m_value & 0x1f);
320     }
321
322     void sub32(RegisterID src, RegisterID dest)
323     {
324         m_assembler.sub(dest, dest, src);
325     }
326
327     void sub32(TrustedImm32 imm, RegisterID dest)
328     {
329         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
330         if (armImm.isValid())
331             m_assembler.sub(dest, dest, armImm);
332         else {
333             move(imm, dataTempRegister);
334             m_assembler.sub(dest, dest, dataTempRegister);
335         }
336     }
337
338     void sub32(TrustedImm32 imm, Address address)
339     {
340         load32(address, dataTempRegister);
341
342         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
343         if (armImm.isValid())
344             m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
345         else {
346             // Hrrrm, since dataTempRegister holds the data loaded,
347             // use addressTempRegister to hold the immediate.
348             move(imm, addressTempRegister);
349             m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
350         }
351
352         store32(dataTempRegister, address);
353     }
354
355     void sub32(Address src, RegisterID dest)
356     {
357         load32(src, dataTempRegister);
358         sub32(dataTempRegister, dest);
359     }
360
361     void sub32(TrustedImm32 imm, AbsoluteAddress address)
362     {
363         load32(address.m_ptr, dataTempRegister);
364
365         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
366         if (armImm.isValid())
367             m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
368         else {
369             // Hrrrm, since dataTempRegister holds the data loaded,
370             // use addressTempRegister to hold the immediate.
371             move(imm, addressTempRegister);
372             m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
373         }
374
375         store32(dataTempRegister, address.m_ptr);
376     }
377
378     void xor32(RegisterID src, RegisterID dest)
379     {
380         m_assembler.eor(dest, dest, src);
381     }
382
383     void xor32(TrustedImm32 imm, RegisterID dest)
384     {
385         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
386         if (armImm.isValid())
387             m_assembler.eor(dest, dest, armImm);
388         else {
389             move(imm, dataTempRegister);
390             m_assembler.eor(dest, dest, dataTempRegister);
391         }
392     }
393     
394
395     // Memory access operations:
396     //
397     // Loads are of the form load(address, destination) and stores of the form
398     // store(source, address).  The source for a store may be an TrustedImm32.  Address
399     // operand objects to loads and store will be implicitly constructed if a
400     // register is passed.
401
402 private:
403     void load32(ArmAddress address, RegisterID dest)
404     {
405         if (address.type == ArmAddress::HasIndex)
406             m_assembler.ldr(dest, address.base, address.u.index, address.u.scale);
407         else if (address.u.offset >= 0) {
408             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
409             ASSERT(armImm.isValid());
410             m_assembler.ldr(dest, address.base, armImm);
411         } else {
412             ASSERT(address.u.offset >= -255);
413             m_assembler.ldr(dest, address.base, address.u.offset, true, false);
414         }
415     }
416
417     void load16(ArmAddress address, RegisterID dest)
418     {
419         if (address.type == ArmAddress::HasIndex)
420             m_assembler.ldrh(dest, address.base, address.u.index, address.u.scale);
421         else if (address.u.offset >= 0) {
422             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
423             ASSERT(armImm.isValid());
424             m_assembler.ldrh(dest, address.base, armImm);
425         } else {
426             ASSERT(address.u.offset >= -255);
427             m_assembler.ldrh(dest, address.base, address.u.offset, true, false);
428         }
429     }
430
431     void load8(ArmAddress address, RegisterID dest)
432     {
433         if (address.type == ArmAddress::HasIndex)
434             m_assembler.ldrb(dest, address.base, address.u.index, address.u.scale);
435         else if (address.u.offset >= 0) {
436             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
437             ASSERT(armImm.isValid());
438             m_assembler.ldrb(dest, address.base, armImm);
439         } else {
440             ASSERT(address.u.offset >= -255);
441             m_assembler.ldrb(dest, address.base, address.u.offset, true, false);
442         }
443     }
444
445     void store32(RegisterID src, ArmAddress address)
446     {
447         if (address.type == ArmAddress::HasIndex)
448             m_assembler.str(src, address.base, address.u.index, address.u.scale);
449         else if (address.u.offset >= 0) {
450             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
451             ASSERT(armImm.isValid());
452             m_assembler.str(src, address.base, armImm);
453         } else {
454             ASSERT(address.u.offset >= -255);
455             m_assembler.str(src, address.base, address.u.offset, true, false);
456         }
457     }
458
459 public:
460     void load32(ImplicitAddress address, RegisterID dest)
461     {
462         load32(setupArmAddress(address), dest);
463     }
464
465     void load32(BaseIndex address, RegisterID dest)
466     {
467         load32(setupArmAddress(address), dest);
468     }
469
470     void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
471     {
472         load32(setupArmAddress(address), dest);
473     }
474
475     void load32(const void* address, RegisterID dest)
476     {
477         move(TrustedImmPtr(address), addressTempRegister);
478         m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
479     }
480
481     void load8(ImplicitAddress address, RegisterID dest)
482     {
483         load8(setupArmAddress(address), dest);
484     }
485
486     void load8(BaseIndex address, RegisterID dest)
487     {
488         load8(setupArmAddress(address), dest);
489     }
490     
491     DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
492     {
493         DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
494         load32(ArmAddress(address.base, dataTempRegister), dest);
495         return label;
496     }
497     
498     DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
499     {
500         DataLabelCompact label(this);
501         ASSERT(address.offset >= 0);
502         ASSERT(address.offset <= MaximumCompactPtrAlignedAddressOffset);
503         ASSERT(ARMThumbImmediate::makeUInt12(address.offset).isUInt7());
504         m_assembler.ldrCompact(dest, address.base, ARMThumbImmediate::makeUInt12(address.offset));
505         return label;
506     }
507
508     void load16(BaseIndex address, RegisterID dest)
509     {
510         m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale);
511     }
512     
513     void load16(ImplicitAddress address, RegisterID dest)
514     {
515         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.offset);
516         if (armImm.isValid())
517             m_assembler.ldrh(dest, address.base, armImm);
518         else {
519             move(TrustedImm32(address.offset), dataTempRegister);
520             m_assembler.ldrh(dest, address.base, dataTempRegister);
521         }
522     }
523
524     DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
525     {
526         DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
527         store32(src, ArmAddress(address.base, dataTempRegister));
528         return label;
529     }
530
531     void store32(RegisterID src, ImplicitAddress address)
532     {
533         store32(src, setupArmAddress(address));
534     }
535
536     void store32(RegisterID src, BaseIndex address)
537     {
538         store32(src, setupArmAddress(address));
539     }
540
541     void store32(TrustedImm32 imm, ImplicitAddress address)
542     {
543         move(imm, dataTempRegister);
544         store32(dataTempRegister, setupArmAddress(address));
545     }
546
547     void store32(RegisterID src, const void* address)
548     {
549         move(TrustedImmPtr(address), addressTempRegister);
550         m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
551     }
552
553     void store32(TrustedImm32 imm, const void* address)
554     {
555         move(imm, dataTempRegister);
556         store32(dataTempRegister, address);
557     }
558
559
560     // Floating-point operations:
561
562     bool supportsFloatingPoint() const { return true; }
563     // On x86(_64) the MacroAssembler provides an interface to truncate a double to an integer.
564     // If a value is not representable as an integer, and possibly for some values that are,
565     // (on x86 INT_MIN, since this is indistinguishable from results for out-of-range/NaN input)
566     // a branch will  be taken.  It is not clear whether this interface will be well suited to
567     // other platforms.  On ARMv7 the hardware truncation operation produces multiple possible
568     // failure values (saturates to INT_MIN & INT_MAX, NaN reulsts in a value of 0).  This is a
569     // temporary solution while we work out what this interface should be.  Either we need to
570     // decide to make this interface work on all platforms, rework the interface to make it more
571     // generic, or decide that the MacroAssembler cannot practically be used to abstracted these
572     // operations, and make clients go directly to the m_assembler to plant truncation instructions.
573     // In short, FIXME:.
574     bool supportsFloatingPointTruncate() const { return false; }
575
576     bool supportsFloatingPointSqrt() const
577     {
578         return false;
579     }
580     bool supportsDoubleBitops() const { return false; }
581
582     void loadDouble(ImplicitAddress address, FPRegisterID dest)
583     {
584         RegisterID base = address.base;
585         int32_t offset = address.offset;
586
587         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
588         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
589             add32(TrustedImm32(offset), base, addressTempRegister);
590             base = addressTempRegister;
591             offset = 0;
592         }
593         
594         m_assembler.vldr(dest, base, offset);
595     }
596
597     void loadDouble(const void* address, FPRegisterID dest)
598     {
599         move(TrustedImmPtr(address), addressTempRegister);
600         m_assembler.vldr(dest, addressTempRegister, 0);
601     }
602
603     void storeDouble(FPRegisterID src, ImplicitAddress address)
604     {
605         RegisterID base = address.base;
606         int32_t offset = address.offset;
607
608         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
609         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
610             add32(TrustedImm32(offset), base, addressTempRegister);
611             base = addressTempRegister;
612             offset = 0;
613         }
614         
615         m_assembler.vstr(src, base, offset);
616     }
617
618     void addDouble(FPRegisterID src, FPRegisterID dest)
619     {
620         m_assembler.vadd_F64(dest, dest, src);
621     }
622
623     void addDouble(Address src, FPRegisterID dest)
624     {
625         loadDouble(src, fpTempRegister);
626         addDouble(fpTempRegister, dest);
627     }
628
629     void divDouble(FPRegisterID src, FPRegisterID dest)
630     {
631         m_assembler.vdiv_F64(dest, dest, src);
632     }
633
634     void subDouble(FPRegisterID src, FPRegisterID dest)
635     {
636         m_assembler.vsub_F64(dest, dest, src);
637     }
638
639     void subDouble(Address src, FPRegisterID dest)
640     {
641         loadDouble(src, fpTempRegister);
642         subDouble(fpTempRegister, dest);
643     }
644
645     void mulDouble(FPRegisterID src, FPRegisterID dest)
646     {
647         m_assembler.vmul_F64(dest, dest, src);
648     }
649
650     void mulDouble(Address src, FPRegisterID dest)
651     {
652         loadDouble(src, fpTempRegister);
653         mulDouble(fpTempRegister, dest);
654     }
655
656     void sqrtDouble(FPRegisterID, FPRegisterID)
657     {
658         ASSERT_NOT_REACHED();
659     }
660     
661     void andnotDouble(FPRegisterID, FPRegisterID)
662     {
663         ASSERT_NOT_REACHED();
664     }
665
666     void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
667     {
668         m_assembler.vmov(fpTempRegisterAsSingle(), src);
669         m_assembler.vcvt_F64_S32(dest, fpTempRegisterAsSingle());
670     }
671
672     void convertInt32ToDouble(Address address, FPRegisterID dest)
673     {
674         // Fixme: load directly into the fpr!
675         load32(address, dataTempRegister);
676         m_assembler.vmov(fpTempRegisterAsSingle(), dataTempRegister);
677         m_assembler.vcvt_F64_S32(dest, fpTempRegisterAsSingle());
678     }
679
680     void convertInt32ToDouble(AbsoluteAddress address, FPRegisterID dest)
681     {
682         // Fixme: load directly into the fpr!
683         load32(address.m_ptr, dataTempRegister);
684         m_assembler.vmov(fpTempRegisterAsSingle(), dataTempRegister);
685         m_assembler.vcvt_F64_S32(dest, fpTempRegisterAsSingle());
686     }
687
688     Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
689     {
690         m_assembler.vcmp_F64(left, right);
691         m_assembler.vmrs();
692
693         if (cond == DoubleNotEqual) {
694             // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump.
695             Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
696             Jump result = makeBranch(ARMv7Assembler::ConditionNE);
697             unordered.link(this);
698             return result;
699         }
700         if (cond == DoubleEqualOrUnordered) {
701             Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
702             Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
703             unordered.link(this);
704             // We get here if either unordered or equal.
705             Jump result = jump();
706             notEqual.link(this);
707             return result;
708         }
709         return makeBranch(cond);
710     }
711
712     Jump branchTruncateDoubleToInt32(FPRegisterID, RegisterID)
713     {
714         ASSERT_NOT_REACHED();
715         return jump();
716     }
717
718     // Convert 'src' to an integer, and places the resulting 'dest'.
719     // If the result is not representable as a 32 bit value, branch.
720     // May also branch for some values that are representable in 32 bits
721     // (specifically, in this case, 0).
722     void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID)
723     {
724         m_assembler.vcvtr_S32_F64(fpTempRegisterAsSingle(), src);
725         m_assembler.vmov(dest, fpTempRegisterAsSingle());
726
727         // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
728         m_assembler.vcvt_F64_S32(fpTempRegister, fpTempRegisterAsSingle());
729         failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, fpTempRegister));
730
731         // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
732         failureCases.append(branchTest32(Zero, dest));
733     }
734
735     Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID)
736     {
737         m_assembler.vcmpz_F64(reg);
738         m_assembler.vmrs();
739         Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
740         Jump result = makeBranch(ARMv7Assembler::ConditionNE);
741         unordered.link(this);
742         return result;
743     }
744
745     Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID)
746     {
747         m_assembler.vcmpz_F64(reg);
748         m_assembler.vmrs();
749         Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
750         Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
751         unordered.link(this);
752         // We get here if either unordered or equal.
753         Jump result = jump();
754         notEqual.link(this);
755         return result;
756     }
757
758     // Stack manipulation operations:
759     //
760     // The ABI is assumed to provide a stack abstraction to memory,
761     // containing machine word sized units of data.  Push and pop
762     // operations add and remove a single register sized unit of data
763     // to or from the stack.  Peek and poke operations read or write
764     // values on the stack, without moving the current stack position.
765     
766     void pop(RegisterID dest)
767     {
768         // store postindexed with writeback
769         m_assembler.ldr(dest, ARMRegisters::sp, sizeof(void*), false, true);
770     }
771
772     void push(RegisterID src)
773     {
774         // store preindexed with writeback
775         m_assembler.str(src, ARMRegisters::sp, -sizeof(void*), true, true);
776     }
777
778     void push(Address address)
779     {
780         load32(address, dataTempRegister);
781         push(dataTempRegister);
782     }
783
784     void push(TrustedImm32 imm)
785     {
786         move(imm, dataTempRegister);
787         push(dataTempRegister);
788     }
789
790     // Register move operations:
791     //
792     // Move values in registers.
793
794     void move(TrustedImm32 imm, RegisterID dest)
795     {
796         uint32_t value = imm.m_value;
797
798         if (imm.m_isPointer)
799             moveFixedWidthEncoding(imm, dest);
800         else {
801             ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(value);
802
803             if (armImm.isValid())
804                 m_assembler.mov(dest, armImm);
805             else if ((armImm = ARMThumbImmediate::makeEncodedImm(~value)).isValid())
806                 m_assembler.mvn(dest, armImm);
807             else {
808                 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(value));
809                 if (value & 0xffff0000)
810                     m_assembler.movt(dest, ARMThumbImmediate::makeUInt16(value >> 16));
811             }
812         }
813     }
814
815     void move(RegisterID src, RegisterID dest)
816     {
817         m_assembler.mov(dest, src);
818     }
819
820     void move(TrustedImmPtr imm, RegisterID dest)
821     {
822         move(TrustedImm32(imm), dest);
823     }
824
825     void swap(RegisterID reg1, RegisterID reg2)
826     {
827         move(reg1, dataTempRegister);
828         move(reg2, reg1);
829         move(dataTempRegister, reg2);
830     }
831
832     void signExtend32ToPtr(RegisterID src, RegisterID dest)
833     {
834         if (src != dest)
835             move(src, dest);
836     }
837
838     void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
839     {
840         if (src != dest)
841             move(src, dest);
842     }
843
844     void nop()
845     {
846         m_assembler.nop();
847     }
848
849     // Forwards / external control flow operations:
850     //
851     // This set of jump and conditional branch operations return a Jump
852     // object which may linked at a later point, allow forwards jump,
853     // or jumps that will require external linkage (after the code has been
854     // relocated).
855     //
856     // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
857     // respecitvely, for unsigned comparisons the names b, a, be, and ae are
858     // used (representing the names 'below' and 'above').
859     //
860     // Operands to the comparision are provided in the expected order, e.g.
861     // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
862     // treated as a signed 32bit value, is less than or equal to 5.
863     //
864     // jz and jnz test whether the first operand is equal to zero, and take
865     // an optional second operand of a mask under which to perform the test.
866 private:
867
868     // Should we be using TEQ for equal/not-equal?
869     void compare32(RegisterID left, TrustedImm32 right)
870     {
871         int32_t imm = right.m_value;
872         if (!imm)
873             m_assembler.tst(left, left);
874         else {
875             ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
876             if (armImm.isValid())
877                 m_assembler.cmp(left, armImm);
878             else if ((armImm = ARMThumbImmediate::makeEncodedImm(-imm)).isValid())
879                 m_assembler.cmn(left, armImm);
880             else {
881                 move(TrustedImm32(imm), dataTempRegister);
882                 m_assembler.cmp(left, dataTempRegister);
883             }
884         }
885     }
886
887     void test32(RegisterID reg, TrustedImm32 mask)
888     {
889         int32_t imm = mask.m_value;
890
891         if (imm == -1)
892             m_assembler.tst(reg, reg);
893         else {
894             ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
895             if (armImm.isValid())
896                 m_assembler.tst(reg, armImm);
897             else {
898                 move(mask, dataTempRegister);
899                 m_assembler.tst(reg, dataTempRegister);
900             }
901         }
902     }
903
904 public:
905     Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
906     {
907         m_assembler.cmp(left, right);
908         return Jump(makeBranch(cond));
909     }
910
911     Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
912     {
913         compare32(left, right);
914         return Jump(makeBranch(cond));
915     }
916
917     Jump branch32(RelationalCondition cond, RegisterID left, Address right)
918     {
919         load32(right, dataTempRegister);
920         return branch32(cond, left, dataTempRegister);
921     }
922
923     Jump branch32(RelationalCondition cond, Address left, RegisterID right)
924     {
925         load32(left, dataTempRegister);
926         return branch32(cond, dataTempRegister, right);
927     }
928
929     Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
930     {
931         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
932         load32(left, addressTempRegister);
933         return branch32(cond, addressTempRegister, right);
934     }
935
936     Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
937     {
938         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
939         load32(left, addressTempRegister);
940         return branch32(cond, addressTempRegister, right);
941     }
942
943     Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
944     {
945         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
946         load32WithUnalignedHalfWords(left, addressTempRegister);
947         return branch32(cond, addressTempRegister, right);
948     }
949
950     Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
951     {
952         load32(left.m_ptr, dataTempRegister);
953         return branch32(cond, dataTempRegister, right);
954     }
955
956     Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
957     {
958         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
959         load32(left.m_ptr, addressTempRegister);
960         return branch32(cond, addressTempRegister, right);
961     }
962
963     Jump branch16(RelationalCondition cond, BaseIndex left, RegisterID right)
964     {
965         load16(left, dataTempRegister);
966         m_assembler.lsl(addressTempRegister, right, 16);
967         m_assembler.lsl(dataTempRegister, dataTempRegister, 16);
968         return branch32(cond, dataTempRegister, addressTempRegister);
969     }
970
971     Jump branch16(RelationalCondition cond, RegisterID left, TrustedImm32 right)
972     {
973         ASSERT(!(0xffff0000 & right.m_value));
974         // Extract the lower 16 bits into a temp for comparison
975         m_assembler.ubfx(dataTempRegister, left, 0, 16);
976         return branch32(cond, dataTempRegister, right);
977     }
978     
979     Jump branch16(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
980     {
981         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
982         load16(left, addressTempRegister);
983         m_assembler.lsl(addressTempRegister, addressTempRegister, 16);
984         return branch32(cond, addressTempRegister, TrustedImm32(right.m_value << 16));
985     }
986
987     Jump branch8(RelationalCondition cond, RegisterID left, TrustedImm32 right)
988     {
989         compare32(left, right);
990         return Jump(makeBranch(cond));
991     }
992
993     Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
994     {
995         ASSERT(!(0xffffff00 & right.m_value));
996         // use addressTempRegister incase the branch8 we call uses dataTempRegister. :-/
997         load8(left, addressTempRegister);
998         return branch8(cond, addressTempRegister, right);
999     }
1000
1001     Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1002     {
1003         ASSERT(!(0xffffff00 & right.m_value));
1004         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1005         load8(left, addressTempRegister);
1006         return branch32(cond, addressTempRegister, right);
1007     }
1008     
1009     Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
1010     {
1011         m_assembler.tst(reg, mask);
1012         return Jump(makeBranch(cond));
1013     }
1014
1015     Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1016     {
1017         test32(reg, mask);
1018         return Jump(makeBranch(cond));
1019     }
1020
1021     Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1022     {
1023         // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1024         load32(address, addressTempRegister);
1025         return branchTest32(cond, addressTempRegister, mask);
1026     }
1027
1028     Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1029     {
1030         // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1031         load32(address, addressTempRegister);
1032         return branchTest32(cond, addressTempRegister, mask);
1033     }
1034
1035     Jump branchTest8(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1036     {
1037         test32(reg, mask);
1038         return Jump(makeBranch(cond));
1039     }
1040
1041     Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1042     {
1043         // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1044         load8(address, addressTempRegister);
1045         return branchTest8(cond, addressTempRegister, mask);
1046     }
1047
1048     void jump(RegisterID target)
1049     {
1050         m_assembler.bx(target);
1051     }
1052
1053     // Address is a memory location containing the address to jump to
1054     void jump(Address address)
1055     {
1056         load32(address, dataTempRegister);
1057         m_assembler.bx(dataTempRegister);
1058     }
1059
1060
1061     // Arithmetic control flow operations:
1062     //
1063     // This set of conditional branch operations branch based
1064     // on the result of an arithmetic operation.  The operation
1065     // is performed as normal, storing the result.
1066     //
1067     // * jz operations branch if the result is zero.
1068     // * jo operations branch if the (signed) arithmetic
1069     //   operation caused an overflow to occur.
1070     
1071     Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
1072     {
1073         m_assembler.add_S(dest, dest, src);
1074         return Jump(makeBranch(cond));
1075     }
1076
1077     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1078     {
1079         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1080         if (armImm.isValid())
1081             m_assembler.add_S(dest, dest, armImm);
1082         else {
1083             move(imm, dataTempRegister);
1084             m_assembler.add_S(dest, dest, dataTempRegister);
1085         }
1086         return Jump(makeBranch(cond));
1087     }
1088
1089     Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
1090     {
1091         m_assembler.smull(dest, dataTempRegister, src1, src2);
1092
1093         if (cond == Overflow) {
1094             m_assembler.asr(addressTempRegister, dest, 31);
1095             return branch32(NotEqual, addressTempRegister, dataTempRegister);
1096         }
1097
1098         return branchTest32(cond, dest);
1099     }
1100
1101     Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
1102     {
1103         return branchMul32(cond, src, dest, dest);
1104     }
1105
1106     Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
1107     {
1108         move(imm, dataTempRegister);
1109         return branchMul32(cond, dataTempRegister, src, dest);
1110     }
1111
1112     Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
1113     {
1114         m_assembler.orr_S(dest, dest, src);
1115         return Jump(makeBranch(cond));
1116     }
1117
1118     Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
1119     {
1120         m_assembler.sub_S(dest, dest, src);
1121         return Jump(makeBranch(cond));
1122     }
1123
1124     Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1125     {
1126         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1127         if (armImm.isValid())
1128             m_assembler.sub_S(dest, dest, armImm);
1129         else {
1130             move(imm, dataTempRegister);
1131             m_assembler.sub_S(dest, dest, dataTempRegister);
1132         }
1133         return Jump(makeBranch(cond));
1134     }
1135     
1136     void relativeTableJump(RegisterID index, int scale)
1137     {
1138         ASSERT(scale >= 0 && scale <= 31);
1139
1140         // dataTempRegister will point after the jump if index register contains zero
1141         move(ARMRegisters::pc, dataTempRegister);
1142         m_assembler.add(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(9));
1143
1144         ShiftTypeAndAmount shift(SRType_LSL, scale);
1145         m_assembler.add(dataTempRegister, dataTempRegister, index, shift);
1146         jump(dataTempRegister);
1147     }
1148
1149     // Miscellaneous operations:
1150
1151     void breakpoint()
1152     {
1153         m_assembler.bkpt(0);
1154     }
1155
1156     ALWAYS_INLINE Call nearCall()
1157     {
1158         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1159         return Call(m_assembler.blx(dataTempRegister), Call::LinkableNear);
1160     }
1161
1162     ALWAYS_INLINE Call call()
1163     {
1164         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1165         return Call(m_assembler.blx(dataTempRegister), Call::Linkable);
1166     }
1167
1168     ALWAYS_INLINE Call call(RegisterID target)
1169     {
1170         return Call(m_assembler.blx(target), Call::None);
1171     }
1172
1173     ALWAYS_INLINE Call call(Address address)
1174     {
1175         load32(address, dataTempRegister);
1176         return Call(m_assembler.blx(dataTempRegister), Call::None);
1177     }
1178
1179     ALWAYS_INLINE void ret()
1180     {
1181         m_assembler.bx(linkRegister);
1182     }
1183
1184     void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
1185     {
1186         m_assembler.cmp(left, right);
1187         m_assembler.it(armV7Condition(cond), false);
1188         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1189         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1190     }
1191
1192     void compare32(RelationalCondition cond, Address left, RegisterID right, RegisterID dest)
1193     {
1194         load32(left, dataTempRegister);
1195         compare32(cond, dataTempRegister, right, dest);
1196     }
1197
1198     void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1199     {
1200         compare32(left, right);
1201         m_assembler.it(armV7Condition(cond), false);
1202         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1203         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1204     }
1205
1206     // FIXME:
1207     // The mask should be optional... paerhaps the argument order should be
1208     // dest-src, operations always have a dest? ... possibly not true, considering
1209     // asm ops like test, or pseudo ops like pop().
1210     void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1211     {
1212         load32(address, dataTempRegister);
1213         test32(dataTempRegister, mask);
1214         m_assembler.it(armV7Condition(cond), false);
1215         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1216         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1217     }
1218
1219     void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1220     {
1221         load8(address, dataTempRegister);
1222         test32(dataTempRegister, mask);
1223         m_assembler.it(armV7Condition(cond), false);
1224         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1225         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1226     }
1227
1228     ALWAYS_INLINE DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dst)
1229     {
1230         moveFixedWidthEncoding(imm, dst);
1231         return DataLabel32(this);
1232     }
1233
1234     ALWAYS_INLINE DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst)
1235     {
1236         moveFixedWidthEncoding(TrustedImm32(imm), dst);
1237         return DataLabelPtr(this);
1238     }
1239
1240     ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1241     {
1242         dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1243         return branch32(cond, left, dataTempRegister);
1244     }
1245
1246     ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1247     {
1248         load32(left, addressTempRegister);
1249         dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1250         return branch32(cond, addressTempRegister, dataTempRegister);
1251     }
1252
1253     ALWAYS_INLINE DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
1254     {
1255         DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
1256         store32(dataTempRegister, address);
1257         return label;
1258     }
1259     ALWAYS_INLINE DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(TrustedImmPtr(0), address); }
1260
1261
1262     ALWAYS_INLINE Call tailRecursiveCall()
1263     {
1264         // Like a normal call, but don't link.
1265         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1266         return Call(m_assembler.bx(dataTempRegister), Call::Linkable);
1267     }
1268
1269     ALWAYS_INLINE Call makeTailRecursiveCall(Jump oldJump)
1270     {
1271         oldJump.link(this);
1272         return tailRecursiveCall();
1273     }
1274
1275     
1276     int executableOffsetFor(int location)
1277     {
1278         return m_assembler.executableOffsetFor(location);
1279     }
1280
1281 protected:
1282     bool inUninterruptedSequence()
1283     {
1284         return m_inUninterruptedSequence;
1285     }
1286
1287     ALWAYS_INLINE Jump jump()
1288     {
1289         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1290         return Jump(m_assembler.bx(dataTempRegister), inUninterruptedSequence() ? ARMv7Assembler::JumpNoConditionFixedSize : ARMv7Assembler::JumpNoCondition);
1291     }
1292
1293     ALWAYS_INLINE Jump makeBranch(ARMv7Assembler::Condition cond)
1294     {
1295         m_assembler.it(cond, true, true);
1296         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1297         return Jump(m_assembler.bx(dataTempRegister), inUninterruptedSequence() ? ARMv7Assembler::JumpConditionFixedSize : ARMv7Assembler::JumpCondition, cond);
1298     }
1299     ALWAYS_INLINE Jump makeBranch(RelationalCondition cond) { return makeBranch(armV7Condition(cond)); }
1300     ALWAYS_INLINE Jump makeBranch(ResultCondition cond) { return makeBranch(armV7Condition(cond)); }
1301     ALWAYS_INLINE Jump makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); }
1302
1303     ArmAddress setupArmAddress(BaseIndex address)
1304     {
1305         if (address.offset) {
1306             ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1307             if (imm.isValid())
1308                 m_assembler.add(addressTempRegister, address.base, imm);
1309             else {
1310                 move(TrustedImm32(address.offset), addressTempRegister);
1311                 m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1312             }
1313
1314             return ArmAddress(addressTempRegister, address.index, address.scale);
1315         } else
1316             return ArmAddress(address.base, address.index, address.scale);
1317     }
1318
1319     ArmAddress setupArmAddress(Address address)
1320     {
1321         if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1322             return ArmAddress(address.base, address.offset);
1323
1324         move(TrustedImm32(address.offset), addressTempRegister);
1325         return ArmAddress(address.base, addressTempRegister);
1326     }
1327
1328     ArmAddress setupArmAddress(ImplicitAddress address)
1329     {
1330         if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1331             return ArmAddress(address.base, address.offset);
1332
1333         move(TrustedImm32(address.offset), addressTempRegister);
1334         return ArmAddress(address.base, addressTempRegister);
1335     }
1336
1337     RegisterID makeBaseIndexBase(BaseIndex address)
1338     {
1339         if (!address.offset)
1340             return address.base;
1341
1342         ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1343         if (imm.isValid())
1344             m_assembler.add(addressTempRegister, address.base, imm);
1345         else {
1346             move(TrustedImm32(address.offset), addressTempRegister);
1347             m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1348         }
1349
1350         return addressTempRegister;
1351     }
1352
1353     void moveFixedWidthEncoding(TrustedImm32 imm, RegisterID dst)
1354     {
1355         uint32_t value = imm.m_value;
1356         m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff));
1357         m_assembler.movt(dst, ARMThumbImmediate::makeUInt16(value >> 16));
1358     }
1359
1360     ARMv7Assembler::Condition armV7Condition(RelationalCondition cond)
1361     {
1362         return static_cast<ARMv7Assembler::Condition>(cond);
1363     }
1364
1365     ARMv7Assembler::Condition armV7Condition(ResultCondition cond)
1366     {
1367         return static_cast<ARMv7Assembler::Condition>(cond);
1368     }
1369
1370     ARMv7Assembler::Condition armV7Condition(DoubleCondition cond)
1371     {
1372         return static_cast<ARMv7Assembler::Condition>(cond);
1373     }
1374
1375 private:
1376     friend class LinkBuffer;
1377     friend class RepatchBuffer;
1378
1379     static void linkCall(void* code, Call call, FunctionPtr function)
1380     {
1381         ARMv7Assembler::linkCall(code, call.m_label, function.value());
1382     }
1383
1384     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
1385     {
1386         ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1387     }
1388
1389     static void repatchCall(CodeLocationCall call, FunctionPtr destination)
1390     {
1391         ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1392     }
1393     
1394     bool m_inUninterruptedSequence;
1395 };
1396
1397 } // namespace JSC
1398
1399 #endif // ENABLE(ASSEMBLER)
1400
1401 #endif // MacroAssemblerARMv7_h