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