c7a76bb8f002510c31216729c30d1b2f30dc00bd
[WebKit-https.git] / Source / JavaScriptCore / assembler / MacroAssemblerARMv7.h
1 /*
2  * Copyright (C) 2009-2018 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 #pragma once
28
29 #if ENABLE(ASSEMBLER)
30
31 #include "ARMv7Assembler.h"
32 #include "AbstractMacroAssembler.h"
33
34 namespace JSC {
35
36 using Assembler = TARGET_ASSEMBLER;
37
38 class MacroAssemblerARMv7 : public AbstractMacroAssembler<Assembler> {
39     static const RegisterID dataTempRegister = ARMRegisters::ip;
40     static const RegisterID addressTempRegister = ARMRegisters::r6;
41
42     static const ARMRegisters::FPDoubleRegisterID fpTempRegister = ARMRegisters::d7;
43     inline ARMRegisters::FPSingleRegisterID fpTempRegisterAsSingle() { return ARMRegisters::asSingle(fpTempRegister); }
44
45 public:
46     static const unsigned numGPRs = 16;
47     static const unsigned numFPRs = 16;
48     
49     MacroAssemblerARMv7()
50         : m_makeJumpPatchable(false)
51     {
52     }
53
54     typedef ARMv7Assembler::LinkRecord LinkRecord;
55     typedef ARMv7Assembler::JumpType JumpType;
56     typedef ARMv7Assembler::JumpLinkType JumpLinkType;
57     typedef ARMv7Assembler::Condition Condition;
58
59     static const ARMv7Assembler::Condition DefaultCondition = ARMv7Assembler::ConditionInvalid;
60     static const ARMv7Assembler::JumpType DefaultJump = ARMv7Assembler::JumpNoConditionFixedSize;
61
62     static bool isCompactPtrAlignedAddressOffset(ptrdiff_t value)
63     {
64         return value >= -255 && value <= 255;
65     }
66
67     Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink() { return m_assembler.jumpsToLink(); }
68     static bool canCompact(JumpType jumpType) { return ARMv7Assembler::canCompact(jumpType); }
69     static JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to) { return ARMv7Assembler::computeJumpType(jumpType, from, to); }
70     static JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to) { return ARMv7Assembler::computeJumpType(record, from, to); }
71     static int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return ARMv7Assembler::jumpSizeDelta(jumpType, jumpLinkType); }
72     template <Assembler::CopyFunction copy>
73     static void link(LinkRecord& record, uint8_t* from, const uint8_t* fromInstruction, uint8_t* to) { return ARMv7Assembler::link<copy>(record, from, fromInstruction, to); }
74
75     struct ArmAddress {
76         enum AddressType {
77             HasOffset,
78             HasIndex,
79         } type;
80         RegisterID base;
81         union {
82             int32_t offset;
83             struct {
84                 RegisterID index;
85                 Scale scale;
86             };
87         } u;
88         
89         explicit ArmAddress(RegisterID base, int32_t offset = 0)
90             : type(HasOffset)
91             , base(base)
92         {
93             u.offset = offset;
94         }
95         
96         explicit ArmAddress(RegisterID base, RegisterID index, Scale scale = TimesOne)
97             : type(HasIndex)
98             , base(base)
99         {
100             u.index = index;
101             u.scale = scale;
102         }
103     };
104     
105 public:
106     static const Scale ScalePtr = TimesFour;
107
108     enum RelationalCondition {
109         Equal = ARMv7Assembler::ConditionEQ,
110         NotEqual = ARMv7Assembler::ConditionNE,
111         Above = ARMv7Assembler::ConditionHI,
112         AboveOrEqual = ARMv7Assembler::ConditionHS,
113         Below = ARMv7Assembler::ConditionLO,
114         BelowOrEqual = ARMv7Assembler::ConditionLS,
115         GreaterThan = ARMv7Assembler::ConditionGT,
116         GreaterThanOrEqual = ARMv7Assembler::ConditionGE,
117         LessThan = ARMv7Assembler::ConditionLT,
118         LessThanOrEqual = ARMv7Assembler::ConditionLE
119     };
120
121     enum ResultCondition {
122         Overflow = ARMv7Assembler::ConditionVS,
123         Signed = ARMv7Assembler::ConditionMI,
124         PositiveOrZero = ARMv7Assembler::ConditionPL,
125         Zero = ARMv7Assembler::ConditionEQ,
126         NonZero = ARMv7Assembler::ConditionNE
127     };
128
129     enum DoubleCondition {
130         // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
131         DoubleEqual = ARMv7Assembler::ConditionEQ,
132         DoubleNotEqual = ARMv7Assembler::ConditionVC, // Not the right flag! check for this & handle differently.
133         DoubleGreaterThan = ARMv7Assembler::ConditionGT,
134         DoubleGreaterThanOrEqual = ARMv7Assembler::ConditionGE,
135         DoubleLessThan = ARMv7Assembler::ConditionLO,
136         DoubleLessThanOrEqual = ARMv7Assembler::ConditionLS,
137         // If either operand is NaN, these conditions always evaluate to true.
138         DoubleEqualOrUnordered = ARMv7Assembler::ConditionVS, // Not the right flag! check for this & handle differently.
139         DoubleNotEqualOrUnordered = ARMv7Assembler::ConditionNE,
140         DoubleGreaterThanOrUnordered = ARMv7Assembler::ConditionHI,
141         DoubleGreaterThanOrEqualOrUnordered = ARMv7Assembler::ConditionHS,
142         DoubleLessThanOrUnordered = ARMv7Assembler::ConditionLT,
143         DoubleLessThanOrEqualOrUnordered = ARMv7Assembler::ConditionLE,
144     };
145
146     static const RegisterID stackPointerRegister = ARMRegisters::sp;
147     static const RegisterID framePointerRegister = ARMRegisters::fp;
148     static const RegisterID linkRegister = ARMRegisters::lr;
149
150     // Integer arithmetic operations:
151     //
152     // Operations are typically two operand - operation(source, srcDst)
153     // For many operations the source may be an TrustedImm32, the srcDst operand
154     // may often be a memory location (explictly described using an Address
155     // object).
156
157     void add32(RegisterID src, RegisterID dest)
158     {
159         m_assembler.add(dest, dest, src);
160     }
161
162     void add32(RegisterID left, RegisterID right, RegisterID dest)
163     {
164         m_assembler.add(dest, left, right);
165     }
166
167     void add32(TrustedImm32 imm, RegisterID dest)
168     {
169         add32(imm, dest, dest);
170     }
171     
172     void add32(AbsoluteAddress src, RegisterID dest)
173     {
174         load32(src.m_ptr, dataTempRegister);
175         add32(dataTempRegister, dest);
176     }
177
178     void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
179     {
180         // For adds with stack pointer destination avoid unpredictable instruction
181         if (dest == ARMRegisters::sp && src != dest) {
182             add32(imm, src, dataTempRegister);
183             move(dataTempRegister, dest);
184             return;
185         }
186
187         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
188
189         if (armImm.isValid())
190             m_assembler.add(dest, src, armImm);
191         else {
192             move(imm, dataTempRegister);
193             m_assembler.add(dest, src, dataTempRegister);
194         }
195     }
196
197     void add32(TrustedImm32 imm, Address address)
198     {
199         load32(address, dataTempRegister);
200
201         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
202         if (armImm.isValid())
203             m_assembler.add(dataTempRegister, dataTempRegister, armImm);
204         else {
205             // Hrrrm, since dataTempRegister holds the data loaded,
206             // use addressTempRegister to hold the immediate.
207             move(imm, addressTempRegister);
208             m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister);
209         }
210
211         store32(dataTempRegister, address);
212     }
213
214     void add32(Address src, RegisterID dest)
215     {
216         load32(src, dataTempRegister);
217         add32(dataTempRegister, dest);
218     }
219
220     void add32(TrustedImm32 imm, AbsoluteAddress address)
221     {
222         load32(address.m_ptr, dataTempRegister);
223
224         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
225         if (armImm.isValid())
226             m_assembler.add(dataTempRegister, dataTempRegister, armImm);
227         else {
228             // Hrrrm, since dataTempRegister holds the data loaded,
229             // use addressTempRegister to hold the immediate.
230             move(imm, addressTempRegister);
231             m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister);
232         }
233
234         store32(dataTempRegister, address.m_ptr);
235     }
236
237     void getEffectiveAddress(BaseIndex address, RegisterID dest)
238     {
239         m_assembler.lsl(addressTempRegister, address.index, static_cast<int>(address.scale));
240         m_assembler.add(dest, address.base, addressTempRegister);
241         if (address.offset)
242             add32(TrustedImm32(address.offset), dest);
243     }
244
245     void addPtrNoFlags(TrustedImm32 imm, RegisterID srcDest)
246     {
247         add32(imm, srcDest);
248     }
249     
250     void add64(TrustedImm32 imm, AbsoluteAddress address)
251     {
252         move(TrustedImmPtr(address.m_ptr), addressTempRegister);
253
254         m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(0));
255         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
256         if (armImm.isValid())
257             m_assembler.add_S(dataTempRegister, dataTempRegister, armImm);
258         else {
259             move(imm, addressTempRegister);
260             m_assembler.add_S(dataTempRegister, dataTempRegister, addressTempRegister);
261             move(TrustedImmPtr(address.m_ptr), addressTempRegister);
262         }
263         m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(0));
264
265         m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(4));
266         m_assembler.adc(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(imm.m_value >> 31));
267         m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(4));
268     }
269
270     void and16(Address src, RegisterID dest)
271     {
272         load16(src, dataTempRegister);
273         and32(dataTempRegister, dest);
274     }
275
276     void and32(RegisterID op1, RegisterID op2, RegisterID dest)
277     {
278         m_assembler.ARM_and(dest, op1, op2);
279     }
280
281     void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
282     {
283         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
284         if (armImm.isValid())
285             m_assembler.ARM_and(dest, src, armImm);
286         else {
287             move(imm, dataTempRegister);
288             m_assembler.ARM_and(dest, src, dataTempRegister);
289         }
290     }
291
292     void and32(RegisterID src, RegisterID dest)
293     {
294         and32(dest, src, dest);
295     }
296
297     void and32(TrustedImm32 imm, RegisterID dest)
298     {
299         and32(imm, dest, dest);
300     }
301
302     void and32(Address src, RegisterID dest)
303     {
304         load32(src, dataTempRegister);
305         and32(dataTempRegister, dest);
306     }
307
308     void countLeadingZeros32(RegisterID src, RegisterID dest)
309     {
310         m_assembler.clz(dest, src);
311     }
312
313     void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
314     {
315         // Clamp the shift to the range 0..31
316         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
317         ASSERT(armImm.isValid());
318         m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
319
320         m_assembler.lsl(dest, src, dataTempRegister);
321     }
322
323     void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
324     {
325         m_assembler.lsl(dest, src, imm.m_value & 0x1f);
326     }
327
328     void lshift32(RegisterID shiftAmount, RegisterID dest)
329     {
330         lshift32(dest, shiftAmount, dest);
331     }
332
333     void lshift32(TrustedImm32 imm, RegisterID dest)
334     {
335         lshift32(dest, imm, dest);
336     }
337
338     void mul32(RegisterID src, RegisterID dest)
339     {
340         m_assembler.smull(dest, dataTempRegister, dest, src);
341     }
342
343     void mul32(RegisterID left, RegisterID right, RegisterID dest)
344     {
345         m_assembler.smull(dest, dataTempRegister, left, right);
346     }
347
348     void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
349     {
350         move(imm, dataTempRegister);
351         m_assembler.smull(dest, dataTempRegister, src, dataTempRegister);
352     }
353
354     void neg32(RegisterID srcDest)
355     {
356         m_assembler.neg(srcDest, srcDest);
357     }
358
359     void neg32(RegisterID src, RegisterID dest)
360     {
361         m_assembler.neg(dest, src);
362     }
363
364     void or32(RegisterID src, RegisterID dest)
365     {
366         m_assembler.orr(dest, dest, src);
367     }
368     
369     void or32(RegisterID src, AbsoluteAddress dest)
370     {
371         move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
372         load32(addressTempRegister, dataTempRegister);
373         or32(src, dataTempRegister);
374         store32(dataTempRegister, addressTempRegister);
375     }
376
377     void or32(TrustedImm32 imm, AbsoluteAddress address)
378     {
379         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
380         if (armImm.isValid()) {
381             move(TrustedImmPtr(address.m_ptr), addressTempRegister);
382             load32(addressTempRegister, dataTempRegister);
383             m_assembler.orr(dataTempRegister, dataTempRegister, armImm);
384             store32(dataTempRegister, addressTempRegister);
385         } else {
386             move(TrustedImmPtr(address.m_ptr), addressTempRegister);
387             load32(addressTempRegister, dataTempRegister);
388             move(imm, addressTempRegister);
389             m_assembler.orr(dataTempRegister, dataTempRegister, addressTempRegister);
390             move(TrustedImmPtr(address.m_ptr), addressTempRegister);
391             store32(dataTempRegister, addressTempRegister);
392         }
393     }
394
395     void or32(TrustedImm32 imm, Address address)
396     {
397         load32(address, dataTempRegister);
398         or32(imm, dataTempRegister, dataTempRegister);
399         store32(dataTempRegister, address);
400     }
401
402     void or32(TrustedImm32 imm, RegisterID dest)
403     {
404         or32(imm, dest, dest);
405     }
406
407     void or32(RegisterID op1, RegisterID op2, RegisterID dest)
408     {
409         m_assembler.orr(dest, op1, op2);
410     }
411
412     void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
413     {
414         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
415         if (armImm.isValid())
416             m_assembler.orr(dest, src, armImm);
417         else {
418             ASSERT(src != dataTempRegister);
419             move(imm, dataTempRegister);
420             m_assembler.orr(dest, src, dataTempRegister);
421         }
422     }
423
424     void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
425     {
426         // Clamp the shift to the range 0..31
427         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
428         ASSERT(armImm.isValid());
429         m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
430
431         m_assembler.asr(dest, src, dataTempRegister);
432     }
433
434     void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
435     {
436         if (!imm.m_value)
437             move(src, dest);
438         else
439             m_assembler.asr(dest, src, imm.m_value & 0x1f);
440     }
441
442     void rshift32(RegisterID shiftAmount, RegisterID dest)
443     {
444         rshift32(dest, shiftAmount, dest);
445     }
446     
447     void rshift32(TrustedImm32 imm, RegisterID dest)
448     {
449         rshift32(dest, imm, dest);
450     }
451
452     void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
453     {
454         // Clamp the shift to the range 0..31
455         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
456         ASSERT(armImm.isValid());
457         m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
458         
459         m_assembler.lsr(dest, src, dataTempRegister);
460     }
461     
462     void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
463     {
464         if (!imm.m_value)
465             move(src, dest);
466         else
467             m_assembler.lsr(dest, src, imm.m_value & 0x1f);
468     }
469
470     void urshift32(RegisterID shiftAmount, RegisterID dest)
471     {
472         urshift32(dest, shiftAmount, dest);
473     }
474     
475     void urshift32(TrustedImm32 imm, RegisterID dest)
476     {
477         urshift32(dest, imm, dest);
478     }
479
480     void sub32(RegisterID src, RegisterID dest)
481     {
482         m_assembler.sub(dest, dest, src);
483     }
484
485     void sub32(RegisterID left, RegisterID right, RegisterID dest)
486     {
487         m_assembler.sub(dest, left, right);
488     }
489
490     void sub32(TrustedImm32 imm, RegisterID dest)
491     {
492         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
493         if (armImm.isValid())
494             m_assembler.sub(dest, dest, armImm);
495         else {
496             move(imm, dataTempRegister);
497             m_assembler.sub(dest, dest, dataTempRegister);
498         }
499     }
500
501     void sub32(TrustedImm32 imm, Address address)
502     {
503         load32(address, dataTempRegister);
504
505         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
506         if (armImm.isValid())
507             m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
508         else {
509             // Hrrrm, since dataTempRegister holds the data loaded,
510             // use addressTempRegister to hold the immediate.
511             move(imm, addressTempRegister);
512             m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
513         }
514
515         store32(dataTempRegister, address);
516     }
517
518     void sub32(Address src, RegisterID dest)
519     {
520         load32(src, dataTempRegister);
521         sub32(dataTempRegister, dest);
522     }
523
524     void sub32(TrustedImm32 imm, AbsoluteAddress address)
525     {
526         load32(address.m_ptr, dataTempRegister);
527
528         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
529         if (armImm.isValid())
530             m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
531         else {
532             // Hrrrm, since dataTempRegister holds the data loaded,
533             // use addressTempRegister to hold the immediate.
534             move(imm, addressTempRegister);
535             m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
536         }
537
538         store32(dataTempRegister, address.m_ptr);
539     }
540
541     void xor32(RegisterID op1, RegisterID op2, RegisterID dest)
542     {
543         m_assembler.eor(dest, op1, op2);
544     }
545
546     void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
547     {
548         if (imm.m_value == -1) {
549             m_assembler.mvn(dest, src);
550             return;
551         }
552
553         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
554         if (armImm.isValid())
555             m_assembler.eor(dest, src, armImm);
556         else {
557             move(imm, dataTempRegister);
558             m_assembler.eor(dest, src, dataTempRegister);
559         }
560     }
561
562     void xor32(RegisterID src, RegisterID dest)
563     {
564         xor32(dest, src, dest);
565     }
566
567     void xor32(Address src, RegisterID dest)
568     {
569         load32(src, dataTempRegister);
570         xor32(dataTempRegister, dest);
571     }
572
573     void xor32(TrustedImm32 imm, RegisterID dest)
574     {
575         if (imm.m_value == -1)
576             m_assembler.mvn(dest, dest);
577         else
578             xor32(imm, dest, dest);
579     }
580     
581     void not32(RegisterID srcDest)
582     {
583         m_assembler.mvn(srcDest, srcDest);
584     }
585
586     // Memory access operations:
587     //
588     // Loads are of the form load(address, destination) and stores of the form
589     // store(source, address).  The source for a store may be an TrustedImm32.  Address
590     // operand objects to loads and store will be implicitly constructed if a
591     // register is passed.
592
593 private:
594     void load32(ArmAddress address, RegisterID dest)
595     {
596         if (address.type == ArmAddress::HasIndex)
597             m_assembler.ldr(dest, address.base, address.u.index, address.u.scale);
598         else if (address.u.offset >= 0) {
599             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
600             ASSERT(armImm.isValid());
601             m_assembler.ldr(dest, address.base, armImm);
602         } else {
603             ASSERT(address.u.offset >= -255);
604             m_assembler.ldr(dest, address.base, address.u.offset, true, false);
605         }
606     }
607
608     void load16(ArmAddress address, RegisterID dest)
609     {
610         if (address.type == ArmAddress::HasIndex)
611             m_assembler.ldrh(dest, address.base, address.u.index, address.u.scale);
612         else if (address.u.offset >= 0) {
613             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
614             ASSERT(armImm.isValid());
615             m_assembler.ldrh(dest, address.base, armImm);
616         } else {
617             ASSERT(address.u.offset >= -255);
618             m_assembler.ldrh(dest, address.base, address.u.offset, true, false);
619         }
620     }
621     
622     void load16SignedExtendTo32(ArmAddress address, RegisterID dest)
623     {
624         ASSERT(address.type == ArmAddress::HasIndex);
625         m_assembler.ldrsh(dest, address.base, address.u.index, address.u.scale);
626     }
627
628     void load8(ArmAddress address, RegisterID dest)
629     {
630         if (address.type == ArmAddress::HasIndex)
631             m_assembler.ldrb(dest, address.base, address.u.index, address.u.scale);
632         else if (address.u.offset >= 0) {
633             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
634             ASSERT(armImm.isValid());
635             m_assembler.ldrb(dest, address.base, armImm);
636         } else {
637             ASSERT(address.u.offset >= -255);
638             m_assembler.ldrb(dest, address.base, address.u.offset, true, false);
639         }
640     }
641     
642     void load8SignedExtendTo32(ArmAddress address, RegisterID dest)
643     {
644         ASSERT(address.type == ArmAddress::HasIndex);
645         m_assembler.ldrsb(dest, address.base, address.u.index, address.u.scale);
646     }
647
648 protected:
649     void store32(RegisterID src, ArmAddress address)
650     {
651         if (address.type == ArmAddress::HasIndex)
652             m_assembler.str(src, address.base, address.u.index, address.u.scale);
653         else if (address.u.offset >= 0) {
654             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
655             ASSERT(armImm.isValid());
656             m_assembler.str(src, address.base, armImm);
657         } else {
658             ASSERT(address.u.offset >= -255);
659             m_assembler.str(src, address.base, address.u.offset, true, false);
660         }
661     }
662
663 private:
664     void store8(RegisterID src, ArmAddress address)
665     {
666         if (address.type == ArmAddress::HasIndex)
667             m_assembler.strb(src, address.base, address.u.index, address.u.scale);
668         else if (address.u.offset >= 0) {
669             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
670             ASSERT(armImm.isValid());
671             m_assembler.strb(src, address.base, armImm);
672         } else {
673             ASSERT(address.u.offset >= -255);
674             m_assembler.strb(src, address.base, address.u.offset, true, false);
675         }
676     }
677     
678     void store16(RegisterID src, ArmAddress address)
679     {
680         if (address.type == ArmAddress::HasIndex)
681             m_assembler.strh(src, address.base, address.u.index, address.u.scale);
682         else if (address.u.offset >= 0) {
683             ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
684             ASSERT(armImm.isValid());
685             m_assembler.strh(src, address.base, armImm);
686         } else {
687             ASSERT(address.u.offset >= -255);
688             m_assembler.strh(src, address.base, address.u.offset, true, false);
689         }
690     }
691
692 public:
693     void load32(ImplicitAddress address, RegisterID dest)
694     {
695         load32(setupArmAddress(address), dest);
696     }
697
698     void load32(BaseIndex address, RegisterID dest)
699     {
700         load32(setupArmAddress(address), dest);
701     }
702
703     void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
704     {
705         load32(setupArmAddress(address), dest);
706     }
707
708     void load16Unaligned(BaseIndex address, RegisterID dest)
709     {
710         load16(setupArmAddress(address), dest);
711     }
712
713     void load32(const void* address, RegisterID dest)
714     {
715         move(TrustedImmPtr(address), addressTempRegister);
716         m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
717     }
718     
719     void abortWithReason(AbortReason reason)
720     {
721         move(TrustedImm32(reason), dataTempRegister);
722         breakpoint();
723     }
724
725     void abortWithReason(AbortReason reason, intptr_t misc)
726     {
727         move(TrustedImm32(misc), addressTempRegister);
728         abortWithReason(reason);
729     }
730
731     ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
732     {
733         ConvertibleLoadLabel result(this);
734         ASSERT(address.offset >= 0 && address.offset <= 255);
735         m_assembler.ldrWide8BitImmediate(dest, address.base, address.offset);
736         return result;
737     }
738
739     void load8(ImplicitAddress address, RegisterID dest)
740     {
741         load8(setupArmAddress(address), dest);
742     }
743
744     void load8SignedExtendTo32(ImplicitAddress, RegisterID)
745     {
746         UNREACHABLE_FOR_PLATFORM();
747     }
748
749     void load8(BaseIndex address, RegisterID dest)
750     {
751         load8(setupArmAddress(address), dest);
752     }
753     
754     void load8SignedExtendTo32(BaseIndex address, RegisterID dest)
755     {
756         load8SignedExtendTo32(setupArmAddress(address), dest);
757     }
758
759     void load8(const void* address, RegisterID dest)
760     {
761         move(TrustedImmPtr(address), dest);
762         load8(dest, dest);
763     }
764
765     DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
766     {
767         DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
768         load32(ArmAddress(address.base, dataTempRegister), dest);
769         return label;
770     }
771     
772     DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
773     {
774         padBeforePatch();
775
776         RegisterID base = address.base;
777         
778         DataLabelCompact label(this);
779         ASSERT(isCompactPtrAlignedAddressOffset(address.offset));
780
781         m_assembler.ldr(dest, base, address.offset, true, false);
782         return label;
783     }
784
785     void load16(BaseIndex address, RegisterID dest)
786     {
787         m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale);
788     }
789     
790     void load16SignedExtendTo32(BaseIndex address, RegisterID dest)
791     {
792         load16SignedExtendTo32(setupArmAddress(address), dest);
793     }
794     
795     void load16(ImplicitAddress address, RegisterID dest)
796     {
797         ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.offset);
798         if (armImm.isValid())
799             m_assembler.ldrh(dest, address.base, armImm);
800         else {
801             move(TrustedImm32(address.offset), dataTempRegister);
802             m_assembler.ldrh(dest, address.base, dataTempRegister);
803         }
804     }
805     
806     void load16SignedExtendTo32(ImplicitAddress, RegisterID)
807     {
808         UNREACHABLE_FOR_PLATFORM();
809     }
810
811     DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
812     {
813         DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
814         store32(src, ArmAddress(address.base, dataTempRegister));
815         return label;
816     }
817
818     void store32(RegisterID src, ImplicitAddress address)
819     {
820         store32(src, setupArmAddress(address));
821     }
822
823     void store32(RegisterID src, BaseIndex address)
824     {
825         store32(src, setupArmAddress(address));
826     }
827
828     void store32(TrustedImm32 imm, ImplicitAddress address)
829     {
830         move(imm, dataTempRegister);
831         store32(dataTempRegister, setupArmAddress(address));
832     }
833
834     void store32(TrustedImm32 imm, BaseIndex address)
835     {
836         move(imm, dataTempRegister);
837         store32(dataTempRegister, setupArmAddress(address));
838     }
839
840     void store32(RegisterID src, const void* address)
841     {
842         move(TrustedImmPtr(address), addressTempRegister);
843         m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
844     }
845
846     void store32(TrustedImm32 imm, const void* address)
847     {
848         move(imm, dataTempRegister);
849         store32(dataTempRegister, address);
850     }
851
852     void store8(RegisterID src, Address address)
853     {
854         store8(src, setupArmAddress(address));
855     }
856     
857     void store8(RegisterID src, BaseIndex address)
858     {
859         store8(src, setupArmAddress(address));
860     }
861     
862     void store8(RegisterID src, void* address)
863     {
864         move(TrustedImmPtr(address), addressTempRegister);
865         store8(src, ArmAddress(addressTempRegister, 0));
866     }
867     
868     void store8(TrustedImm32 imm, void* address)
869     {
870         TrustedImm32 imm8(static_cast<int8_t>(imm.m_value));
871         move(imm8, dataTempRegister);
872         store8(dataTempRegister, address);
873     }
874     
875     void store8(TrustedImm32 imm, Address address)
876     {
877         TrustedImm32 imm8(static_cast<int8_t>(imm.m_value));
878         move(imm8, dataTempRegister);
879         store8(dataTempRegister, address);
880     }
881
882     void store16(RegisterID src, ImplicitAddress address)
883     {
884         store16(src, setupArmAddress(address));
885     }
886
887     void store16(RegisterID src, BaseIndex address)
888     {
889         store16(src, setupArmAddress(address));
890     }
891
892     // Possibly clobbers src, but not on this architecture.
893     void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2)
894     {
895         m_assembler.vmov(dest1, dest2, src);
896     }
897     
898     void moveIntsToDouble(RegisterID src1, RegisterID src2, FPRegisterID dest, FPRegisterID scratch)
899     {
900         UNUSED_PARAM(scratch);
901         m_assembler.vmov(dest, src1, src2);
902     }
903
904     static bool shouldBlindForSpecificArch(uint32_t value)
905     {
906         ARMThumbImmediate immediate = ARMThumbImmediate::makeEncodedImm(value);
907
908         // Couldn't be encoded as an immediate, so assume it's untrusted.
909         if (!immediate.isValid())
910             return true;
911         
912         // If we can encode the immediate, we have less than 16 attacker
913         // controlled bits.
914         if (immediate.isEncodedImm())
915             return false;
916
917         // Don't let any more than 12 bits of an instruction word
918         // be controlled by an attacker.
919         return !immediate.isUInt12();
920     }
921
922     // Floating-point operations:
923
924     static bool supportsFloatingPoint() { return true; }
925     static bool supportsFloatingPointTruncate() { return true; }
926     static bool supportsFloatingPointSqrt() { return true; }
927     static bool supportsFloatingPointAbs() { return true; }
928     static bool supportsFloatingPointRounding() { return false; }
929
930     void loadDouble(ImplicitAddress address, FPRegisterID dest)
931     {
932         RegisterID base = address.base;
933         int32_t offset = address.offset;
934
935         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
936         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
937             add32(TrustedImm32(offset), base, addressTempRegister);
938             base = addressTempRegister;
939             offset = 0;
940         }
941         
942         m_assembler.vldr(dest, base, offset);
943     }
944
945     void loadFloat(ImplicitAddress address, FPRegisterID dest)
946     {
947         RegisterID base = address.base;
948         int32_t offset = address.offset;
949
950         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
951         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
952             add32(TrustedImm32(offset), base, addressTempRegister);
953             base = addressTempRegister;
954             offset = 0;
955         }
956         
957         m_assembler.flds(ARMRegisters::asSingle(dest), base, offset);
958     }
959
960     void loadDouble(BaseIndex address, FPRegisterID dest)
961     {
962         move(address.index, addressTempRegister);
963         lshift32(TrustedImm32(address.scale), addressTempRegister);
964         add32(address.base, addressTempRegister);
965         loadDouble(Address(addressTempRegister, address.offset), dest);
966     }
967     
968     void loadFloat(BaseIndex address, FPRegisterID dest)
969     {
970         move(address.index, addressTempRegister);
971         lshift32(TrustedImm32(address.scale), addressTempRegister);
972         add32(address.base, addressTempRegister);
973         loadFloat(Address(addressTempRegister, address.offset), dest);
974     }
975
976     void moveDouble(FPRegisterID src, FPRegisterID dest)
977     {
978         if (src != dest)
979             m_assembler.vmov(dest, src);
980     }
981
982     void moveDouble(FPRegisterID src, RegisterID dest)
983     {
984         m_assembler.vmov(dest, RegisterID(dest + 1), src);
985     }
986
987     void moveZeroToDouble(FPRegisterID reg)
988     {
989         static double zeroConstant = 0.;
990         loadDouble(TrustedImmPtr(&zeroConstant), reg);
991     }
992
993     void loadDouble(TrustedImmPtr address, FPRegisterID dest)
994     {
995         move(address, addressTempRegister);
996         m_assembler.vldr(dest, addressTempRegister, 0);
997     }
998
999     void storeDouble(FPRegisterID src, ImplicitAddress address)
1000     {
1001         RegisterID base = address.base;
1002         int32_t offset = address.offset;
1003
1004         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
1005         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
1006             add32(TrustedImm32(offset), base, addressTempRegister);
1007             base = addressTempRegister;
1008             offset = 0;
1009         }
1010         
1011         m_assembler.vstr(src, base, offset);
1012     }
1013
1014     void storeFloat(FPRegisterID src, ImplicitAddress address)
1015     {
1016         RegisterID base = address.base;
1017         int32_t offset = address.offset;
1018
1019         // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
1020         if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
1021             add32(TrustedImm32(offset), base, addressTempRegister);
1022             base = addressTempRegister;
1023             offset = 0;
1024         }
1025         
1026         m_assembler.fsts(ARMRegisters::asSingle(src), base, offset);
1027     }
1028
1029     void storeDouble(FPRegisterID src, TrustedImmPtr address)
1030     {
1031         move(address, addressTempRegister);
1032         storeDouble(src, addressTempRegister);
1033     }
1034
1035     void storeDouble(FPRegisterID src, BaseIndex address)
1036     {
1037         move(address.index, addressTempRegister);
1038         lshift32(TrustedImm32(address.scale), addressTempRegister);
1039         add32(address.base, addressTempRegister);
1040         storeDouble(src, Address(addressTempRegister, address.offset));
1041     }
1042     
1043     void storeFloat(FPRegisterID src, BaseIndex address)
1044     {
1045         move(address.index, addressTempRegister);
1046         lshift32(TrustedImm32(address.scale), addressTempRegister);
1047         add32(address.base, addressTempRegister);
1048         storeFloat(src, Address(addressTempRegister, address.offset));
1049     }
1050     
1051     void addDouble(FPRegisterID src, FPRegisterID dest)
1052     {
1053         m_assembler.vadd(dest, dest, src);
1054     }
1055
1056     void addDouble(Address src, FPRegisterID dest)
1057     {
1058         loadDouble(src, fpTempRegister);
1059         addDouble(fpTempRegister, dest);
1060     }
1061
1062     void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1063     {
1064         m_assembler.vadd(dest, op1, op2);
1065     }
1066
1067     void addDouble(AbsoluteAddress address, FPRegisterID dest)
1068     {
1069         loadDouble(TrustedImmPtr(address.m_ptr), fpTempRegister);
1070         m_assembler.vadd(dest, dest, fpTempRegister);
1071     }
1072
1073     void divDouble(FPRegisterID src, FPRegisterID dest)
1074     {
1075         m_assembler.vdiv(dest, dest, src);
1076     }
1077
1078     void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1079     {
1080         m_assembler.vdiv(dest, op1, op2);
1081     }
1082
1083     void subDouble(FPRegisterID src, FPRegisterID dest)
1084     {
1085         m_assembler.vsub(dest, dest, src);
1086     }
1087
1088     void subDouble(Address src, FPRegisterID dest)
1089     {
1090         loadDouble(src, fpTempRegister);
1091         subDouble(fpTempRegister, dest);
1092     }
1093
1094     void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1095     {
1096         m_assembler.vsub(dest, op1, op2);
1097     }
1098
1099     void mulDouble(FPRegisterID src, FPRegisterID dest)
1100     {
1101         m_assembler.vmul(dest, dest, src);
1102     }
1103
1104     void mulDouble(Address src, FPRegisterID dest)
1105     {
1106         loadDouble(src, fpTempRegister);
1107         mulDouble(fpTempRegister, dest);
1108     }
1109
1110     void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1111     {
1112         m_assembler.vmul(dest, op1, op2);
1113     }
1114
1115     void sqrtDouble(FPRegisterID src, FPRegisterID dest)
1116     {
1117         m_assembler.vsqrt(dest, src);
1118     }
1119     
1120     void absDouble(FPRegisterID src, FPRegisterID dest)
1121     {
1122         m_assembler.vabs(dest, src);
1123     }
1124
1125     void negateDouble(FPRegisterID src, FPRegisterID dest)
1126     {
1127         m_assembler.vneg(dest, src);
1128     }
1129
1130     NO_RETURN_DUE_TO_CRASH void ceilDouble(FPRegisterID, FPRegisterID)
1131     {
1132         ASSERT(!supportsFloatingPointRounding());
1133         CRASH();
1134     }
1135
1136     NO_RETURN_DUE_TO_CRASH void floorDouble(FPRegisterID, FPRegisterID)
1137     {
1138         ASSERT(!supportsFloatingPointRounding());
1139         CRASH();
1140     }
1141
1142     NO_RETURN_DUE_TO_CRASH void roundTowardZeroDouble(FPRegisterID, FPRegisterID)
1143     {
1144         ASSERT(!supportsFloatingPointRounding());
1145         CRASH();
1146     }
1147
1148     void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
1149     {
1150         m_assembler.vmov(fpTempRegister, src, src);
1151         m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
1152     }
1153
1154     void convertInt32ToDouble(Address address, FPRegisterID dest)
1155     {
1156         // Fixme: load directly into the fpr!
1157         load32(address, dataTempRegister);
1158         m_assembler.vmov(fpTempRegister, dataTempRegister, dataTempRegister);
1159         m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
1160     }
1161
1162     void convertInt32ToDouble(AbsoluteAddress address, FPRegisterID dest)
1163     {
1164         // Fixme: load directly into the fpr!
1165         load32(address.m_ptr, dataTempRegister);
1166         m_assembler.vmov(fpTempRegister, dataTempRegister, dataTempRegister);
1167         m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
1168     }
1169     
1170     void convertFloatToDouble(FPRegisterID src, FPRegisterID dst)
1171     {
1172         m_assembler.vcvtds(dst, ARMRegisters::asSingle(src));
1173     }
1174     
1175     void convertDoubleToFloat(FPRegisterID src, FPRegisterID dst)
1176     {
1177         m_assembler.vcvtsd(ARMRegisters::asSingle(dst), src);
1178     }
1179
1180     Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
1181     {
1182         m_assembler.vcmp(left, right);
1183         m_assembler.vmrs();
1184
1185         if (cond == DoubleNotEqual) {
1186             // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump.
1187             Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1188             Jump result = makeBranch(ARMv7Assembler::ConditionNE);
1189             unordered.link(this);
1190             return result;
1191         }
1192         if (cond == DoubleEqualOrUnordered) {
1193             Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1194             Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
1195             unordered.link(this);
1196             // We get here if either unordered or equal.
1197             Jump result = jump();
1198             notEqual.link(this);
1199             return result;
1200         }
1201         return makeBranch(cond);
1202     }
1203
1204     enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
1205     Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
1206     {
1207         // Convert into dest.
1208         m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1209         m_assembler.vmov(dest, fpTempRegisterAsSingle());
1210
1211         // Calculate 2x dest.  If the value potentially underflowed, it will have
1212         // clamped to 0x80000000, so 2x dest is zero in this case. In the case of
1213         // overflow the result will be equal to -2.
1214         Jump underflow = branchAdd32(Zero, dest, dest, dataTempRegister);
1215         Jump noOverflow = branch32(NotEqual, dataTempRegister, TrustedImm32(-2));
1216
1217         // For BranchIfTruncateSuccessful, we branch if 'noOverflow' jumps.
1218         underflow.link(this);
1219         if (branchType == BranchIfTruncateSuccessful)
1220             return noOverflow;
1221
1222         // We'll reach the current point in the code on failure, so plant a
1223         // jump here & link the success case.
1224         Jump failure = jump();
1225         noOverflow.link(this);
1226         return failure;
1227     }
1228
1229     // Result is undefined if the value is outside of the integer range.
1230     void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
1231     {
1232         m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1233         m_assembler.vmov(dest, fpTempRegisterAsSingle());
1234     }
1235
1236     void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
1237     {
1238         m_assembler.vcvt_floatingPointToUnsigned(fpTempRegisterAsSingle(), src);
1239         m_assembler.vmov(dest, fpTempRegisterAsSingle());
1240     }
1241     
1242     // Convert 'src' to an integer, and places the resulting 'dest'.
1243     // If the result is not representable as a 32 bit value, branch.
1244     // May also branch for some values that are representable in 32 bits
1245     // (specifically, in this case, 0).
1246     void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID, bool negZeroCheck = true)
1247     {
1248         m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1249         m_assembler.vmov(dest, fpTempRegisterAsSingle());
1250
1251         // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
1252         m_assembler.vcvt_signedToFloatingPoint(fpTempRegister, fpTempRegisterAsSingle());
1253         failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, fpTempRegister));
1254
1255         // Test for negative zero.
1256         if (negZeroCheck) {
1257             Jump valueIsNonZero = branchTest32(NonZero, dest);
1258             m_assembler.vmov(dataTempRegister, ARMRegisters::asSingleUpper(src));
1259             failureCases.append(branch32(LessThan, dataTempRegister, TrustedImm32(0)));
1260             valueIsNonZero.link(this);
1261         }
1262     }
1263
1264     Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID)
1265     {
1266         m_assembler.vcmpz(reg);
1267         m_assembler.vmrs();
1268         Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1269         Jump result = makeBranch(ARMv7Assembler::ConditionNE);
1270         unordered.link(this);
1271         return result;
1272     }
1273
1274     Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID)
1275     {
1276         m_assembler.vcmpz(reg);
1277         m_assembler.vmrs();
1278         Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1279         Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
1280         unordered.link(this);
1281         // We get here if either unordered or equal.
1282         Jump result = jump();
1283         notEqual.link(this);
1284         return result;
1285     }
1286
1287     // Stack manipulation operations:
1288     //
1289     // The ABI is assumed to provide a stack abstraction to memory,
1290     // containing machine word sized units of data.  Push and pop
1291     // operations add and remove a single register sized unit of data
1292     // to or from the stack.  Peek and poke operations read or write
1293     // values on the stack, without moving the current stack position.
1294     
1295     void pop(RegisterID dest)
1296     {
1297         m_assembler.pop(dest);
1298     }
1299
1300     void push(RegisterID src)
1301     {
1302         m_assembler.push(src);
1303     }
1304
1305     void push(Address address)
1306     {
1307         load32(address, dataTempRegister);
1308         push(dataTempRegister);
1309     }
1310
1311     void push(TrustedImm32 imm)
1312     {
1313         move(imm, dataTempRegister);
1314         push(dataTempRegister);
1315     }
1316
1317     void popPair(RegisterID dest1, RegisterID dest2)
1318     {
1319         m_assembler.pop(1 << dest1 | 1 << dest2);
1320     }
1321     
1322     void pushPair(RegisterID src1, RegisterID src2)
1323     {
1324         m_assembler.push(1 << src1 | 1 << src2);
1325     }
1326     
1327     // Register move operations:
1328     //
1329     // Move values in registers.
1330
1331     void move(TrustedImm32 imm, RegisterID dest)
1332     {
1333         uint32_t value = imm.m_value;
1334
1335         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(value);
1336
1337         if (armImm.isValid())
1338             m_assembler.mov(dest, armImm);
1339         else if ((armImm = ARMThumbImmediate::makeEncodedImm(~value)).isValid())
1340             m_assembler.mvn(dest, armImm);
1341         else {
1342             m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(value));
1343             if (value & 0xffff0000)
1344                 m_assembler.movt(dest, ARMThumbImmediate::makeUInt16(value >> 16));
1345         }
1346     }
1347
1348     void move(RegisterID src, RegisterID dest)
1349     {
1350         if (src != dest)
1351             m_assembler.mov(dest, src);
1352     }
1353
1354     void move(TrustedImmPtr imm, RegisterID dest)
1355     {
1356         move(TrustedImm32(imm), dest);
1357     }
1358
1359     void swap(RegisterID reg1, RegisterID reg2)
1360     {
1361         move(reg1, dataTempRegister);
1362         move(reg2, reg1);
1363         move(dataTempRegister, reg2);
1364     }
1365
1366     void swap(FPRegisterID fr1, FPRegisterID fr2)
1367     {
1368         moveDouble(fr1, fpTempRegister);
1369         moveDouble(fr2, fr1);
1370         moveDouble(fpTempRegister, fr2);
1371     }
1372
1373     void signExtend32ToPtr(RegisterID src, RegisterID dest)
1374     {
1375         move(src, dest);
1376     }
1377
1378     void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
1379     {
1380         move(src, dest);
1381     }
1382
1383     // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
1384     static RelationalCondition invert(RelationalCondition cond)
1385     {
1386         return static_cast<RelationalCondition>(cond ^ 1);
1387     }
1388
1389     void nop()
1390     {
1391         m_assembler.nop();
1392     }
1393     
1394     void memoryFence()
1395     {
1396         m_assembler.dmbSY();
1397     }
1398     
1399     void storeFence()
1400     {
1401         m_assembler.dmbISHST();
1402     }
1403
1404     template<PtrTag startTag, PtrTag destTag>
1405     static void replaceWithJump(CodeLocationLabel<startTag> instructionStart, CodeLocationLabel<destTag> destination)
1406     {
1407         ARMv7Assembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
1408     }
1409     
1410     static ptrdiff_t maxJumpReplacementSize()
1411     {
1412         return ARMv7Assembler::maxJumpReplacementSize();
1413     }
1414
1415     static ptrdiff_t patchableJumpSize()
1416     {
1417         return ARMv7Assembler::patchableJumpSize();
1418     }
1419
1420     // Forwards / external control flow operations:
1421     //
1422     // This set of jump and conditional branch operations return a Jump
1423     // object which may linked at a later point, allow forwards jump,
1424     // or jumps that will require external linkage (after the code has been
1425     // relocated).
1426     //
1427     // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
1428     // respecitvely, for unsigned comparisons the names b, a, be, and ae are
1429     // used (representing the names 'below' and 'above').
1430     //
1431     // Operands to the comparision are provided in the expected order, e.g.
1432     // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
1433     // treated as a signed 32bit value, is less than or equal to 5.
1434     //
1435     // jz and jnz test whether the first operand is equal to zero, and take
1436     // an optional second operand of a mask under which to perform the test.
1437 private:
1438
1439     // Should we be using TEQ for equal/not-equal?
1440     void compare32AndSetFlags(RegisterID left, TrustedImm32 right)
1441     {
1442         int32_t imm = right.m_value;
1443         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
1444         if (armImm.isValid())
1445             m_assembler.cmp(left, armImm);
1446         else if ((armImm = ARMThumbImmediate::makeEncodedImm(-imm)).isValid())
1447             m_assembler.cmn(left, armImm);
1448         else {
1449             move(TrustedImm32(imm), dataTempRegister);
1450             m_assembler.cmp(left, dataTempRegister);
1451         }
1452     }
1453
1454 public:
1455     void test32(RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1456     {
1457         int32_t imm = mask.m_value;
1458
1459         if (imm == -1)
1460             m_assembler.tst(reg, reg);
1461         else {
1462             ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
1463             if (armImm.isValid()) {
1464                 if (reg == ARMRegisters::sp) {
1465                     move(reg, addressTempRegister);
1466                     m_assembler.tst(addressTempRegister, armImm);
1467                 } else
1468                     m_assembler.tst(reg, armImm);
1469             } else {
1470                 move(mask, dataTempRegister);
1471                 if (reg == ARMRegisters::sp) {
1472                     move(reg, addressTempRegister);
1473                     m_assembler.tst(addressTempRegister, dataTempRegister);
1474                 } else
1475                     m_assembler.tst(reg, dataTempRegister);
1476             }
1477         }
1478     }
1479     
1480     Jump branch(ResultCondition cond)
1481     {
1482         return Jump(makeBranch(cond));
1483     }
1484
1485     Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
1486     {
1487         m_assembler.cmp(left, right);
1488         return Jump(makeBranch(cond));
1489     }
1490
1491     Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1492     {
1493         compare32AndSetFlags(left, right);
1494         return Jump(makeBranch(cond));
1495     }
1496
1497     Jump branch32(RelationalCondition cond, RegisterID left, Address right)
1498     {
1499         load32(right, dataTempRegister);
1500         return branch32(cond, left, dataTempRegister);
1501     }
1502
1503     Jump branch32(RelationalCondition cond, Address left, RegisterID right)
1504     {
1505         load32(left, dataTempRegister);
1506         return branch32(cond, dataTempRegister, right);
1507     }
1508
1509     Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
1510     {
1511         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1512         load32(left, addressTempRegister);
1513         return branch32(cond, addressTempRegister, right);
1514     }
1515
1516     Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1517     {
1518         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1519         load32(left, addressTempRegister);
1520         return branch32(cond, addressTempRegister, right);
1521     }
1522
1523     Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1524     {
1525         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1526         load32WithUnalignedHalfWords(left, addressTempRegister);
1527         return branch32(cond, addressTempRegister, right);
1528     }
1529
1530     Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
1531     {
1532         load32(left.m_ptr, dataTempRegister);
1533         return branch32(cond, dataTempRegister, right);
1534     }
1535
1536     Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
1537     {
1538         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1539         load32(left.m_ptr, addressTempRegister);
1540         return branch32(cond, addressTempRegister, right);
1541     }
1542
1543     Jump branchPtr(RelationalCondition cond, BaseIndex left, RegisterID right)
1544     {
1545         load32(left, dataTempRegister);
1546         return branch32(cond, dataTempRegister, right);
1547     }
1548
1549     Jump branch8(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1550     {
1551         TrustedImm32 right8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, right);
1552         compare32AndSetFlags(left, right8);
1553         return Jump(makeBranch(cond));
1554     }
1555
1556     Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
1557     {
1558         // use addressTempRegister incase the branch8 we call uses dataTempRegister. :-/
1559         TrustedImm32 right8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, right);
1560         MacroAssemblerHelpers::load8OnCondition(*this, cond, left, addressTempRegister);
1561         return branch8(cond, addressTempRegister, right8);
1562     }
1563
1564     Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1565     {
1566         // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1567         TrustedImm32 right8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, right);
1568         MacroAssemblerHelpers::load8OnCondition(*this, cond, left, addressTempRegister);
1569         return branch32(cond, addressTempRegister, right8);
1570     }
1571     
1572     Jump branch8(RelationalCondition cond, AbsoluteAddress address, TrustedImm32 right)
1573     {
1574         // Use addressTempRegister instead of dataTempRegister, since branch32 uses dataTempRegister.
1575         TrustedImm32 right8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, right);
1576         move(TrustedImmPtr(address.m_ptr), addressTempRegister);
1577         MacroAssemblerHelpers::load8OnCondition(*this, cond, Address(addressTempRegister), addressTempRegister);
1578         return branch32(cond, addressTempRegister, right8);
1579     }
1580     
1581     Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
1582     {
1583         ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == PositiveOrZero);
1584         m_assembler.tst(reg, mask);
1585         return Jump(makeBranch(cond));
1586     }
1587
1588     Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1589     {
1590         ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == PositiveOrZero);
1591         test32(reg, mask);
1592         return Jump(makeBranch(cond));
1593     }
1594
1595     Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1596     {
1597         // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1598         load32(address, addressTempRegister);
1599         return branchTest32(cond, addressTempRegister, mask);
1600     }
1601
1602     Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1603     {
1604         // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1605         load32(address, addressTempRegister);
1606         return branchTest32(cond, addressTempRegister, mask);
1607     }
1608
1609     Jump branchTest8(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1610     {
1611         // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1612         TrustedImm32 mask8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, mask);
1613         MacroAssemblerHelpers::load8OnCondition(*this, cond, address, addressTempRegister);
1614         return branchTest32(cond, addressTempRegister, mask8);
1615     }
1616
1617     Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1618     {
1619         // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1620         TrustedImm32 mask8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, mask);
1621         MacroAssemblerHelpers::load8OnCondition(*this, cond, address, addressTempRegister);
1622         return branchTest32(cond, addressTempRegister, mask8);
1623     }
1624
1625     Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
1626     {
1627         // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1628         TrustedImm32 mask8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, mask);
1629         move(TrustedImmPtr(address.m_ptr), addressTempRegister);
1630         MacroAssemblerHelpers::load8OnCondition(*this, cond, Address(addressTempRegister), addressTempRegister);
1631         return branchTest32(cond, addressTempRegister, mask8);
1632     }
1633
1634     void farJump(RegisterID target, PtrTag)
1635     {
1636         m_assembler.bx(target);
1637     }
1638
1639     // Address is a memory location containing the address to jump to
1640     void farJump(Address address, PtrTag)
1641     {
1642         load32(address, dataTempRegister);
1643         m_assembler.bx(dataTempRegister);
1644     }
1645     
1646     void farJump(AbsoluteAddress address, PtrTag)
1647     {
1648         move(TrustedImmPtr(address.m_ptr), dataTempRegister);
1649         load32(Address(dataTempRegister), dataTempRegister);
1650         m_assembler.bx(dataTempRegister);
1651     }
1652
1653     ALWAYS_INLINE void farJump(RegisterID target, RegisterID jumpTag) { UNUSED_PARAM(jumpTag), farJump(target, NoPtrTag); }
1654     ALWAYS_INLINE void farJump(Address address, RegisterID jumpTag) { UNUSED_PARAM(jumpTag), farJump(address, NoPtrTag); }
1655     ALWAYS_INLINE void farJump(AbsoluteAddress address, RegisterID jumpTag) { UNUSED_PARAM(jumpTag), farJump(address, NoPtrTag); }
1656
1657     // Arithmetic control flow operations:
1658     //
1659     // This set of conditional branch operations branch based
1660     // on the result of an arithmetic operation.  The operation
1661     // is performed as normal, storing the result.
1662     //
1663     // * jz operations branch if the result is zero.
1664     // * jo operations branch if the (signed) arithmetic
1665     //   operation caused an overflow to occur.
1666     
1667     Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1668     {
1669         m_assembler.add_S(dest, op1, op2);
1670         return Jump(makeBranch(cond));
1671     }
1672
1673     Jump branchAdd32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
1674     {
1675         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1676         if (armImm.isValid())
1677             m_assembler.add_S(dest, op1, armImm);
1678         else {
1679             move(imm, dataTempRegister);
1680             m_assembler.add_S(dest, op1, dataTempRegister);
1681         }
1682         return Jump(makeBranch(cond));
1683     }
1684
1685     Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
1686     {
1687         return branchAdd32(cond, dest, src, dest);
1688     }
1689
1690     Jump branchAdd32(ResultCondition cond, Address src, RegisterID dest)
1691     {
1692         load32(src, dataTempRegister);
1693         return branchAdd32(cond, dest, dataTempRegister, dest);
1694     }
1695
1696     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1697     {
1698         return branchAdd32(cond, dest, imm, dest);
1699     }
1700
1701     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
1702     {
1703         // Move the high bits of the address into addressTempRegister,
1704         // and load the value into dataTempRegister.
1705         move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
1706         m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
1707
1708         // Do the add.
1709         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1710         if (armImm.isValid())
1711             m_assembler.add_S(dataTempRegister, dataTempRegister, armImm);
1712         else {
1713             // If the operand does not fit into an immediate then load it temporarily
1714             // into addressTempRegister; since we're overwriting addressTempRegister
1715             // we'll need to reload it with the high bits of the address afterwards.
1716             move(imm, addressTempRegister);
1717             m_assembler.add_S(dataTempRegister, dataTempRegister, addressTempRegister);
1718             move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
1719         }
1720
1721         // Store the result.
1722         m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
1723
1724         return Jump(makeBranch(cond));
1725     }
1726
1727     Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
1728     {
1729         m_assembler.smull(dest, dataTempRegister, src1, src2);
1730
1731         if (cond == Overflow) {
1732             m_assembler.asr(addressTempRegister, dest, 31);
1733             return branch32(NotEqual, addressTempRegister, dataTempRegister);
1734         }
1735
1736         return branchTest32(cond, dest);
1737     }
1738
1739     Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
1740     {
1741         return branchMul32(cond, src, dest, dest);
1742     }
1743
1744     Jump branchMul32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
1745     {
1746         move(imm, dataTempRegister);
1747         return branchMul32(cond, dataTempRegister, src, dest);
1748     }
1749
1750     Jump branchNeg32(ResultCondition cond, RegisterID srcDest)
1751     {
1752         ARMThumbImmediate zero = ARMThumbImmediate::makeUInt12(0);
1753         m_assembler.sub_S(srcDest, zero, srcDest);
1754         return Jump(makeBranch(cond));
1755     }
1756
1757     Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
1758     {
1759         m_assembler.orr_S(dest, dest, src);
1760         return Jump(makeBranch(cond));
1761     }
1762
1763     Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1764     {
1765         m_assembler.sub_S(dest, op1, op2);
1766         return Jump(makeBranch(cond));
1767     }
1768
1769     Jump branchSub32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
1770     {
1771         ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1772         if (armImm.isValid())
1773             m_assembler.sub_S(dest, op1, armImm);
1774         else {
1775             move(imm, dataTempRegister);
1776             m_assembler.sub_S(dest, op1, dataTempRegister);
1777         }
1778         return Jump(makeBranch(cond));
1779     }
1780     
1781     Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
1782     {
1783         return branchSub32(cond, dest, src, dest);
1784     }
1785
1786     Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1787     {
1788         return branchSub32(cond, dest, imm, dest);
1789     }
1790     
1791     void relativeTableJump(RegisterID index, int scale)
1792     {
1793         ASSERT(scale >= 0 && scale <= 31);
1794
1795         // dataTempRegister will point after the jump if index register contains zero
1796         move(ARMRegisters::pc, dataTempRegister);
1797         m_assembler.add(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(9));
1798
1799         ShiftTypeAndAmount shift(SRType_LSL, scale);
1800         m_assembler.add(dataTempRegister, dataTempRegister, index, shift);
1801         farJump(dataTempRegister, NoPtrTag);
1802     }
1803
1804     // Miscellaneous operations:
1805
1806     void breakpoint(uint8_t imm = 0)
1807     {
1808         m_assembler.bkpt(imm);
1809     }
1810
1811     static bool isBreakpoint(void* address) { return ARMv7Assembler::isBkpt(address); }
1812
1813     ALWAYS_INLINE Call nearCall()
1814     {
1815         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1816         return Call(m_assembler.blx(dataTempRegister), Call::LinkableNear);
1817     }
1818
1819     ALWAYS_INLINE Call nearTailCall()
1820     {
1821         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1822         return Call(m_assembler.bx(dataTempRegister), Call::LinkableNearTail);
1823     }
1824
1825     ALWAYS_INLINE Call call(PtrTag)
1826     {
1827         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1828         return Call(m_assembler.blx(dataTempRegister), Call::Linkable);
1829     }
1830
1831     ALWAYS_INLINE Call call(RegisterID target, PtrTag)
1832     {
1833         return Call(m_assembler.blx(target), Call::None);
1834     }
1835
1836     ALWAYS_INLINE Call call(Address address, PtrTag)
1837     {
1838         load32(address, dataTempRegister);
1839         return Call(m_assembler.blx(dataTempRegister), Call::None);
1840     }
1841
1842     ALWAYS_INLINE Call call(RegisterID callTag) { return UNUSED_PARAM(callTag), call(NoPtrTag); }
1843     ALWAYS_INLINE Call call(RegisterID target, RegisterID callTag) { return UNUSED_PARAM(callTag), call(target, NoPtrTag); }
1844     ALWAYS_INLINE Call call(Address address, RegisterID callTag) { return UNUSED_PARAM(callTag), call(address, NoPtrTag); }
1845
1846     ALWAYS_INLINE void ret()
1847     {
1848         m_assembler.bx(linkRegister);
1849     }
1850
1851     void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
1852     {
1853         m_assembler.cmp(left, right);
1854         m_assembler.it(armV7Condition(cond), false);
1855         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1856         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1857     }
1858
1859     void compare32(RelationalCondition cond, Address left, RegisterID right, RegisterID dest)
1860     {
1861         load32(left, dataTempRegister);
1862         compare32(cond, dataTempRegister, right, dest);
1863     }
1864
1865     void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest)
1866     {
1867         TrustedImm32 right8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, right);
1868         MacroAssemblerHelpers::load8OnCondition(*this, cond, left, addressTempRegister);
1869         compare32(cond, addressTempRegister, right8, dest);
1870     }
1871
1872     void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1873     {
1874         compare32AndSetFlags(left, right);
1875         m_assembler.it(armV7Condition(cond), false);
1876         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1877         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1878     }
1879
1880     // FIXME:
1881     // The mask should be optional... paerhaps the argument order should be
1882     // dest-src, operations always have a dest? ... possibly not true, considering
1883     // asm ops like test, or pseudo ops like pop().
1884     void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1885     {
1886         load32(address, dataTempRegister);
1887         test32(dataTempRegister, mask);
1888         m_assembler.it(armV7Condition(cond), false);
1889         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1890         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1891     }
1892
1893     void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1894     {
1895         TrustedImm32 mask8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, mask);
1896         MacroAssemblerHelpers::load8OnCondition(*this, cond, address, dataTempRegister);
1897         test32(dataTempRegister, mask8);
1898         m_assembler.it(armV7Condition(cond), false);
1899         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1900         m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1901     }
1902
1903     ALWAYS_INLINE DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dst)
1904     {
1905         padBeforePatch();
1906         moveFixedWidthEncoding(imm, dst);
1907         return DataLabel32(this);
1908     }
1909
1910     ALWAYS_INLINE DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst)
1911     {
1912         padBeforePatch();
1913         moveFixedWidthEncoding(TrustedImm32(imm), dst);
1914         return DataLabelPtr(this);
1915     }
1916
1917     ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(nullptr))
1918     {
1919         dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1920         return branch32(cond, left, dataTempRegister);
1921     }
1922
1923     ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(nullptr))
1924     {
1925         load32(left, addressTempRegister);
1926         dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1927         return branch32(cond, addressTempRegister, dataTempRegister);
1928     }
1929     
1930     ALWAYS_INLINE Jump branch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0))
1931     {
1932         load32(left, addressTempRegister);
1933         dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1934         return branch32(cond, addressTempRegister, dataTempRegister);
1935     }
1936     
1937     PatchableJump patchableBranchPtr(RelationalCondition cond, Address left, TrustedImmPtr right = TrustedImmPtr(nullptr))
1938     {
1939         m_makeJumpPatchable = true;
1940         Jump result = branch32(cond, left, TrustedImm32(right));
1941         m_makeJumpPatchable = false;
1942         return PatchableJump(result);
1943     }
1944     
1945     PatchableJump patchableBranchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1946     {
1947         m_makeJumpPatchable = true;
1948         Jump result = branchTest32(cond, reg, mask);
1949         m_makeJumpPatchable = false;
1950         return PatchableJump(result);
1951     }
1952
1953     PatchableJump patchableBranch8(RelationalCondition cond, Address left, TrustedImm32 imm)
1954     {
1955         m_makeJumpPatchable = true;
1956         Jump result = branch8(cond, left, imm);
1957         m_makeJumpPatchable = false;
1958         return PatchableJump(result);
1959     }
1960
1961     PatchableJump patchableBranch32(RelationalCondition cond, RegisterID reg, TrustedImm32 imm)
1962     {
1963         m_makeJumpPatchable = true;
1964         Jump result = branch32(cond, reg, imm);
1965         m_makeJumpPatchable = false;
1966         return PatchableJump(result);
1967     }
1968
1969     PatchableJump patchableBranch32(RelationalCondition cond, Address left, TrustedImm32 imm)
1970     {
1971         m_makeJumpPatchable = true;
1972         Jump result = branch32(cond, left, imm);
1973         m_makeJumpPatchable = false;
1974         return PatchableJump(result);
1975     }
1976
1977     PatchableJump patchableBranchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(nullptr))
1978     {
1979         m_makeJumpPatchable = true;
1980         Jump result = branchPtrWithPatch(cond, left, dataLabel, initialRightValue);
1981         m_makeJumpPatchable = false;
1982         return PatchableJump(result);
1983     }
1984
1985     PatchableJump patchableBranch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0))
1986     {
1987         m_makeJumpPatchable = true;
1988         Jump result = branch32WithPatch(cond, left, dataLabel, initialRightValue);
1989         m_makeJumpPatchable = false;
1990         return PatchableJump(result);
1991     }
1992
1993     PatchableJump patchableJump()
1994     {
1995         padBeforePatch();
1996         m_makeJumpPatchable = true;
1997         Jump result = jump();
1998         m_makeJumpPatchable = false;
1999         return PatchableJump(result);
2000     }
2001
2002     ALWAYS_INLINE DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
2003     {
2004         DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
2005         store32(dataTempRegister, address);
2006         return label;
2007     }
2008     ALWAYS_INLINE DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(TrustedImmPtr(nullptr), address); }
2009
2010     template<PtrTag resultTag, PtrTag locationTag>
2011     static FunctionPtr<resultTag> readCallTarget(CodeLocationCall<locationTag> call)
2012     {
2013         return FunctionPtr<resultTag>(reinterpret_cast<void(*)()>(ARMv7Assembler::readCallTarget(call.dataLocation())));
2014     }
2015     
2016     static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; }
2017     static bool canJumpReplacePatchableBranch32WithPatch() { return false; }
2018     
2019     template<PtrTag tag>
2020     static CodeLocationLabel<tag> startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr<tag> label)
2021     {
2022         const unsigned twoWordOpSize = 4;
2023         return label.labelAtOffset(-twoWordOpSize * 2);
2024     }
2025     
2026     template<PtrTag tag>
2027     static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel<tag> instructionStart, RegisterID rd, void* initialValue)
2028     {
2029 #if OS(LINUX)
2030         ARMv7Assembler::revertJumpTo_movT3movtcmpT2(instructionStart.dataLocation(), rd, dataTempRegister, reinterpret_cast<uintptr_t>(initialValue));
2031 #else
2032         UNUSED_PARAM(rd);
2033         ARMv7Assembler::revertJumpTo_movT3(instructionStart.dataLocation(), dataTempRegister, ARMThumbImmediate::makeUInt16(reinterpret_cast<uintptr_t>(initialValue) & 0xffff));
2034 #endif
2035     }
2036
2037     template<PtrTag tag>
2038     static CodeLocationLabel<tag> startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr<tag>)
2039     {
2040         UNREACHABLE_FOR_PLATFORM();
2041         return CodeLocationLabel<tag>();
2042     }
2043
2044     template<PtrTag tag>
2045     static CodeLocationLabel<tag> startOfPatchableBranch32WithPatchOnAddress(CodeLocationDataLabel32<tag>)
2046     {
2047         UNREACHABLE_FOR_PLATFORM();
2048         return CodeLocationLabel<tag>();
2049     }
2050
2051     template<PtrTag tag>
2052     static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel<tag>, Address, void*)
2053     {
2054         UNREACHABLE_FOR_PLATFORM();
2055     }
2056
2057     template<PtrTag tag>
2058     static void revertJumpReplacementToPatchableBranch32WithPatch(CodeLocationLabel<tag>, Address, int32_t)
2059     {
2060         UNREACHABLE_FOR_PLATFORM();
2061     }
2062
2063     template<PtrTag callTag, PtrTag destTag>
2064     static void repatchCall(CodeLocationCall<callTag> call, CodeLocationLabel<destTag> destination)
2065     {
2066         ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
2067     }
2068
2069     template<PtrTag callTag, PtrTag destTag>
2070     static void repatchCall(CodeLocationCall<callTag> call, FunctionPtr<destTag> destination)
2071     {
2072         ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
2073     }
2074
2075 protected:
2076     ALWAYS_INLINE Jump jump()
2077     {
2078         m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint.
2079         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
2080         return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpNoConditionFixedSize : ARMv7Assembler::JumpNoCondition);
2081     }
2082
2083     ALWAYS_INLINE Jump makeBranch(ARMv7Assembler::Condition cond)
2084     {
2085         m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint.
2086         m_assembler.it(cond, true, true);
2087         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
2088         return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpConditionFixedSize : ARMv7Assembler::JumpCondition, cond);
2089     }
2090     ALWAYS_INLINE Jump makeBranch(RelationalCondition cond) { return makeBranch(armV7Condition(cond)); }
2091     ALWAYS_INLINE Jump makeBranch(ResultCondition cond) { return makeBranch(armV7Condition(cond)); }
2092     ALWAYS_INLINE Jump makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); }
2093
2094     ArmAddress setupArmAddress(BaseIndex address)
2095     {
2096         if (address.offset) {
2097             ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
2098             if (imm.isValid())
2099                 m_assembler.add(addressTempRegister, address.base, imm);
2100             else {
2101                 move(TrustedImm32(address.offset), addressTempRegister);
2102                 m_assembler.add(addressTempRegister, addressTempRegister, address.base);
2103             }
2104
2105             return ArmAddress(addressTempRegister, address.index, address.scale);
2106         } else
2107             return ArmAddress(address.base, address.index, address.scale);
2108     }
2109
2110     ArmAddress setupArmAddress(Address address)
2111     {
2112         if ((address.offset >= -0xff) && (address.offset <= 0xfff))
2113             return ArmAddress(address.base, address.offset);
2114
2115         move(TrustedImm32(address.offset), addressTempRegister);
2116         return ArmAddress(address.base, addressTempRegister);
2117     }
2118
2119     ArmAddress setupArmAddress(ImplicitAddress address)
2120     {
2121         if ((address.offset >= -0xff) && (address.offset <= 0xfff))
2122             return ArmAddress(address.base, address.offset);
2123
2124         move(TrustedImm32(address.offset), addressTempRegister);
2125         return ArmAddress(address.base, addressTempRegister);
2126     }
2127
2128     RegisterID makeBaseIndexBase(BaseIndex address)
2129     {
2130         if (!address.offset)
2131             return address.base;
2132
2133         ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
2134         if (imm.isValid())
2135             m_assembler.add(addressTempRegister, address.base, imm);
2136         else {
2137             move(TrustedImm32(address.offset), addressTempRegister);
2138             m_assembler.add(addressTempRegister, addressTempRegister, address.base);
2139         }
2140
2141         return addressTempRegister;
2142     }
2143
2144     void moveFixedWidthEncoding(TrustedImm32 imm, RegisterID dst)
2145     {
2146         uint32_t value = imm.m_value;
2147         m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff));
2148         m_assembler.movt(dst, ARMThumbImmediate::makeUInt16(value >> 16));
2149     }
2150
2151     ARMv7Assembler::Condition armV7Condition(RelationalCondition cond)
2152     {
2153         return static_cast<ARMv7Assembler::Condition>(cond);
2154     }
2155
2156     ARMv7Assembler::Condition armV7Condition(ResultCondition cond)
2157     {
2158         return static_cast<ARMv7Assembler::Condition>(cond);
2159     }
2160
2161     ARMv7Assembler::Condition armV7Condition(DoubleCondition cond)
2162     {
2163         return static_cast<ARMv7Assembler::Condition>(cond);
2164     }
2165
2166 private:
2167     friend class LinkBuffer;
2168
2169     template<PtrTag tag>
2170     static void linkCall(void* code, Call call, FunctionPtr<tag> function)
2171     {
2172         if (call.isFlagSet(Call::Tail))
2173             ARMv7Assembler::linkJump(code, call.m_label, function.executableAddress());
2174         else
2175             ARMv7Assembler::linkCall(code, call.m_label, function.executableAddress());
2176     }
2177
2178     bool m_makeJumpPatchable;
2179 };
2180
2181 } // namespace JSC
2182
2183 #endif // ENABLE(ASSEMBLER)