tizen beta release
[profile/ivi/webkit-efl.git] / Source / JavaScriptCore / assembler / MacroAssemblerARMv7.h
1 /*
2  * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2010 University of Szeged
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
25  */
26
27 #ifndef MacroAssemblerARMv7_h
28 #define MacroAssemblerARMv7_h
29
30 #if ENABLE(ASSEMBLER)
31
32 #include "ARMv7Assembler.h"
33 #include "AbstractMacroAssembler.h"
34
35 namespace JSC {
36
37 class MacroAssemblerARMv7 : public AbstractMacroAssembler<ARMv7Assembler> {
38     // FIXME: switch dataTempRegister & addressTempRegister, or possibly use r7?
39     //        - dTR is likely used more than aTR, and we'll get better instruction
40     //        encoding if it's in the low 8 registers.
41     static const RegisterID dataTempRegister = ARMRegisters::ip;
42     static const RegisterID addressTempRegister = ARMRegisters::r3;
43
44     static const ARMRegisters::FPDoubleRegisterID fpTempRegister = ARMRegisters::d7;
45     inline ARMRegisters::FPSingleRegisterID fpTempRegisterAsSingle() { return ARMRegisters::asSingle(fpTempRegister); }
46
47 public:
48     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 add64(TrustedImm32 imm, AbsoluteAddress address)
215     {
216         move(TrustedImmPtr(address.m_ptr), addressTempRegister);
217
218         m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(0));
219         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
220         if (armImm.isValid())
221             m_assembler.add_S(dataTempRegister, dataTempRegister, armImm);
222         else {
223             move(imm, addressTempRegister);
224             m_assembler.add_S(dataTempRegister, dataTempRegister, addressTempRegister);
225             move(TrustedImmPtr(address.m_ptr), addressTempRegister);
226         }
227         m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(0));
228
229         m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(4));
230         m_assembler.adc(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(imm.m_value >> 31));
231         m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(4));
232     }
233
234     void and32(RegisterID op1, RegisterID op2, RegisterID dest)
235     {
236         m_assembler.ARM_and(dest, op1, op2);
237     }
238
239     void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
240     {
241         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
242         if (armImm.isValid())
243             m_assembler.ARM_and(dest, src, armImm);
244         else {
245             move(imm, dataTempRegister);
246             m_assembler.ARM_and(dest, src, dataTempRegister);
247         }
248     }
249
250     void and32(RegisterID src, RegisterID dest)
251     {
252         and32(dest, src, dest);
253     }
254
255     void and32(TrustedImm32 imm, RegisterID dest)
256     {
257         and32(imm, dest, dest);
258     }
259
260     void countLeadingZeros32(RegisterID src, RegisterID dest)
261     {
262         m_assembler.clz(dest, src);
263     }
264
265     void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
266     {
267         // Clamp the shift to the range 0..31
268         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
269         ASSERT(armImm.isValid());
270         m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
271
272         m_assembler.lsl(dest, src, dataTempRegister);
273     }
274
275     void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
276     {
277         m_assembler.lsl(dest, src, imm.m_value & 0x1f);
278     }
279
280     void lshift32(RegisterID shiftAmount, RegisterID dest)
281     {
282         lshift32(dest, shiftAmount, dest);
283     }
284
285     void lshift32(TrustedImm32 imm, RegisterID dest)
286     {
287         lshift32(dest, imm, dest);
288     }
289
290     void mul32(RegisterID src, RegisterID dest)
291     {
292         m_assembler.smull(dest, dataTempRegister, dest, src);
293     }
294
295     void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
296     {
297         move(imm, dataTempRegister);
298         m_assembler.smull(dest, dataTempRegister, src, dataTempRegister);
299     }
300
301     void neg32(RegisterID srcDest)
302     {
303         m_assembler.neg(srcDest, srcDest);
304     }
305
306     void not32(RegisterID srcDest)
307     {
308         m_assembler.mvn(srcDest, srcDest);
309     }
310
311     void or32(RegisterID src, RegisterID dest)
312     {
313         m_assembler.orr(dest, dest, src);
314     }
315
316     void or32(TrustedImm32 imm, RegisterID dest)
317     {
318         or32(imm, dest, dest);
319     }
320
321     void or32(RegisterID op1, RegisterID op2, RegisterID dest)
322     {
323         m_assembler.orr(dest, op1, op2);
324     }
325
326     void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
327     {
328         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
329         if (armImm.isValid())
330             m_assembler.orr(dest, src, armImm);
331         else {
332             move(imm, dataTempRegister);
333             m_assembler.orr(dest, src, dataTempRegister);
334         }
335     }
336
337     void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
338     {
339         // Clamp the shift to the range 0..31
340         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
341         ASSERT(armImm.isValid());
342         m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
343
344         m_assembler.asr(dest, src, dataTempRegister);
345     }
346
347     void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
348     {
349         m_assembler.asr(dest, src, imm.m_value & 0x1f);
350     }
351
352     void rshift32(RegisterID shiftAmount, RegisterID dest)
353     {
354         rshift32(dest, shiftAmount, dest);
355     }
356     
357     void rshift32(TrustedImm32 imm, RegisterID dest)
358     {
359         rshift32(dest, imm, dest);
360     }
361
362     void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
363     {
364         // Clamp the shift to the range 0..31
365         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
366         ASSERT(armImm.isValid());
367         m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
368         
369         m_assembler.lsr(dest, src, dataTempRegister);
370     }
371     
372     void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
373     {
374         m_assembler.lsr(dest, src, imm.m_value & 0x1f);
375     }
376
377     void urshift32(RegisterID shiftAmount, RegisterID dest)
378     {
379         urshift32(dest, shiftAmount, dest);
380     }
381     
382     void urshift32(TrustedImm32 imm, RegisterID dest)
383     {
384         urshift32(dest, imm, dest);
385     }
386
387     void sub32(RegisterID src, RegisterID dest)
388     {
389         m_assembler.sub(dest, dest, src);
390     }
391
392     void sub32(TrustedImm32 imm, RegisterID dest)
393     {
394         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
395         if (armImm.isValid())
396             m_assembler.sub(dest, dest, armImm);
397         else {
398             move(imm, dataTempRegister);
399             m_assembler.sub(dest, dest, dataTempRegister);
400         }
401     }
402
403     void sub32(TrustedImm32 imm, Address address)
404     {
405         load32(address, dataTempRegister);
406
407         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
408         if (armImm.isValid())
409             m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
410         else {
411             // Hrrrm, since dataTempRegister holds the data loaded,
412             // use addressTempRegister to hold the immediate.
413             move(imm, addressTempRegister);
414             m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
415         }
416
417         store32(dataTempRegister, address);
418     }
419
420     void sub32(Address src, RegisterID dest)
421     {
422         load32(src, dataTempRegister);
423         sub32(dataTempRegister, dest);
424     }
425
426     void sub32(TrustedImm32 imm, AbsoluteAddress address)
427     {
428         load32(address.m_ptr, dataTempRegister);
429
430         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
431         if (armImm.isValid())
432             m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
433         else {
434             // Hrrrm, since dataTempRegister holds the data loaded,
435             // use addressTempRegister to hold the immediate.
436             move(imm, addressTempRegister);
437             m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
438         }
439
440         store32(dataTempRegister, address.m_ptr);
441     }
442
443     void xor32(RegisterID op1, RegisterID op2, RegisterID dest)
444     {
445         m_assembler.eor(dest, op1, op2);
446     }
447
448     void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
449     {
450         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
451         if (armImm.isValid())
452             m_assembler.eor(dest, src, armImm);
453         else {
454             move(imm, dataTempRegister);
455             m_assembler.eor(dest, src, dataTempRegister);
456         }
457     }
458
459     void xor32(RegisterID src, RegisterID dest)
460     {
461         xor32(dest, src, dest);
462     }
463
464     void xor32(TrustedImm32 imm, RegisterID dest)
465     {
466         xor32(imm, dest, dest);
467     }
468     
469
470     // Memory access operations:
471     //
472     // Loads are of the form load(address, destination) and stores of the form
473     // store(source, address).  The source for a store may be an TrustedImm32.  Address
474     // operand objects to loads and store will be implicitly constructed if a
475     // register is passed.
476
477 private:
478     void load32(ArmAddress address, RegisterID dest)
479     {
480         if (address.type == ArmAddress::HasIndex)
481             m_assembler.ldr(dest, address.base, address.u.index, address.u.scale);
482         else if (address.u.offset >= 0) {
483             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
484             ASSERT(armImm.isValid());
485             m_assembler.ldr(dest, address.base, armImm);
486         } else {
487             ASSERT(address.u.offset >= -255);
488             m_assembler.ldr(dest, address.base, address.u.offset, true, false);
489         }
490     }
491
492     void load16(ArmAddress address, RegisterID dest)
493     {
494         if (address.type == ArmAddress::HasIndex)
495             m_assembler.ldrh(dest, address.base, address.u.index, address.u.scale);
496         else if (address.u.offset >= 0) {
497             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
498             ASSERT(armImm.isValid());
499             m_assembler.ldrh(dest, address.base, armImm);
500         } else {
501             ASSERT(address.u.offset >= -255);
502             m_assembler.ldrh(dest, address.base, address.u.offset, true, false);
503         }
504     }
505
506     void load8(ArmAddress address, RegisterID dest)
507     {
508         if (address.type == ArmAddress::HasIndex)
509             m_assembler.ldrb(dest, address.base, address.u.index, address.u.scale);
510         else if (address.u.offset >= 0) {
511             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
512             ASSERT(armImm.isValid());
513             m_assembler.ldrb(dest, address.base, armImm);
514         } else {
515             ASSERT(address.u.offset >= -255);
516             m_assembler.ldrb(dest, address.base, address.u.offset, true, false);
517         }
518     }
519
520     void store32(RegisterID src, ArmAddress address)
521     {
522         if (address.type == ArmAddress::HasIndex)
523             m_assembler.str(src, address.base, address.u.index, address.u.scale);
524         else if (address.u.offset >= 0) {
525             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
526             ASSERT(armImm.isValid());
527             m_assembler.str(src, address.base, armImm);
528         } else {
529             ASSERT(address.u.offset >= -255);
530             m_assembler.str(src, address.base, address.u.offset, true, false);
531         }
532     }
533
534     void store8(RegisterID src, ArmAddress address)
535     {
536         if (address.type == ArmAddress::HasIndex)
537             m_assembler.strb(src, address.base, address.u.index, address.u.scale);
538         else if (address.u.offset >= 0) {
539             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
540             ASSERT(armImm.isValid());
541             m_assembler.strb(src, address.base, armImm);
542         } else {
543             ASSERT(address.u.offset >= -255);
544             m_assembler.strb(src, address.base, address.u.offset, true, false);
545         }
546     }
547
548 public:
549     void load32(ImplicitAddress address, RegisterID dest)
550     {
551         load32(setupArmAddress(address), dest);
552     }
553
554     void load32(BaseIndex address, RegisterID dest)
555     {
556         load32(setupArmAddress(address), dest);
557     }
558
559     void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
560     {
561         load32(setupArmAddress(address), dest);
562     }
563
564     void load32(const void* address, RegisterID dest)
565     {
566         move(TrustedImmPtr(address), addressTempRegister);
567         m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
568     }
569
570     void load8(ImplicitAddress address, RegisterID dest)
571     {
572         load8(setupArmAddress(address), dest);
573     }
574
575     void load8(BaseIndex address, RegisterID dest)
576     {
577         load8(setupArmAddress(address), dest);
578     }
579     
580     DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
581     {
582         DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
583         load32(ArmAddress(address.base, dataTempRegister), dest);
584         return label;
585     }
586     
587     // FIXME: we should be able to plant a compact load relative to/from any base/dest register.
588     DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
589     {
590         RegisterID base = address.base;
591         
592         if (base >= ARMRegisters::r8) {
593             move(base, addressTempRegister);
594             base = addressTempRegister;
595         }
596
597         DataLabelCompact label(this);
598         ASSERT(address.offset >= 0);
599         ASSERT(address.offset <= MaximumCompactPtrAlignedAddressOffset);
600         ASSERT(ARMThumbImmediate::makeUInt12(address.offset).isUInt7());
601
602         if (dest >= ARMRegisters::r8) {
603             m_assembler.ldrCompact(addressTempRegister, base, ARMThumbImmediate::makeUInt12(address.offset));
604             move(addressTempRegister, dest);
605         } else
606             m_assembler.ldrCompact(dest, base, ARMThumbImmediate::makeUInt12(address.offset));
607         return label;
608     }
609
610     void load16(BaseIndex address, RegisterID dest)
611     {
612         m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale);
613     }
614     
615     void load16(ImplicitAddress address, RegisterID dest)
616     {
617         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.offset);
618         if (armImm.isValid())
619             m_assembler.ldrh(dest, address.base, armImm);
620         else {
621             move(TrustedImm32(address.offset), dataTempRegister);
622             m_assembler.ldrh(dest, address.base, dataTempRegister);
623         }
624     }
625
626     DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
627     {
628         DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
629         store32(src, ArmAddress(address.base, dataTempRegister));
630         return label;
631     }
632
633     void store32(RegisterID src, ImplicitAddress address)
634     {
635         store32(src, setupArmAddress(address));
636     }
637
638     void store32(RegisterID src, BaseIndex address)
639     {
640         store32(src, setupArmAddress(address));
641     }
642
643     void store32(TrustedImm32 imm, ImplicitAddress address)
644     {
645         move(imm, dataTempRegister);
646         store32(dataTempRegister, setupArmAddress(address));
647     }
648
649     void store32(TrustedImm32 imm, BaseIndex address)
650     {
651         move(imm, dataTempRegister);
652         store32(dataTempRegister, setupArmAddress(address));
653     }
654
655     void store32(RegisterID src, const void* address)
656     {
657         move(TrustedImmPtr(address), addressTempRegister);
658         m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
659     }
660
661     void store32(TrustedImm32 imm, const void* address)
662     {
663         move(imm, dataTempRegister);
664         store32(dataTempRegister, address);
665     }
666
667     void store8(RegisterID src, BaseIndex address)
668     {
669         store8(src, setupArmAddress(address));
670     }
671
672
673     // Floating-point operations:
674
675     static bool supportsFloatingPoint() { return true; }
676     static bool supportsFloatingPointTruncate() { return true; }
677     static bool supportsFloatingPointSqrt() { return true; }
678     static bool supportsFloatingPointAbs() { return true; }
679
680     void loadDouble(ImplicitAddress address, FPRegisterID dest)
681     {
682         RegisterID base = address.base;
683         int32_t offset = address.offset;
684
685         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
686         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
687             add32(TrustedImm32(offset), base, addressTempRegister);
688             base = addressTempRegister;
689             offset = 0;
690         }
691         
692         m_assembler.vldr(dest, base, offset);
693     }
694
695     void moveDouble(FPRegisterID src, FPRegisterID dest)
696     {
697         if (src != dest)
698             m_assembler.vmov(dest, src);
699     }
700
701     void loadDouble(const void* address, FPRegisterID dest)
702     {
703         move(TrustedImmPtr(address), addressTempRegister);
704         m_assembler.vldr(dest, addressTempRegister, 0);
705     }
706
707     void storeDouble(FPRegisterID src, ImplicitAddress address)
708     {
709         RegisterID base = address.base;
710         int32_t offset = address.offset;
711
712         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
713         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
714             add32(TrustedImm32(offset), base, addressTempRegister);
715             base = addressTempRegister;
716             offset = 0;
717         }
718         
719         m_assembler.vstr(src, base, offset);
720     }
721
722     void storeDouble(FPRegisterID src, const void* address)
723     {
724         move(ImmPtr(address), addressTempRegister);
725         storeDouble(src, addressTempRegister);
726     }
727
728     void addDouble(FPRegisterID src, FPRegisterID dest)
729     {
730         m_assembler.vadd(dest, dest, src);
731     }
732
733     void addDouble(Address src, FPRegisterID dest)
734     {
735         loadDouble(src, fpTempRegister);
736         addDouble(fpTempRegister, dest);
737     }
738
739     void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
740     {
741         m_assembler.vadd(dest, op1, op2);
742     }
743
744     void addDouble(AbsoluteAddress address, FPRegisterID dest)
745     {
746         loadDouble(address.m_ptr, fpTempRegister);
747         m_assembler.vadd(dest, dest, fpTempRegister);
748     }
749
750     void divDouble(FPRegisterID src, FPRegisterID dest)
751     {
752         m_assembler.vdiv(dest, dest, src);
753     }
754
755     void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
756     {
757         m_assembler.vdiv(dest, op1, op2);
758     }
759
760     void subDouble(FPRegisterID src, FPRegisterID dest)
761     {
762         m_assembler.vsub(dest, dest, src);
763     }
764
765     void subDouble(Address src, FPRegisterID dest)
766     {
767         loadDouble(src, fpTempRegister);
768         subDouble(fpTempRegister, dest);
769     }
770
771     void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
772     {
773         m_assembler.vsub(dest, op1, op2);
774     }
775
776     void mulDouble(FPRegisterID src, FPRegisterID dest)
777     {
778         m_assembler.vmul(dest, dest, src);
779     }
780
781     void mulDouble(Address src, FPRegisterID dest)
782     {
783         loadDouble(src, fpTempRegister);
784         mulDouble(fpTempRegister, dest);
785     }
786
787     void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
788     {
789         m_assembler.vmul(dest, op1, op2);
790     }
791
792     void sqrtDouble(FPRegisterID src, FPRegisterID dest)
793     {
794         m_assembler.vsqrt(dest, src);
795     }
796     
797     void absDouble(FPRegisterID src, FPRegisterID dest)
798     {
799         m_assembler.vabs(dest, src);
800     }
801
802     void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
803     {
804         m_assembler.vmov(fpTempRegisterAsSingle(), src);
805         m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
806     }
807
808     void convertInt32ToDouble(Address address, FPRegisterID dest)
809     {
810         // Fixme: load directly into the fpr!
811         load32(address, dataTempRegister);
812         m_assembler.vmov(fpTempRegisterAsSingle(), dataTempRegister);
813         m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
814     }
815
816     void convertInt32ToDouble(AbsoluteAddress address, FPRegisterID dest)
817     {
818         // Fixme: load directly into the fpr!
819         load32(address.m_ptr, dataTempRegister);
820         m_assembler.vmov(fpTempRegisterAsSingle(), dataTempRegister);
821         m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
822     }
823
824     Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
825     {
826         m_assembler.vcmp(left, right);
827         m_assembler.vmrs();
828
829         if (cond == DoubleNotEqual) {
830             // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump.
831             Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
832             Jump result = makeBranch(ARMv7Assembler::ConditionNE);
833             unordered.link(this);
834             return result;
835         }
836         if (cond == DoubleEqualOrUnordered) {
837             Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
838             Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
839             unordered.link(this);
840             // We get here if either unordered or equal.
841             Jump result = jump();
842             notEqual.link(this);
843             return result;
844         }
845         return makeBranch(cond);
846     }
847
848     enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
849     Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
850     {
851         // Convert into dest.
852         m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
853         m_assembler.vmov(dest, fpTempRegisterAsSingle());
854
855         // Calculate 2x dest.  If the value potentially underflowed, it will have
856         // clamped to 0x80000000, so 2x dest is zero in this case. In the case of
857         // overflow the result will be equal to -2.
858         Jump underflow = branchAdd32(Zero, dest, dest, dataTempRegister);
859         Jump noOverflow = branch32(NotEqual, dataTempRegister, Imm32(-2));
860
861         // For BranchIfTruncateSuccessful, we branch if 'noOverflow' jumps.
862         underflow.link(this);
863         if (branchType == BranchIfTruncateSuccessful)
864             return noOverflow;
865
866         // We'll reach the current point in the code on failure, so plant a
867         // jump here & link the success case.
868         Jump failure = jump();
869         noOverflow.link(this);
870         return failure;
871     }
872
873     // Result is undefined if the value is outside of the integer range.
874     void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
875     {
876         m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
877         m_assembler.vmov(dest, fpTempRegisterAsSingle());
878     }
879     
880     // Convert 'src' to an integer, and places the resulting 'dest'.
881     // If the result is not representable as a 32 bit value, branch.
882     // May also branch for some values that are representable in 32 bits
883     // (specifically, in this case, 0).
884     void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID)
885     {
886         m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
887         m_assembler.vmov(dest, fpTempRegisterAsSingle());
888
889         // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
890         m_assembler.vcvt_signedToFloatingPoint(fpTempRegister, fpTempRegisterAsSingle());
891         failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, fpTempRegister));
892
893         // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
894         failureCases.append(branchTest32(Zero, dest));
895     }
896
897     Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID)
898     {
899         m_assembler.vcmpz(reg);
900         m_assembler.vmrs();
901         Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
902         Jump result = makeBranch(ARMv7Assembler::ConditionNE);
903         unordered.link(this);
904         return result;
905     }
906
907     Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID)
908     {
909         m_assembler.vcmpz(reg);
910         m_assembler.vmrs();
911         Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
912         Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
913         unordered.link(this);
914         // We get here if either unordered or equal.
915         Jump result = jump();
916         notEqual.link(this);
917         return result;
918     }
919
920     // Stack manipulation operations:
921     //
922     // The ABI is assumed to provide a stack abstraction to memory,
923     // containing machine word sized units of data.  Push and pop
924     // operations add and remove a single register sized unit of data
925     // to or from the stack.  Peek and poke operations read or write
926     // values on the stack, without moving the current stack position.
927     
928     void pop(RegisterID dest)
929     {
930         // store postindexed with writeback
931         m_assembler.ldr(dest, ARMRegisters::sp, sizeof(void*), false, true);
932     }
933
934     void push(RegisterID src)
935     {
936         // store preindexed with writeback
937         m_assembler.str(src, ARMRegisters::sp, -sizeof(void*), true, true);
938     }
939
940     void push(Address address)
941     {
942         load32(address, dataTempRegister);
943         push(dataTempRegister);
944     }
945
946     void push(TrustedImm32 imm)
947     {
948         move(imm, dataTempRegister);
949         push(dataTempRegister);
950     }
951
952     // Register move operations:
953     //
954     // Move values in registers.
955
956     void move(TrustedImm32 imm, RegisterID dest)
957     {
958         uint32_t value = imm.m_value;
959
960         if (imm.m_isPointer)
961             moveFixedWidthEncoding(imm, dest);
962         else {
963             ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(value);
964
965             if (armImm.isValid())
966                 m_assembler.mov(dest, armImm);
967             else if ((armImm = ARMThumbImmediate::makeEncodedImm(~value)).isValid())
968                 m_assembler.mvn(dest, armImm);
969             else {
970                 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(value));
971                 if (value & 0xffff0000)
972                     m_assembler.movt(dest, ARMThumbImmediate::makeUInt16(value >> 16));
973             }
974         }
975     }
976
977     void move(RegisterID src, RegisterID dest)
978     {
979         if (src != dest)
980             m_assembler.mov(dest, src);
981     }
982
983     void move(TrustedImmPtr imm, RegisterID dest)
984     {
985         move(TrustedImm32(imm), dest);
986     }
987
988     void swap(RegisterID reg1, RegisterID reg2)
989     {
990         move(reg1, dataTempRegister);
991         move(reg2, reg1);
992         move(dataTempRegister, reg2);
993     }
994
995     void signExtend32ToPtr(RegisterID src, RegisterID dest)
996     {
997         move(src, dest);
998     }
999
1000     void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
1001     {
1002         move(src, dest);
1003     }
1004
1005     // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
1006     static RelationalCondition invert(RelationalCondition cond)
1007     {
1008         return static_cast<RelationalCondition>(cond ^ 1);
1009     }
1010
1011     void nop()
1012     {
1013         m_assembler.nop();
1014     }
1015
1016     // Forwards / external control flow operations:
1017     //
1018     // This set of jump and conditional branch operations return a Jump
1019     // object which may linked at a later point, allow forwards jump,
1020     // or jumps that will require external linkage (after the code has been
1021     // relocated).
1022     //
1023     // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
1024     // respecitvely, for unsigned comparisons the names b, a, be, and ae are
1025     // used (representing the names 'below' and 'above').
1026     //
1027     // Operands to the comparision are provided in the expected order, e.g.
1028     // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
1029     // treated as a signed 32bit value, is less than or equal to 5.
1030     //
1031     // jz and jnz test whether the first operand is equal to zero, and take
1032     // an optional second operand of a mask under which to perform the test.
1033 private:
1034
1035     // Should we be using TEQ for equal/not-equal?
1036     void compare32(RegisterID left, TrustedImm32 right)
1037     {
1038         int32_t imm = right.m_value;
1039         if (!imm)
1040             m_assembler.tst(left, left);
1041         else {
1042             ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
1043             if (armImm.isValid())
1044                 m_assembler.cmp(left, armImm);
1045             else if ((armImm = ARMThumbImmediate::makeEncodedImm(-imm)).isValid())
1046                 m_assembler.cmn(left, armImm);
1047             else {
1048                 move(TrustedImm32(imm), dataTempRegister);
1049                 m_assembler.cmp(left, dataTempRegister);
1050             }
1051         }
1052     }
1053
1054     void test32(RegisterID reg, TrustedImm32 mask)
1055     {
1056         int32_t imm = mask.m_value;
1057
1058         if (imm == -1)
1059             m_assembler.tst(reg, reg);
1060         else {
1061             ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
1062             if (armImm.isValid())
1063                 m_assembler.tst(reg, armImm);
1064             else {
1065                 move(mask, dataTempRegister);
1066                 m_assembler.tst(reg, dataTempRegister);
1067             }
1068         }
1069     }
1070
1071 public:
1072     Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
1073     {
1074         m_assembler.cmp(left, right);
1075         return Jump(makeBranch(cond));
1076     }
1077
1078     Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1079     {
1080         compare32(left, right);
1081         return Jump(makeBranch(cond));
1082     }
1083
1084     Jump branch32(RelationalCondition cond, RegisterID left, Address right)
1085     {
1086         load32(right, dataTempRegister);
1087         return branch32(cond, left, dataTempRegister);
1088     }
1089
1090     Jump branch32(RelationalCondition cond, Address left, RegisterID right)
1091     {
1092         load32(left, dataTempRegister);
1093         return branch32(cond, dataTempRegister, right);
1094     }
1095
1096     Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
1097     {
1098         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1099         load32(left, addressTempRegister);
1100         return branch32(cond, addressTempRegister, right);
1101     }
1102
1103     Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1104     {
1105         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1106         load32(left, addressTempRegister);
1107         return branch32(cond, addressTempRegister, right);
1108     }
1109
1110     Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1111     {
1112         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1113         load32WithUnalignedHalfWords(left, addressTempRegister);
1114         return branch32(cond, addressTempRegister, right);
1115     }
1116
1117     Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
1118     {
1119         load32(left.m_ptr, dataTempRegister);
1120         return branch32(cond, dataTempRegister, right);
1121     }
1122
1123     Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
1124     {
1125         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1126         load32(left.m_ptr, addressTempRegister);
1127         return branch32(cond, addressTempRegister, right);
1128     }
1129
1130     Jump branch8(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1131     {
1132         compare32(left, right);
1133         return Jump(makeBranch(cond));
1134     }
1135
1136     Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
1137     {
1138         ASSERT(!(0xffffff00 & right.m_value));
1139         // use addressTempRegister incase the branch8 we call uses dataTempRegister. :-/
1140         load8(left, addressTempRegister);
1141         return branch8(cond, addressTempRegister, right);
1142     }
1143
1144     Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1145     {
1146         ASSERT(!(0xffffff00 & right.m_value));
1147         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1148         load8(left, addressTempRegister);
1149         return branch32(cond, addressTempRegister, right);
1150     }
1151     
1152     Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
1153     {
1154         m_assembler.tst(reg, mask);
1155         return Jump(makeBranch(cond));
1156     }
1157
1158     Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1159     {
1160         test32(reg, mask);
1161         return Jump(makeBranch(cond));
1162     }
1163
1164     Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1165     {
1166         // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1167         load32(address, addressTempRegister);
1168         return branchTest32(cond, addressTempRegister, mask);
1169     }
1170
1171     Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1172     {
1173         // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1174         load32(address, addressTempRegister);
1175         return branchTest32(cond, addressTempRegister, mask);
1176     }
1177
1178     Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1179     {
1180         // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1181         load8(address, addressTempRegister);
1182         return branchTest32(cond, addressTempRegister, mask);
1183     }
1184
1185     void jump(RegisterID target)
1186     {
1187         m_assembler.bx(target);
1188     }
1189
1190     // Address is a memory location containing the address to jump to
1191     void jump(Address address)
1192     {
1193         load32(address, dataTempRegister);
1194         m_assembler.bx(dataTempRegister);
1195     }
1196     
1197     void jump(AbsoluteAddress address)
1198     {
1199         move(TrustedImmPtr(address.m_ptr), dataTempRegister);
1200         load32(Address(dataTempRegister), dataTempRegister);
1201         m_assembler.bx(dataTempRegister);
1202     }
1203
1204
1205     // Arithmetic control flow operations:
1206     //
1207     // This set of conditional branch operations branch based
1208     // on the result of an arithmetic operation.  The operation
1209     // is performed as normal, storing the result.
1210     //
1211     // * jz operations branch if the result is zero.
1212     // * jo operations branch if the (signed) arithmetic
1213     //   operation caused an overflow to occur.
1214     
1215     Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1216     {
1217         m_assembler.add_S(dest, op1, op2);
1218         return Jump(makeBranch(cond));
1219     }
1220
1221     Jump branchAdd32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
1222     {
1223         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1224         if (armImm.isValid())
1225             m_assembler.add_S(dest, op1, armImm);
1226         else {
1227             move(imm, dataTempRegister);
1228             m_assembler.add_S(dest, op1, dataTempRegister);
1229         }
1230         return Jump(makeBranch(cond));
1231     }
1232
1233     Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
1234     {
1235         return branchAdd32(cond, dest, src, dest);
1236     }
1237
1238     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1239     {
1240         return branchAdd32(cond, dest, imm, dest);
1241     }
1242
1243     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
1244     {
1245         // Move the high bits of the address into addressTempRegister,
1246         // and load the value into dataTempRegister.
1247         move(ImmPtr(dest.m_ptr), addressTempRegister);
1248         m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
1249
1250         // Do the add.
1251         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1252         if (armImm.isValid())
1253             m_assembler.add_S(dataTempRegister, dataTempRegister, armImm);
1254         else {
1255             // If the operand does not fit into an immediate then load it temporarily
1256             // into addressTempRegister; since we're overwriting addressTempRegister
1257             // we'll need to reload it with the high bits of the address afterwards.
1258             move(imm, addressTempRegister);
1259             m_assembler.add_S(dataTempRegister, dataTempRegister, addressTempRegister);
1260             move(ImmPtr(dest.m_ptr), addressTempRegister);
1261         }
1262
1263         // Store the result.
1264         m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
1265
1266         return Jump(makeBranch(cond));
1267     }
1268
1269     Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
1270     {
1271         m_assembler.smull(dest, dataTempRegister, src1, src2);
1272
1273         if (cond == Overflow) {
1274             m_assembler.asr(addressTempRegister, dest, 31);
1275             return branch32(NotEqual, addressTempRegister, dataTempRegister);
1276         }
1277
1278         return branchTest32(cond, dest);
1279     }
1280
1281     Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
1282     {
1283         return branchMul32(cond, src, dest, dest);
1284     }
1285
1286     Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
1287     {
1288         move(imm, dataTempRegister);
1289         return branchMul32(cond, dataTempRegister, src, dest);
1290     }
1291
1292     Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
1293     {
1294         m_assembler.orr_S(dest, dest, src);
1295         return Jump(makeBranch(cond));
1296     }
1297
1298     Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1299     {
1300         m_assembler.sub_S(dest, op1, op2);
1301         return Jump(makeBranch(cond));
1302     }
1303
1304     Jump branchSub32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
1305     {
1306         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1307         if (armImm.isValid())
1308             m_assembler.sub_S(dest, op1, armImm);
1309         else {
1310             move(imm, dataTempRegister);
1311             m_assembler.sub_S(dest, op1, dataTempRegister);
1312         }
1313         return Jump(makeBranch(cond));
1314     }
1315     
1316     Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
1317     {
1318         return branchSub32(cond, dest, src, dest);
1319     }
1320
1321     Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1322     {
1323         return branchSub32(cond, dest, imm, dest);
1324     }
1325     
1326     void relativeTableJump(RegisterID index, int scale)
1327     {
1328         ASSERT(scale >= 0 && scale <= 31);
1329
1330         // dataTempRegister will point after the jump if index register contains zero
1331         move(ARMRegisters::pc, dataTempRegister);
1332         m_assembler.add(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(9));
1333
1334         ShiftTypeAndAmount shift(SRType_LSL, scale);
1335         m_assembler.add(dataTempRegister, dataTempRegister, index, shift);
1336         jump(dataTempRegister);
1337     }
1338
1339     // Miscellaneous operations:
1340
1341     void breakpoint(uint8_t imm = 0)
1342     {
1343         m_assembler.bkpt(imm);
1344     }
1345
1346     ALWAYS_INLINE Call nearCall()
1347     {
1348         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1349         return Call(m_assembler.blx(dataTempRegister), Call::LinkableNear);
1350     }
1351
1352     ALWAYS_INLINE Call call()
1353     {
1354         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1355         return Call(m_assembler.blx(dataTempRegister), Call::Linkable);
1356     }
1357
1358     ALWAYS_INLINE Call call(RegisterID target)
1359     {
1360         return Call(m_assembler.blx(target), Call::None);
1361     }
1362
1363     ALWAYS_INLINE Call call(Address address)
1364     {
1365         load32(address, dataTempRegister);
1366         return Call(m_assembler.blx(dataTempRegister), Call::None);
1367     }
1368
1369     ALWAYS_INLINE void ret()
1370     {
1371         m_assembler.bx(linkRegister);
1372     }
1373
1374     void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
1375     {
1376         m_assembler.cmp(left, right);
1377         m_assembler.it(armV7Condition(cond), false);
1378         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1379         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1380     }
1381
1382     void compare32(RelationalCondition cond, Address left, RegisterID right, RegisterID dest)
1383     {
1384         load32(left, dataTempRegister);
1385         compare32(cond, dataTempRegister, right, dest);
1386     }
1387
1388     void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1389     {
1390         compare32(left, right);
1391         m_assembler.it(armV7Condition(cond), false);
1392         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1393         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1394     }
1395
1396     // FIXME:
1397     // The mask should be optional... paerhaps the argument order should be
1398     // dest-src, operations always have a dest? ... possibly not true, considering
1399     // asm ops like test, or pseudo ops like pop().
1400     void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1401     {
1402         load32(address, dataTempRegister);
1403         test32(dataTempRegister, mask);
1404         m_assembler.it(armV7Condition(cond), false);
1405         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1406         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1407     }
1408
1409     void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1410     {
1411         load8(address, dataTempRegister);
1412         test32(dataTempRegister, mask);
1413         m_assembler.it(armV7Condition(cond), false);
1414         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1415         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1416     }
1417
1418     ALWAYS_INLINE DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dst)
1419     {
1420         moveFixedWidthEncoding(imm, dst);
1421         return DataLabel32(this);
1422     }
1423
1424     ALWAYS_INLINE DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst)
1425     {
1426         moveFixedWidthEncoding(TrustedImm32(imm), dst);
1427         return DataLabelPtr(this);
1428     }
1429
1430     ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1431     {
1432         dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1433         return branch32(cond, left, dataTempRegister);
1434     }
1435
1436     ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1437     {
1438         load32(left, addressTempRegister);
1439         dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1440         return branch32(cond, addressTempRegister, dataTempRegister);
1441     }
1442
1443     ALWAYS_INLINE DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
1444     {
1445         DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
1446         store32(dataTempRegister, address);
1447         return label;
1448     }
1449     ALWAYS_INLINE DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(TrustedImmPtr(0), address); }
1450
1451
1452     ALWAYS_INLINE Call tailRecursiveCall()
1453     {
1454         // Like a normal call, but don't link.
1455         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1456         return Call(m_assembler.bx(dataTempRegister), Call::Linkable);
1457     }
1458
1459     ALWAYS_INLINE Call makeTailRecursiveCall(Jump oldJump)
1460     {
1461         oldJump.link(this);
1462         return tailRecursiveCall();
1463     }
1464
1465     
1466     int executableOffsetFor(int location)
1467     {
1468         return m_assembler.executableOffsetFor(location);
1469     }
1470
1471     static FunctionPtr readCallTarget(CodeLocationCall call)
1472     {
1473         return FunctionPtr(reinterpret_cast<void(*)()>(ARMv7Assembler::readCallTarget(call.dataLocation())));
1474     }
1475
1476 protected:
1477     bool inUninterruptedSequence()
1478     {
1479         return m_inUninterruptedSequence;
1480     }
1481
1482     ALWAYS_INLINE Jump jump()
1483     {
1484         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1485         return Jump(m_assembler.bx(dataTempRegister), inUninterruptedSequence() ? ARMv7Assembler::JumpNoConditionFixedSize : ARMv7Assembler::JumpNoCondition);
1486     }
1487
1488     ALWAYS_INLINE Jump makeBranch(ARMv7Assembler::Condition cond)
1489     {
1490         m_assembler.it(cond, true, true);
1491         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1492         return Jump(m_assembler.bx(dataTempRegister), inUninterruptedSequence() ? ARMv7Assembler::JumpConditionFixedSize : ARMv7Assembler::JumpCondition, cond);
1493     }
1494     ALWAYS_INLINE Jump makeBranch(RelationalCondition cond) { return makeBranch(armV7Condition(cond)); }
1495     ALWAYS_INLINE Jump makeBranch(ResultCondition cond) { return makeBranch(armV7Condition(cond)); }
1496     ALWAYS_INLINE Jump makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); }
1497
1498     ArmAddress setupArmAddress(BaseIndex address)
1499     {
1500         if (address.offset) {
1501             ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1502             if (imm.isValid())
1503                 m_assembler.add(addressTempRegister, address.base, imm);
1504             else {
1505                 move(TrustedImm32(address.offset), addressTempRegister);
1506                 m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1507             }
1508
1509             return ArmAddress(addressTempRegister, address.index, address.scale);
1510         } else
1511             return ArmAddress(address.base, address.index, address.scale);
1512     }
1513
1514     ArmAddress setupArmAddress(Address address)
1515     {
1516         if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1517             return ArmAddress(address.base, address.offset);
1518
1519         move(TrustedImm32(address.offset), addressTempRegister);
1520         return ArmAddress(address.base, addressTempRegister);
1521     }
1522
1523     ArmAddress setupArmAddress(ImplicitAddress address)
1524     {
1525         if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1526             return ArmAddress(address.base, address.offset);
1527
1528         move(TrustedImm32(address.offset), addressTempRegister);
1529         return ArmAddress(address.base, addressTempRegister);
1530     }
1531
1532     RegisterID makeBaseIndexBase(BaseIndex address)
1533     {
1534         if (!address.offset)
1535             return address.base;
1536
1537         ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1538         if (imm.isValid())
1539             m_assembler.add(addressTempRegister, address.base, imm);
1540         else {
1541             move(TrustedImm32(address.offset), addressTempRegister);
1542             m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1543         }
1544
1545         return addressTempRegister;
1546     }
1547
1548     void moveFixedWidthEncoding(TrustedImm32 imm, RegisterID dst)
1549     {
1550         uint32_t value = imm.m_value;
1551         m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff));
1552         m_assembler.movt(dst, ARMThumbImmediate::makeUInt16(value >> 16));
1553     }
1554
1555     ARMv7Assembler::Condition armV7Condition(RelationalCondition cond)
1556     {
1557         return static_cast<ARMv7Assembler::Condition>(cond);
1558     }
1559
1560     ARMv7Assembler::Condition armV7Condition(ResultCondition cond)
1561     {
1562         return static_cast<ARMv7Assembler::Condition>(cond);
1563     }
1564
1565     ARMv7Assembler::Condition armV7Condition(DoubleCondition cond)
1566     {
1567         return static_cast<ARMv7Assembler::Condition>(cond);
1568     }
1569     
1570 private:
1571     friend class LinkBuffer;
1572     friend class RepatchBuffer;
1573
1574     static void linkCall(void* code, Call call, FunctionPtr function)
1575     {
1576         ARMv7Assembler::linkCall(code, call.m_label, function.value());
1577     }
1578
1579     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
1580     {
1581         ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1582     }
1583
1584     static void repatchCall(CodeLocationCall call, FunctionPtr destination)
1585     {
1586         ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1587     }
1588     
1589     bool m_inUninterruptedSequence;
1590 };
1591
1592 } // namespace JSC
1593
1594 #endif // ENABLE(ASSEMBLER)
1595
1596 #endif // MacroAssemblerARMv7_h