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