3b62cb5be34b72803e617aacbb7e4a9439f3290a
[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     void load8(ImplicitAddress address, RegisterID dest)
605     {
606         load8(setupArmAddress(address), dest);
607     }
608
609     void load8Signed(ImplicitAddress, RegisterID)
610     {
611         unreachableForPlatform();
612     }
613
614     void load8(BaseIndex address, RegisterID dest)
615     {
616         load8(setupArmAddress(address), dest);
617     }
618     
619     void load8Signed(BaseIndex address, RegisterID dest)
620     {
621         load8Signed(setupArmAddress(address), dest);
622     }
623
624     DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
625     {
626         DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
627         load32(ArmAddress(address.base, dataTempRegister), dest);
628         return label;
629     }
630     
631     // FIXME: we should be able to plant a compact load relative to/from any base/dest register.
632     DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
633     {
634         RegisterID base = address.base;
635         
636         if (base >= ARMRegisters::r8) {
637             move(base, addressTempRegister);
638             base = addressTempRegister;
639         }
640
641         DataLabelCompact label(this);
642         ASSERT(address.offset >= 0);
643         ASSERT(address.offset <= MaximumCompactPtrAlignedAddressOffset);
644         ASSERT(ARMThumbImmediate::makeUInt12(address.offset).isUInt7());
645
646         if (dest >= ARMRegisters::r8) {
647             m_assembler.ldrCompact(addressTempRegister, base, ARMThumbImmediate::makeUInt12(address.offset));
648             move(addressTempRegister, dest);
649         } else
650             m_assembler.ldrCompact(dest, base, ARMThumbImmediate::makeUInt12(address.offset));
651         return label;
652     }
653
654     void load16(BaseIndex address, RegisterID dest)
655     {
656         m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale);
657     }
658     
659     void load16Signed(BaseIndex address, RegisterID dest)
660     {
661         load16Signed(setupArmAddress(address), dest);
662     }
663     
664     void load16(ImplicitAddress address, RegisterID dest)
665     {
666         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.offset);
667         if (armImm.isValid())
668             m_assembler.ldrh(dest, address.base, armImm);
669         else {
670             move(TrustedImm32(address.offset), dataTempRegister);
671             m_assembler.ldrh(dest, address.base, dataTempRegister);
672         }
673     }
674     
675     void load16Signed(ImplicitAddress, RegisterID)
676     {
677         unreachableForPlatform();
678     }
679
680     DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
681     {
682         DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
683         store32(src, ArmAddress(address.base, dataTempRegister));
684         return label;
685     }
686
687     void store32(RegisterID src, ImplicitAddress address)
688     {
689         store32(src, setupArmAddress(address));
690     }
691
692     void store32(RegisterID src, BaseIndex address)
693     {
694         store32(src, setupArmAddress(address));
695     }
696
697     void store32(TrustedImm32 imm, ImplicitAddress address)
698     {
699         move(imm, dataTempRegister);
700         store32(dataTempRegister, setupArmAddress(address));
701     }
702
703     void store32(TrustedImm32 imm, BaseIndex address)
704     {
705         move(imm, dataTempRegister);
706         store32(dataTempRegister, setupArmAddress(address));
707     }
708
709     void store32(RegisterID src, const void* address)
710     {
711         move(TrustedImmPtr(address), addressTempRegister);
712         m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
713     }
714
715     void store32(TrustedImm32 imm, const void* address)
716     {
717         move(imm, dataTempRegister);
718         store32(dataTempRegister, address);
719     }
720
721     void store8(RegisterID src, BaseIndex address)
722     {
723         store8(src, setupArmAddress(address));
724     }
725     
726     void store16(RegisterID src, BaseIndex address)
727     {
728         store16(src, setupArmAddress(address));
729     }
730
731 #if ENABLE(JIT_CONSTANT_BLINDING)
732     static bool shouldBlindForSpecificArch(uint32_t value)
733     {
734         ARMThumbImmediate immediate = ARMThumbImmediate::makeEncodedImm(value);
735
736         // Couldn't be encoded as an immediate, so assume it's untrusted.
737         if (!immediate.isValid())
738             return true;
739         
740         // If we can encode the immediate, we have less than 16 attacker
741         // controlled bits.
742         if (immediate.isEncodedImm())
743             return false;
744
745         // Don't let any more than 12 bits of an instruction word
746         // be controlled by an attacker.
747         return !immediate.isUInt12();
748     }
749 #endif
750
751     // Floating-point operations:
752
753     static bool supportsFloatingPoint() { return true; }
754     static bool supportsFloatingPointTruncate() { return true; }
755     static bool supportsFloatingPointSqrt() { return true; }
756     static bool supportsFloatingPointAbs() { return true; }
757
758     void loadDouble(ImplicitAddress address, FPRegisterID dest)
759     {
760         RegisterID base = address.base;
761         int32_t offset = address.offset;
762
763         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
764         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
765             add32(TrustedImm32(offset), base, addressTempRegister);
766             base = addressTempRegister;
767             offset = 0;
768         }
769         
770         m_assembler.vldr(dest, base, offset);
771     }
772
773     void loadFloat(ImplicitAddress address, FPRegisterID dest)
774     {
775         RegisterID base = address.base;
776         int32_t offset = address.offset;
777
778         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
779         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
780             add32(TrustedImm32(offset), base, addressTempRegister);
781             base = addressTempRegister;
782             offset = 0;
783         }
784         
785         m_assembler.flds(ARMRegisters::asSingle(dest), base, offset);
786     }
787
788     void loadDouble(BaseIndex address, FPRegisterID dest)
789     {
790         move(address.index, addressTempRegister);
791         lshift32(TrustedImm32(address.scale), addressTempRegister);
792         add32(address.base, addressTempRegister);
793         loadDouble(Address(addressTempRegister, address.offset), dest);
794     }
795     
796     void loadFloat(BaseIndex address, FPRegisterID dest)
797     {
798         move(address.index, addressTempRegister);
799         lshift32(TrustedImm32(address.scale), addressTempRegister);
800         add32(address.base, addressTempRegister);
801         loadFloat(Address(addressTempRegister, address.offset), dest);
802     }
803
804     void moveDouble(FPRegisterID src, FPRegisterID dest)
805     {
806         if (src != dest)
807             m_assembler.vmov(dest, src);
808     }
809
810     void loadDouble(const void* address, FPRegisterID dest)
811     {
812         move(TrustedImmPtr(address), addressTempRegister);
813         m_assembler.vldr(dest, addressTempRegister, 0);
814     }
815
816     void storeDouble(FPRegisterID src, ImplicitAddress address)
817     {
818         RegisterID base = address.base;
819         int32_t offset = address.offset;
820
821         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
822         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
823             add32(TrustedImm32(offset), base, addressTempRegister);
824             base = addressTempRegister;
825             offset = 0;
826         }
827         
828         m_assembler.vstr(src, base, offset);
829     }
830
831     void storeFloat(FPRegisterID src, ImplicitAddress address)
832     {
833         RegisterID base = address.base;
834         int32_t offset = address.offset;
835
836         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
837         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
838             add32(TrustedImm32(offset), base, addressTempRegister);
839             base = addressTempRegister;
840             offset = 0;
841         }
842         
843         m_assembler.fsts(ARMRegisters::asSingle(src), base, offset);
844     }
845
846     void storeDouble(FPRegisterID src, const void* address)
847     {
848         move(TrustedImmPtr(address), addressTempRegister);
849         storeDouble(src, addressTempRegister);
850     }
851
852     void storeDouble(FPRegisterID src, BaseIndex address)
853     {
854         move(address.index, addressTempRegister);
855         lshift32(TrustedImm32(address.scale), addressTempRegister);
856         add32(address.base, addressTempRegister);
857         storeDouble(src, Address(addressTempRegister, address.offset));
858     }
859     
860     void storeFloat(FPRegisterID src, BaseIndex address)
861     {
862         move(address.index, addressTempRegister);
863         lshift32(TrustedImm32(address.scale), addressTempRegister);
864         add32(address.base, addressTempRegister);
865         storeFloat(src, Address(addressTempRegister, address.offset));
866     }
867     
868     void addDouble(FPRegisterID src, FPRegisterID dest)
869     {
870         m_assembler.vadd(dest, dest, src);
871     }
872
873     void addDouble(Address src, FPRegisterID dest)
874     {
875         loadDouble(src, fpTempRegister);
876         addDouble(fpTempRegister, dest);
877     }
878
879     void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
880     {
881         m_assembler.vadd(dest, op1, op2);
882     }
883
884     void addDouble(AbsoluteAddress address, FPRegisterID dest)
885     {
886         loadDouble(address.m_ptr, fpTempRegister);
887         m_assembler.vadd(dest, dest, fpTempRegister);
888     }
889
890     void divDouble(FPRegisterID src, FPRegisterID dest)
891     {
892         m_assembler.vdiv(dest, dest, src);
893     }
894
895     void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
896     {
897         m_assembler.vdiv(dest, op1, op2);
898     }
899
900     void subDouble(FPRegisterID src, FPRegisterID dest)
901     {
902         m_assembler.vsub(dest, dest, src);
903     }
904
905     void subDouble(Address src, FPRegisterID dest)
906     {
907         loadDouble(src, fpTempRegister);
908         subDouble(fpTempRegister, dest);
909     }
910
911     void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
912     {
913         m_assembler.vsub(dest, op1, op2);
914     }
915
916     void mulDouble(FPRegisterID src, FPRegisterID dest)
917     {
918         m_assembler.vmul(dest, dest, src);
919     }
920
921     void mulDouble(Address src, FPRegisterID dest)
922     {
923         loadDouble(src, fpTempRegister);
924         mulDouble(fpTempRegister, dest);
925     }
926
927     void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
928     {
929         m_assembler.vmul(dest, op1, op2);
930     }
931
932     void sqrtDouble(FPRegisterID src, FPRegisterID dest)
933     {
934         m_assembler.vsqrt(dest, src);
935     }
936     
937     void absDouble(FPRegisterID src, FPRegisterID dest)
938     {
939         m_assembler.vabs(dest, src);
940     }
941
942     void negateDouble(FPRegisterID src, FPRegisterID dest)
943     {
944         m_assembler.vneg(dest, src);
945     }
946
947     void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
948     {
949         m_assembler.vmov(fpTempRegister, src, src);
950         m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
951     }
952
953     void convertInt32ToDouble(Address address, FPRegisterID dest)
954     {
955         // Fixme: load directly into the fpr!
956         load32(address, dataTempRegister);
957         m_assembler.vmov(fpTempRegister, dataTempRegister, dataTempRegister);
958         m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
959     }
960
961     void convertInt32ToDouble(AbsoluteAddress address, FPRegisterID dest)
962     {
963         // Fixme: load directly into the fpr!
964         load32(address.m_ptr, dataTempRegister);
965         m_assembler.vmov(fpTempRegister, dataTempRegister, dataTempRegister);
966         m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
967     }
968     
969     void convertFloatToDouble(FPRegisterID src, FPRegisterID dst)
970     {
971         m_assembler.vcvtds(dst, ARMRegisters::asSingle(src));
972     }
973     
974     void convertDoubleToFloat(FPRegisterID src, FPRegisterID dst)
975     {
976         m_assembler.vcvtsd(ARMRegisters::asSingle(dst), src);
977     }
978
979     Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
980     {
981         m_assembler.vcmp(left, right);
982         m_assembler.vmrs();
983
984         if (cond == DoubleNotEqual) {
985             // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump.
986             Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
987             Jump result = makeBranch(ARMv7Assembler::ConditionNE);
988             unordered.link(this);
989             return result;
990         }
991         if (cond == DoubleEqualOrUnordered) {
992             Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
993             Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
994             unordered.link(this);
995             // We get here if either unordered or equal.
996             Jump result = jump();
997             notEqual.link(this);
998             return result;
999         }
1000         return makeBranch(cond);
1001     }
1002
1003     enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
1004     Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
1005     {
1006         // Convert into dest.
1007         m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1008         m_assembler.vmov(dest, fpTempRegisterAsSingle());
1009
1010         // Calculate 2x dest.  If the value potentially underflowed, it will have
1011         // clamped to 0x80000000, so 2x dest is zero in this case. In the case of
1012         // overflow the result will be equal to -2.
1013         Jump underflow = branchAdd32(Zero, dest, dest, dataTempRegister);
1014         Jump noOverflow = branch32(NotEqual, dataTempRegister, TrustedImm32(-2));
1015
1016         // For BranchIfTruncateSuccessful, we branch if 'noOverflow' jumps.
1017         underflow.link(this);
1018         if (branchType == BranchIfTruncateSuccessful)
1019             return noOverflow;
1020
1021         // We'll reach the current point in the code on failure, so plant a
1022         // jump here & link the success case.
1023         Jump failure = jump();
1024         noOverflow.link(this);
1025         return failure;
1026     }
1027
1028     Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
1029     {
1030         m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1031         m_assembler.vmov(dest, fpTempRegisterAsSingle());
1032         
1033         Jump overflow = branch32(Equal, dest, TrustedImm32(0x7fffffff));
1034         Jump success = branch32(GreaterThanOrEqual, dest, TrustedImm32(0));
1035         overflow.link(this);
1036
1037         if (branchType == BranchIfTruncateSuccessful)
1038             return success;
1039         
1040         Jump failure = jump();
1041         success.link(this);
1042         return failure;
1043     }
1044
1045     // Result is undefined if the value is outside of the integer range.
1046     void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
1047     {
1048         m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1049         m_assembler.vmov(dest, fpTempRegisterAsSingle());
1050     }
1051
1052     void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
1053     {
1054         m_assembler.vcvt_floatingPointToUnsigned(fpTempRegisterAsSingle(), src);
1055         m_assembler.vmov(dest, fpTempRegisterAsSingle());
1056     }
1057     
1058     // Convert 'src' to an integer, and places the resulting 'dest'.
1059     // If the result is not representable as a 32 bit value, branch.
1060     // May also branch for some values that are representable in 32 bits
1061     // (specifically, in this case, 0).
1062     void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID)
1063     {
1064         m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1065         m_assembler.vmov(dest, fpTempRegisterAsSingle());
1066
1067         // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
1068         m_assembler.vcvt_signedToFloatingPoint(fpTempRegister, fpTempRegisterAsSingle());
1069         failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, fpTempRegister));
1070
1071         // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
1072         failureCases.append(branchTest32(Zero, dest));
1073     }
1074
1075     Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID)
1076     {
1077         m_assembler.vcmpz(reg);
1078         m_assembler.vmrs();
1079         Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1080         Jump result = makeBranch(ARMv7Assembler::ConditionNE);
1081         unordered.link(this);
1082         return result;
1083     }
1084
1085     Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID)
1086     {
1087         m_assembler.vcmpz(reg);
1088         m_assembler.vmrs();
1089         Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1090         Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
1091         unordered.link(this);
1092         // We get here if either unordered or equal.
1093         Jump result = jump();
1094         notEqual.link(this);
1095         return result;
1096     }
1097
1098     // Stack manipulation operations:
1099     //
1100     // The ABI is assumed to provide a stack abstraction to memory,
1101     // containing machine word sized units of data.  Push and pop
1102     // operations add and remove a single register sized unit of data
1103     // to or from the stack.  Peek and poke operations read or write
1104     // values on the stack, without moving the current stack position.
1105     
1106     void pop(RegisterID dest)
1107     {
1108         // store postindexed with writeback
1109         m_assembler.ldr(dest, ARMRegisters::sp, sizeof(void*), false, true);
1110     }
1111
1112     void push(RegisterID src)
1113     {
1114         // store preindexed with writeback
1115         m_assembler.str(src, ARMRegisters::sp, -sizeof(void*), true, true);
1116     }
1117
1118     void push(Address address)
1119     {
1120         load32(address, dataTempRegister);
1121         push(dataTempRegister);
1122     }
1123
1124     void push(TrustedImm32 imm)
1125     {
1126         move(imm, dataTempRegister);
1127         push(dataTempRegister);
1128     }
1129
1130     // Register move operations:
1131     //
1132     // Move values in registers.
1133
1134     void move(TrustedImm32 imm, RegisterID dest)
1135     {
1136         uint32_t value = imm.m_value;
1137
1138         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(value);
1139
1140         if (armImm.isValid())
1141             m_assembler.mov(dest, armImm);
1142         else if ((armImm = ARMThumbImmediate::makeEncodedImm(~value)).isValid())
1143             m_assembler.mvn(dest, armImm);
1144         else {
1145             m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(value));
1146             if (value & 0xffff0000)
1147                 m_assembler.movt(dest, ARMThumbImmediate::makeUInt16(value >> 16));
1148         }
1149     }
1150
1151     void move(RegisterID src, RegisterID dest)
1152     {
1153         if (src != dest)
1154             m_assembler.mov(dest, src);
1155     }
1156
1157     void move(TrustedImmPtr imm, RegisterID dest)
1158     {
1159         move(TrustedImm32(imm), dest);
1160     }
1161
1162     void swap(RegisterID reg1, RegisterID reg2)
1163     {
1164         move(reg1, dataTempRegister);
1165         move(reg2, reg1);
1166         move(dataTempRegister, reg2);
1167     }
1168
1169     void signExtend32ToPtr(RegisterID src, RegisterID dest)
1170     {
1171         move(src, dest);
1172     }
1173
1174     void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
1175     {
1176         move(src, dest);
1177     }
1178
1179     // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
1180     static RelationalCondition invert(RelationalCondition cond)
1181     {
1182         return static_cast<RelationalCondition>(cond ^ 1);
1183     }
1184
1185     void nop()
1186     {
1187         m_assembler.nop();
1188     }
1189
1190     // Forwards / external control flow operations:
1191     //
1192     // This set of jump and conditional branch operations return a Jump
1193     // object which may linked at a later point, allow forwards jump,
1194     // or jumps that will require external linkage (after the code has been
1195     // relocated).
1196     //
1197     // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
1198     // respecitvely, for unsigned comparisons the names b, a, be, and ae are
1199     // used (representing the names 'below' and 'above').
1200     //
1201     // Operands to the comparision are provided in the expected order, e.g.
1202     // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
1203     // treated as a signed 32bit value, is less than or equal to 5.
1204     //
1205     // jz and jnz test whether the first operand is equal to zero, and take
1206     // an optional second operand of a mask under which to perform the test.
1207 private:
1208
1209     // Should we be using TEQ for equal/not-equal?
1210     void compare32(RegisterID left, TrustedImm32 right)
1211     {
1212         int32_t imm = right.m_value;
1213         if (!imm)
1214             m_assembler.tst(left, left);
1215         else {
1216             ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
1217             if (armImm.isValid())
1218                 m_assembler.cmp(left, armImm);
1219             else if ((armImm = ARMThumbImmediate::makeEncodedImm(-imm)).isValid())
1220                 m_assembler.cmn(left, armImm);
1221             else {
1222                 move(TrustedImm32(imm), dataTempRegister);
1223                 m_assembler.cmp(left, dataTempRegister);
1224             }
1225         }
1226     }
1227
1228     void test32(RegisterID reg, TrustedImm32 mask)
1229     {
1230         int32_t imm = mask.m_value;
1231
1232         if (imm == -1)
1233             m_assembler.tst(reg, reg);
1234         else {
1235             ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
1236             if (armImm.isValid())
1237                 m_assembler.tst(reg, armImm);
1238             else {
1239                 move(mask, dataTempRegister);
1240                 m_assembler.tst(reg, dataTempRegister);
1241             }
1242         }
1243     }
1244
1245 public:
1246     Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
1247     {
1248         m_assembler.cmp(left, right);
1249         return Jump(makeBranch(cond));
1250     }
1251
1252     Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1253     {
1254         compare32(left, right);
1255         return Jump(makeBranch(cond));
1256     }
1257
1258     Jump branch32(RelationalCondition cond, RegisterID left, Address right)
1259     {
1260         load32(right, dataTempRegister);
1261         return branch32(cond, left, dataTempRegister);
1262     }
1263
1264     Jump branch32(RelationalCondition cond, Address left, RegisterID right)
1265     {
1266         load32(left, dataTempRegister);
1267         return branch32(cond, dataTempRegister, right);
1268     }
1269
1270     Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
1271     {
1272         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1273         load32(left, addressTempRegister);
1274         return branch32(cond, addressTempRegister, right);
1275     }
1276
1277     Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1278     {
1279         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1280         load32(left, addressTempRegister);
1281         return branch32(cond, addressTempRegister, right);
1282     }
1283
1284     Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1285     {
1286         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1287         load32WithUnalignedHalfWords(left, addressTempRegister);
1288         return branch32(cond, addressTempRegister, right);
1289     }
1290
1291     Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
1292     {
1293         load32(left.m_ptr, dataTempRegister);
1294         return branch32(cond, dataTempRegister, right);
1295     }
1296
1297     Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
1298     {
1299         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1300         load32(left.m_ptr, addressTempRegister);
1301         return branch32(cond, addressTempRegister, right);
1302     }
1303
1304     Jump branch8(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1305     {
1306         compare32(left, right);
1307         return Jump(makeBranch(cond));
1308     }
1309
1310     Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
1311     {
1312         ASSERT(!(0xffffff00 & right.m_value));
1313         // use addressTempRegister incase the branch8 we call uses dataTempRegister. :-/
1314         load8(left, addressTempRegister);
1315         return branch8(cond, addressTempRegister, right);
1316     }
1317
1318     Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1319     {
1320         ASSERT(!(0xffffff00 & right.m_value));
1321         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1322         load8(left, addressTempRegister);
1323         return branch32(cond, addressTempRegister, right);
1324     }
1325     
1326     Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
1327     {
1328         m_assembler.tst(reg, mask);
1329         return Jump(makeBranch(cond));
1330     }
1331
1332     Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1333     {
1334         test32(reg, mask);
1335         return Jump(makeBranch(cond));
1336     }
1337
1338     Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1339     {
1340         // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1341         load32(address, addressTempRegister);
1342         return branchTest32(cond, addressTempRegister, mask);
1343     }
1344
1345     Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1346     {
1347         // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1348         load32(address, addressTempRegister);
1349         return branchTest32(cond, addressTempRegister, mask);
1350     }
1351
1352     Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1353     {
1354         // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1355         load8(address, addressTempRegister);
1356         return branchTest32(cond, addressTempRegister, mask);
1357     }
1358
1359     void jump(RegisterID target)
1360     {
1361         m_assembler.bx(target);
1362     }
1363
1364     // Address is a memory location containing the address to jump to
1365     void jump(Address address)
1366     {
1367         load32(address, dataTempRegister);
1368         m_assembler.bx(dataTempRegister);
1369     }
1370     
1371     void jump(AbsoluteAddress address)
1372     {
1373         move(TrustedImmPtr(address.m_ptr), dataTempRegister);
1374         load32(Address(dataTempRegister), dataTempRegister);
1375         m_assembler.bx(dataTempRegister);
1376     }
1377
1378
1379     // Arithmetic control flow operations:
1380     //
1381     // This set of conditional branch operations branch based
1382     // on the result of an arithmetic operation.  The operation
1383     // is performed as normal, storing the result.
1384     //
1385     // * jz operations branch if the result is zero.
1386     // * jo operations branch if the (signed) arithmetic
1387     //   operation caused an overflow to occur.
1388     
1389     Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1390     {
1391         m_assembler.add_S(dest, op1, op2);
1392         return Jump(makeBranch(cond));
1393     }
1394
1395     Jump branchAdd32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
1396     {
1397         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1398         if (armImm.isValid())
1399             m_assembler.add_S(dest, op1, armImm);
1400         else {
1401             move(imm, dataTempRegister);
1402             m_assembler.add_S(dest, op1, dataTempRegister);
1403         }
1404         return Jump(makeBranch(cond));
1405     }
1406
1407     Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
1408     {
1409         return branchAdd32(cond, dest, src, dest);
1410     }
1411
1412     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1413     {
1414         return branchAdd32(cond, dest, imm, dest);
1415     }
1416
1417     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
1418     {
1419         // Move the high bits of the address into addressTempRegister,
1420         // and load the value into dataTempRegister.
1421         move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
1422         m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
1423
1424         // Do the add.
1425         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1426         if (armImm.isValid())
1427             m_assembler.add_S(dataTempRegister, dataTempRegister, armImm);
1428         else {
1429             // If the operand does not fit into an immediate then load it temporarily
1430             // into addressTempRegister; since we're overwriting addressTempRegister
1431             // we'll need to reload it with the high bits of the address afterwards.
1432             move(imm, addressTempRegister);
1433             m_assembler.add_S(dataTempRegister, dataTempRegister, addressTempRegister);
1434             move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
1435         }
1436
1437         // Store the result.
1438         m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
1439
1440         return Jump(makeBranch(cond));
1441     }
1442
1443     Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
1444     {
1445         m_assembler.smull(dest, dataTempRegister, src1, src2);
1446
1447         if (cond == Overflow) {
1448             m_assembler.asr(addressTempRegister, dest, 31);
1449             return branch32(NotEqual, addressTempRegister, dataTempRegister);
1450         }
1451
1452         return branchTest32(cond, dest);
1453     }
1454
1455     Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
1456     {
1457         return branchMul32(cond, src, dest, dest);
1458     }
1459
1460     Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
1461     {
1462         move(imm, dataTempRegister);
1463         return branchMul32(cond, dataTempRegister, src, dest);
1464     }
1465
1466     Jump branchNeg32(ResultCondition cond, RegisterID srcDest)
1467     {
1468         ARMThumbImmediate zero = ARMThumbImmediate::makeUInt12(0);
1469         m_assembler.sub_S(srcDest, zero, srcDest);
1470         return Jump(makeBranch(cond));
1471     }
1472
1473     Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
1474     {
1475         m_assembler.orr_S(dest, dest, src);
1476         return Jump(makeBranch(cond));
1477     }
1478
1479     Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1480     {
1481         m_assembler.sub_S(dest, op1, op2);
1482         return Jump(makeBranch(cond));
1483     }
1484
1485     Jump branchSub32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
1486     {
1487         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1488         if (armImm.isValid())
1489             m_assembler.sub_S(dest, op1, armImm);
1490         else {
1491             move(imm, dataTempRegister);
1492             m_assembler.sub_S(dest, op1, dataTempRegister);
1493         }
1494         return Jump(makeBranch(cond));
1495     }
1496     
1497     Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
1498     {
1499         return branchSub32(cond, dest, src, dest);
1500     }
1501
1502     Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1503     {
1504         return branchSub32(cond, dest, imm, dest);
1505     }
1506     
1507     void relativeTableJump(RegisterID index, int scale)
1508     {
1509         ASSERT(scale >= 0 && scale <= 31);
1510
1511         // dataTempRegister will point after the jump if index register contains zero
1512         move(ARMRegisters::pc, dataTempRegister);
1513         m_assembler.add(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(9));
1514
1515         ShiftTypeAndAmount shift(SRType_LSL, scale);
1516         m_assembler.add(dataTempRegister, dataTempRegister, index, shift);
1517         jump(dataTempRegister);
1518     }
1519
1520     // Miscellaneous operations:
1521
1522     void breakpoint(uint8_t imm = 0)
1523     {
1524         m_assembler.bkpt(imm);
1525     }
1526
1527     ALWAYS_INLINE Call nearCall()
1528     {
1529         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1530         return Call(m_assembler.blx(dataTempRegister), Call::LinkableNear);
1531     }
1532
1533     ALWAYS_INLINE Call call()
1534     {
1535         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1536         return Call(m_assembler.blx(dataTempRegister), Call::Linkable);
1537     }
1538
1539     ALWAYS_INLINE Call call(RegisterID target)
1540     {
1541         return Call(m_assembler.blx(target), Call::None);
1542     }
1543
1544     ALWAYS_INLINE Call call(Address address)
1545     {
1546         load32(address, dataTempRegister);
1547         return Call(m_assembler.blx(dataTempRegister), Call::None);
1548     }
1549
1550     ALWAYS_INLINE void ret()
1551     {
1552         m_assembler.bx(linkRegister);
1553     }
1554
1555     void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
1556     {
1557         m_assembler.cmp(left, right);
1558         m_assembler.it(armV7Condition(cond), false);
1559         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1560         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1561     }
1562
1563     void compare32(RelationalCondition cond, Address left, RegisterID right, RegisterID dest)
1564     {
1565         load32(left, dataTempRegister);
1566         compare32(cond, dataTempRegister, right, dest);
1567     }
1568
1569     void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest)
1570     {
1571         load8(left, addressTempRegister);
1572         compare32(cond, addressTempRegister, right, dest);
1573     }
1574
1575     void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1576     {
1577         compare32(left, right);
1578         m_assembler.it(armV7Condition(cond), false);
1579         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1580         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1581     }
1582
1583     // FIXME:
1584     // The mask should be optional... paerhaps the argument order should be
1585     // dest-src, operations always have a dest? ... possibly not true, considering
1586     // asm ops like test, or pseudo ops like pop().
1587     void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1588     {
1589         load32(address, dataTempRegister);
1590         test32(dataTempRegister, mask);
1591         m_assembler.it(armV7Condition(cond), false);
1592         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1593         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1594     }
1595
1596     void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1597     {
1598         load8(address, dataTempRegister);
1599         test32(dataTempRegister, mask);
1600         m_assembler.it(armV7Condition(cond), false);
1601         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1602         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1603     }
1604
1605     ALWAYS_INLINE DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dst)
1606     {
1607         moveFixedWidthEncoding(imm, dst);
1608         return DataLabel32(this);
1609     }
1610
1611     ALWAYS_INLINE DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst)
1612     {
1613         moveFixedWidthEncoding(TrustedImm32(imm), dst);
1614         return DataLabelPtr(this);
1615     }
1616
1617     ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1618     {
1619         dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1620         return branch32(cond, left, dataTempRegister);
1621     }
1622
1623     ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1624     {
1625         load32(left, addressTempRegister);
1626         dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1627         return branch32(cond, addressTempRegister, dataTempRegister);
1628     }
1629
1630     PatchableJump patchableBranchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1631     {
1632         m_makeJumpPatchable = true;
1633         Jump result = branchPtrWithPatch(cond, left, dataLabel, initialRightValue);
1634         m_makeJumpPatchable = false;
1635         return PatchableJump(result);
1636     }
1637
1638     PatchableJump patchableJump()
1639     {
1640         m_makeJumpPatchable = true;
1641         Jump result = jump();
1642         m_makeJumpPatchable = false;
1643         return PatchableJump(result);
1644     }
1645
1646     ALWAYS_INLINE DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
1647     {
1648         DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
1649         store32(dataTempRegister, address);
1650         return label;
1651     }
1652     ALWAYS_INLINE DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(TrustedImmPtr(0), address); }
1653
1654
1655     ALWAYS_INLINE Call tailRecursiveCall()
1656     {
1657         // Like a normal call, but don't link.
1658         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1659         return Call(m_assembler.bx(dataTempRegister), Call::Linkable);
1660     }
1661
1662     ALWAYS_INLINE Call makeTailRecursiveCall(Jump oldJump)
1663     {
1664         oldJump.link(this);
1665         return tailRecursiveCall();
1666     }
1667
1668     
1669     int executableOffsetFor(int location)
1670     {
1671         return m_assembler.executableOffsetFor(location);
1672     }
1673
1674     static FunctionPtr readCallTarget(CodeLocationCall call)
1675     {
1676         return FunctionPtr(reinterpret_cast<void(*)()>(ARMv7Assembler::readCallTarget(call.dataLocation())));
1677     }
1678
1679 protected:
1680     ALWAYS_INLINE Jump jump()
1681     {
1682         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1683         return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpNoConditionFixedSize : ARMv7Assembler::JumpNoCondition);
1684     }
1685
1686     ALWAYS_INLINE Jump makeBranch(ARMv7Assembler::Condition cond)
1687     {
1688         m_assembler.it(cond, true, true);
1689         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1690         return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpConditionFixedSize : ARMv7Assembler::JumpCondition, cond);
1691     }
1692     ALWAYS_INLINE Jump makeBranch(RelationalCondition cond) { return makeBranch(armV7Condition(cond)); }
1693     ALWAYS_INLINE Jump makeBranch(ResultCondition cond) { return makeBranch(armV7Condition(cond)); }
1694     ALWAYS_INLINE Jump makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); }
1695
1696     ArmAddress setupArmAddress(BaseIndex address)
1697     {
1698         if (address.offset) {
1699             ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1700             if (imm.isValid())
1701                 m_assembler.add(addressTempRegister, address.base, imm);
1702             else {
1703                 move(TrustedImm32(address.offset), addressTempRegister);
1704                 m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1705             }
1706
1707             return ArmAddress(addressTempRegister, address.index, address.scale);
1708         } else
1709             return ArmAddress(address.base, address.index, address.scale);
1710     }
1711
1712     ArmAddress setupArmAddress(Address address)
1713     {
1714         if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1715             return ArmAddress(address.base, address.offset);
1716
1717         move(TrustedImm32(address.offset), addressTempRegister);
1718         return ArmAddress(address.base, addressTempRegister);
1719     }
1720
1721     ArmAddress setupArmAddress(ImplicitAddress address)
1722     {
1723         if ((address.offset >= -0xff) && (address.offset <= 0xfff))
1724             return ArmAddress(address.base, address.offset);
1725
1726         move(TrustedImm32(address.offset), addressTempRegister);
1727         return ArmAddress(address.base, addressTempRegister);
1728     }
1729
1730     RegisterID makeBaseIndexBase(BaseIndex address)
1731     {
1732         if (!address.offset)
1733             return address.base;
1734
1735         ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
1736         if (imm.isValid())
1737             m_assembler.add(addressTempRegister, address.base, imm);
1738         else {
1739             move(TrustedImm32(address.offset), addressTempRegister);
1740             m_assembler.add(addressTempRegister, addressTempRegister, address.base);
1741         }
1742
1743         return addressTempRegister;
1744     }
1745
1746     void moveFixedWidthEncoding(TrustedImm32 imm, RegisterID dst)
1747     {
1748         uint32_t value = imm.m_value;
1749         m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff));
1750         m_assembler.movt(dst, ARMThumbImmediate::makeUInt16(value >> 16));
1751     }
1752
1753     ARMv7Assembler::Condition armV7Condition(RelationalCondition cond)
1754     {
1755         return static_cast<ARMv7Assembler::Condition>(cond);
1756     }
1757
1758     ARMv7Assembler::Condition armV7Condition(ResultCondition cond)
1759     {
1760         return static_cast<ARMv7Assembler::Condition>(cond);
1761     }
1762
1763     ARMv7Assembler::Condition armV7Condition(DoubleCondition cond)
1764     {
1765         return static_cast<ARMv7Assembler::Condition>(cond);
1766     }
1767     
1768 private:
1769     friend class LinkBuffer;
1770     friend class RepatchBuffer;
1771
1772     static void linkCall(void* code, Call call, FunctionPtr function)
1773     {
1774         ARMv7Assembler::linkCall(code, call.m_label, function.value());
1775     }
1776
1777     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
1778     {
1779         ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1780     }
1781
1782     static void repatchCall(CodeLocationCall call, FunctionPtr destination)
1783     {
1784         ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1785     }
1786
1787     bool m_makeJumpPatchable;
1788 };
1789
1790 } // namespace JSC
1791
1792 #endif // ENABLE(ASSEMBLER)
1793
1794 #endif // MacroAssemblerARMv7_h