Enhance the MacroAssembler and LinkBuffer to support pointer profiling.
[WebKit-https.git] / Source / JavaScriptCore / assembler / MacroAssemblerARM.h
1 /*
2  * Copyright (C) 2008-2018 Apple Inc.
3  * Copyright (C) 2009, 2010 University of Szeged
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #pragma once
29
30 #if ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
31
32 #include "ARMAssembler.h"
33 #include "AbstractMacroAssembler.h"
34
35 namespace JSC {
36
37 using Assembler = TARGET_ASSEMBLER;
38
39 class MacroAssemblerARM : public AbstractMacroAssembler<Assembler> {
40     static const int DoubleConditionMask = 0x0f;
41     static const int DoubleConditionBitSpecial = 0x10;
42     COMPILE_ASSERT(!(DoubleConditionBitSpecial & DoubleConditionMask), DoubleConditionBitSpecial_should_not_interfere_with_ARMAssembler_Condition_codes);
43 public:
44     static const unsigned numGPRs = 16;
45     static const unsigned numFPRs = 16;
46     
47     typedef ARMRegisters::FPRegisterID FPRegisterID;
48
49     enum RelationalCondition {
50         Equal = ARMAssembler::EQ,
51         NotEqual = ARMAssembler::NE,
52         Above = ARMAssembler::HI,
53         AboveOrEqual = ARMAssembler::CS,
54         Below = ARMAssembler::CC,
55         BelowOrEqual = ARMAssembler::LS,
56         GreaterThan = ARMAssembler::GT,
57         GreaterThanOrEqual = ARMAssembler::GE,
58         LessThan = ARMAssembler::LT,
59         LessThanOrEqual = ARMAssembler::LE
60     };
61
62     enum ResultCondition {
63         Overflow = ARMAssembler::VS,
64         Signed = ARMAssembler::MI,
65         PositiveOrZero = ARMAssembler::PL,
66         Zero = ARMAssembler::EQ,
67         NonZero = ARMAssembler::NE
68     };
69
70     enum DoubleCondition {
71         // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
72         DoubleEqual = ARMAssembler::EQ,
73         DoubleNotEqual = ARMAssembler::NE | DoubleConditionBitSpecial,
74         DoubleGreaterThan = ARMAssembler::GT,
75         DoubleGreaterThanOrEqual = ARMAssembler::GE,
76         DoubleLessThan = ARMAssembler::CC,
77         DoubleLessThanOrEqual = ARMAssembler::LS,
78         // If either operand is NaN, these conditions always evaluate to true.
79         DoubleEqualOrUnordered = ARMAssembler::EQ | DoubleConditionBitSpecial,
80         DoubleNotEqualOrUnordered = ARMAssembler::NE,
81         DoubleGreaterThanOrUnordered = ARMAssembler::HI,
82         DoubleGreaterThanOrEqualOrUnordered = ARMAssembler::CS,
83         DoubleLessThanOrUnordered = ARMAssembler::LT,
84         DoubleLessThanOrEqualOrUnordered = ARMAssembler::LE,
85     };
86
87     static const RegisterID stackPointerRegister = ARMRegisters::sp;
88     static const RegisterID framePointerRegister = ARMRegisters::fp;
89     static const RegisterID linkRegister = ARMRegisters::lr;
90
91     static const Scale ScalePtr = TimesFour;
92
93     void add32(RegisterID src, RegisterID dest)
94     {
95         m_assembler.adds(dest, dest, src);
96     }
97
98     void add32(RegisterID op1, RegisterID op2, RegisterID dest)
99     {
100         m_assembler.adds(dest, op1, op2);
101     }
102
103     void add32(TrustedImm32 imm, Address address)
104     {
105         load32(address, ARMRegisters::S1);
106         add32(imm, ARMRegisters::S1);
107         store32(ARMRegisters::S1, address);
108     }
109
110     void add32(TrustedImm32 imm, RegisterID dest)
111     {
112         m_assembler.adds(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
113     }
114
115     void add32(AbsoluteAddress src, RegisterID dest)
116     {
117         move(TrustedImmPtr(src.m_ptr), ARMRegisters::S1);
118         m_assembler.dtrUp(ARMAssembler::LoadUint32, ARMRegisters::S1, ARMRegisters::S1, 0);
119         add32(ARMRegisters::S1, dest);
120     }
121
122     void add32(Address src, RegisterID dest)
123     {
124         load32(src, ARMRegisters::S1);
125         add32(ARMRegisters::S1, dest);
126     }
127
128     void add32(RegisterID src, TrustedImm32 imm, RegisterID dest)
129     {
130         m_assembler.adds(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
131     }
132
133     void getEffectiveAddress(BaseIndex address, RegisterID dest)
134     {
135         m_assembler.add(dest, address.base, m_assembler.lsl(address.index, static_cast<int>(address.scale)));
136         if (address.offset)
137             add32(TrustedImm32(address.offset), dest);
138     }
139
140     void and32(RegisterID src, RegisterID dest)
141     {
142         m_assembler.bitAnds(dest, dest, src);
143     }
144
145     void and32(RegisterID op1, RegisterID op2, RegisterID dest)
146     {
147         m_assembler.bitAnds(dest, op1, op2);
148     }
149
150     void and32(TrustedImm32 imm, RegisterID dest)
151     {
152         ARMWord w = m_assembler.getImm(imm.m_value, ARMRegisters::S0, true);
153         if (w & ARMAssembler::Op2InvertedImmediate)
154             m_assembler.bics(dest, dest, w & ~ARMAssembler::Op2InvertedImmediate);
155         else
156             m_assembler.bitAnds(dest, dest, w);
157     }
158
159     void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
160     {
161         ARMWord w = m_assembler.getImm(imm.m_value, ARMRegisters::S0, true);
162         if (w & ARMAssembler::Op2InvertedImmediate)
163             m_assembler.bics(dest, src, w & ~ARMAssembler::Op2InvertedImmediate);
164         else
165             m_assembler.bitAnds(dest, src, w);
166     }
167
168     void and32(Address src, RegisterID dest)
169     {
170         load32(src, ARMRegisters::S1);
171         and32(ARMRegisters::S1, dest);
172     }
173
174     void lshift32(RegisterID shiftAmount, RegisterID dest)
175     {
176         lshift32(dest, shiftAmount, dest);
177     }
178
179     void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
180     {
181         ARMWord w = ARMAssembler::getOp2Byte(0x1f);
182         m_assembler.bitAnd(ARMRegisters::S0, shiftAmount, w);
183
184         m_assembler.movs(dest, m_assembler.lslRegister(src, ARMRegisters::S0));
185     }
186
187     void lshift32(TrustedImm32 imm, RegisterID dest)
188     {
189         m_assembler.movs(dest, m_assembler.lsl(dest, imm.m_value & 0x1f));
190     }
191
192     void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
193     {
194         m_assembler.movs(dest, m_assembler.lsl(src, imm.m_value & 0x1f));
195     }
196
197     void mul32(RegisterID op1, RegisterID op2, RegisterID dest)
198     {
199         if (op2 == dest) {
200             if (op1 == dest) {
201                 move(op2, ARMRegisters::S0);
202                 op2 = ARMRegisters::S0;
203             } else {
204                 // Swap the operands.
205                 RegisterID tmp = op1;
206                 op1 = op2;
207                 op2 = tmp;
208             }
209         }
210         m_assembler.muls(dest, op1, op2);
211     }
212
213     void mul32(RegisterID src, RegisterID dest)
214     {
215         mul32(src, dest, dest);
216     }
217
218     void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
219     {
220         move(imm, ARMRegisters::S0);
221         m_assembler.muls(dest, src, ARMRegisters::S0);
222     }
223
224     void neg32(RegisterID srcDest)
225     {
226         m_assembler.rsbs(srcDest, srcDest, ARMAssembler::getOp2Byte(0));
227     }
228
229     void neg32(RegisterID src, RegisterID dest)
230     {
231         m_assembler.rsbs(dest, src, ARMAssembler::getOp2Byte(0));
232     }
233
234     void or32(RegisterID src, RegisterID dest)
235     {
236         m_assembler.orrs(dest, dest, src);
237     }
238
239     void or32(RegisterID src, AbsoluteAddress dest)
240     {
241         move(TrustedImmPtr(dest.m_ptr), ARMRegisters::S0);
242         load32(Address(ARMRegisters::S0), ARMRegisters::S1);
243         or32(src, ARMRegisters::S1);
244         store32(ARMRegisters::S1, ARMRegisters::S0);
245     }
246
247     void or32(TrustedImm32 imm, AbsoluteAddress dest)
248     {
249         move(TrustedImmPtr(dest.m_ptr), ARMRegisters::S0);
250         load32(Address(ARMRegisters::S0), ARMRegisters::S1);
251         or32(imm, ARMRegisters::S1); // It uses S0 as temporary register, we need to reload the address.
252         move(TrustedImmPtr(dest.m_ptr), ARMRegisters::S0);
253         store32(ARMRegisters::S1, ARMRegisters::S0);
254     }
255
256     void or32(TrustedImm32 imm, Address address)
257     {
258         load32(address, ARMRegisters::S0);
259         or32(imm, ARMRegisters::S0, ARMRegisters::S0);
260         store32(ARMRegisters::S0, address);
261     }
262
263     void or32(TrustedImm32 imm, RegisterID dest)
264     {
265         ASSERT(dest != ARMRegisters::S0);
266         m_assembler.orrs(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
267     }
268
269     void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
270     {
271         ASSERT(src != ARMRegisters::S0);
272         m_assembler.orrs(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
273     }
274
275     void or32(RegisterID op1, RegisterID op2, RegisterID dest)
276     {
277         m_assembler.orrs(dest, op1, op2);
278     }
279
280     void rshift32(RegisterID shiftAmount, RegisterID dest)
281     {
282         rshift32(dest, shiftAmount, dest);
283     }
284
285     void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
286     {
287         ARMWord w = ARMAssembler::getOp2Byte(0x1f);
288         m_assembler.bitAnd(ARMRegisters::S0, shiftAmount, w);
289
290         m_assembler.movs(dest, m_assembler.asrRegister(src, ARMRegisters::S0));
291     }
292
293     void rshift32(TrustedImm32 imm, RegisterID dest)
294     {
295         rshift32(dest, imm, dest);
296     }
297
298     void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
299     {
300         if (!imm.m_value)
301             move(src, dest);
302         else
303             m_assembler.movs(dest, m_assembler.asr(src, imm.m_value & 0x1f));
304     }
305
306     void urshift32(RegisterID shiftAmount, RegisterID dest)
307     {
308         urshift32(dest, shiftAmount, dest);
309     }
310
311     void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
312     {
313         ARMWord w = ARMAssembler::getOp2Byte(0x1f);
314         m_assembler.bitAnd(ARMRegisters::S0, shiftAmount, w);
315
316         m_assembler.movs(dest, m_assembler.lsrRegister(src, ARMRegisters::S0));
317     }
318
319     void urshift32(TrustedImm32 imm, RegisterID dest)
320     {
321         m_assembler.movs(dest, m_assembler.lsr(dest, imm.m_value & 0x1f));
322     }
323     
324     void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
325     {
326         if (!imm.m_value)
327             move(src, dest);
328         else
329             m_assembler.movs(dest, m_assembler.lsr(src, imm.m_value & 0x1f));
330     }
331
332     void sub32(RegisterID src, RegisterID dest)
333     {
334         m_assembler.subs(dest, dest, src);
335     }
336
337     void sub32(RegisterID left, RegisterID right, RegisterID dest)
338     {
339         m_assembler.subs(dest, left, right);
340     }
341
342     void sub32(TrustedImm32 imm, RegisterID dest)
343     {
344         m_assembler.subs(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
345     }
346
347     void sub32(TrustedImm32 imm, Address address)
348     {
349         load32(address, ARMRegisters::S1);
350         sub32(imm, ARMRegisters::S1);
351         store32(ARMRegisters::S1, address);
352     }
353
354     void sub32(Address src, RegisterID dest)
355     {
356         load32(src, ARMRegisters::S1);
357         sub32(ARMRegisters::S1, dest);
358     }
359
360     void sub32(RegisterID src, TrustedImm32 imm, RegisterID dest)
361     {
362         m_assembler.subs(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
363     }
364
365     void xor32(RegisterID src, RegisterID dest)
366     {
367         m_assembler.eors(dest, dest, src);
368     }
369
370     void xor32(RegisterID op1, RegisterID op2, RegisterID dest)
371     {
372         m_assembler.eors(dest, op1, op2);
373     }
374
375     void xor32(Address src, RegisterID dest)
376     {
377         load32(src, ARMRegisters::S1);
378         xor32(ARMRegisters::S1, dest);
379     }
380
381     void xor32(TrustedImm32 imm, RegisterID dest)
382     {
383         if (imm.m_value == -1)
384             m_assembler.mvns(dest, dest);
385         else
386             m_assembler.eors(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
387     }
388
389     void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
390     {
391         if (imm.m_value == -1)
392             m_assembler.mvns(dest, src);
393         else    
394             m_assembler.eors(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
395     }
396
397     void countLeadingZeros32(RegisterID src, RegisterID dest)
398     {
399 #if WTF_ARM_ARCH_AT_LEAST(5)
400         m_assembler.clz(dest, src);
401 #else
402         UNUSED_PARAM(src);
403         UNUSED_PARAM(dest);
404         RELEASE_ASSERT_NOT_REACHED();
405 #endif
406     }
407
408     void load8(ImplicitAddress address, RegisterID dest)
409     {
410         m_assembler.dataTransfer32(ARMAssembler::LoadUint8, dest, address.base, address.offset);
411     }
412
413     void load8(BaseIndex address, RegisterID dest)
414     {
415         m_assembler.baseIndexTransfer32(ARMAssembler::LoadUint8, dest, address.base, address.index, static_cast<int>(address.scale), address.offset);
416     }
417
418     void load8(const void* address, RegisterID dest)
419     {
420         move(TrustedImmPtr(address), ARMRegisters::S0);
421         m_assembler.dataTransfer32(ARMAssembler::LoadUint8, dest, ARMRegisters::S0, 0);
422     }
423
424     void load8SignedExtendTo32(Address address, RegisterID dest)
425     {
426         m_assembler.dataTransfer16(ARMAssembler::LoadInt8, dest, address.base, address.offset);
427     }
428
429     void load8SignedExtendTo32(BaseIndex address, RegisterID dest)
430     {
431         m_assembler.baseIndexTransfer16(ARMAssembler::LoadInt8, dest, address.base, address.index, static_cast<int>(address.scale), address.offset);
432     }
433
434     void load16(ImplicitAddress address, RegisterID dest)
435     {
436         m_assembler.dataTransfer16(ARMAssembler::LoadUint16, dest, address.base, address.offset);
437     }
438
439     void load16(BaseIndex address, RegisterID dest)
440     {
441         m_assembler.baseIndexTransfer16(ARMAssembler::LoadUint16, dest, address.base, address.index, static_cast<int>(address.scale), address.offset);
442     }
443
444     void load16SignedExtendTo32(BaseIndex address, RegisterID dest)
445     {
446         m_assembler.baseIndexTransfer16(ARMAssembler::LoadInt16, dest, address.base, address.index, static_cast<int>(address.scale), address.offset);
447     }
448
449     void load32(ImplicitAddress address, RegisterID dest)
450     {
451         m_assembler.dataTransfer32(ARMAssembler::LoadUint32, dest, address.base, address.offset);
452     }
453
454     void load32(BaseIndex address, RegisterID dest)
455     {
456         m_assembler.baseIndexTransfer32(ARMAssembler::LoadUint32, dest, address.base, address.index, static_cast<int>(address.scale), address.offset);
457     }
458
459 #if CPU(ARMV5_OR_LOWER)
460     void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest);
461 #else
462     void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
463     {
464         load32(address, dest);
465     }
466 #endif
467
468     void load16Unaligned(BaseIndex address, RegisterID dest)
469     {
470         load16(address, dest);
471     }
472
473     void abortWithReason(AbortReason reason)
474     {
475         move(TrustedImm32(reason), ARMRegisters::S0);
476         breakpoint();
477     }
478
479     void abortWithReason(AbortReason reason, intptr_t misc)
480     {
481         move(TrustedImm32(misc), ARMRegisters::S1);
482         abortWithReason(reason);
483     }
484
485     ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
486     {
487         ConvertibleLoadLabel result(this);
488         ASSERT(address.offset >= 0 && address.offset <= 255);
489         m_assembler.dtrUp(ARMAssembler::LoadUint32, dest, address.base, address.offset);
490         return result;
491     }
492
493     DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
494     {
495         DataLabel32 dataLabel(this);
496         m_assembler.ldrUniqueImmediate(ARMRegisters::S0, 0);
497         m_assembler.dtrUpRegister(ARMAssembler::LoadUint32, dest, address.base, ARMRegisters::S0);
498         return dataLabel;
499     }
500
501     static bool isCompactPtrAlignedAddressOffset(ptrdiff_t value)
502     {
503         return value >= -4095 && value <= 4095;
504     }
505
506     DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
507     {
508         DataLabelCompact dataLabel(this);
509         ASSERT(isCompactPtrAlignedAddressOffset(address.offset));
510         if (address.offset >= 0)
511             m_assembler.dtrUp(ARMAssembler::LoadUint32, dest, address.base, address.offset);
512         else
513             m_assembler.dtrDown(ARMAssembler::LoadUint32, dest, address.base, address.offset);
514         return dataLabel;
515     }
516
517     DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
518     {
519         DataLabel32 dataLabel(this);
520         m_assembler.ldrUniqueImmediate(ARMRegisters::S0, 0);
521         m_assembler.dtrUpRegister(ARMAssembler::StoreUint32, src, address.base, ARMRegisters::S0);
522         return dataLabel;
523     }
524
525     void store8(RegisterID src, BaseIndex address)
526     {
527         m_assembler.baseIndexTransfer32(ARMAssembler::StoreUint8, src, address.base, address.index, static_cast<int>(address.scale), address.offset);
528     }
529
530     void store8(RegisterID src, ImplicitAddress address)
531     {
532         m_assembler.dtrUp(ARMAssembler::StoreUint8, src, address.base, address.offset);
533     }
534
535     void store8(RegisterID src, const void* address)
536     {
537         move(TrustedImmPtr(address), ARMRegisters::S0);
538         m_assembler.dtrUp(ARMAssembler::StoreUint8, src, ARMRegisters::S0, 0);
539     }
540
541     void store8(TrustedImm32 imm, ImplicitAddress address)
542     {
543         TrustedImm32 imm8(static_cast<int8_t>(imm.m_value));
544         move(imm8, ARMRegisters::S1);
545         store8(ARMRegisters::S1, address);
546     }
547
548     void store8(TrustedImm32 imm, const void* address)
549     {
550         TrustedImm32 imm8(static_cast<int8_t>(imm.m_value));
551         move(TrustedImm32(reinterpret_cast<ARMWord>(address)), ARMRegisters::S0);
552         move(imm8, ARMRegisters::S1);
553         m_assembler.dtrUp(ARMAssembler::StoreUint8, ARMRegisters::S1, ARMRegisters::S0, 0);
554     }
555
556     void store16(RegisterID src, BaseIndex address)
557     {
558         m_assembler.baseIndexTransfer16(ARMAssembler::StoreUint16, src, address.base, address.index, static_cast<int>(address.scale), address.offset);
559     }
560
561     void store32(RegisterID src, ImplicitAddress address)
562     {
563         m_assembler.dataTransfer32(ARMAssembler::StoreUint32, src, address.base, address.offset);
564     }
565
566     void store32(RegisterID src, BaseIndex address)
567     {
568         m_assembler.baseIndexTransfer32(ARMAssembler::StoreUint32, src, address.base, address.index, static_cast<int>(address.scale), address.offset);
569     }
570
571     void store32(TrustedImm32 imm, ImplicitAddress address)
572     {
573         move(imm, ARMRegisters::S1);
574         store32(ARMRegisters::S1, address);
575     }
576
577     void store32(TrustedImm32 imm, BaseIndex address)
578     {
579         move(imm, ARMRegisters::S1);
580         m_assembler.baseIndexTransfer32(ARMAssembler::StoreUint32, ARMRegisters::S1, address.base, address.index, static_cast<int>(address.scale), address.offset);
581     }
582
583     void store32(RegisterID src, const void* address)
584     {
585         m_assembler.ldrUniqueImmediate(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
586         m_assembler.dtrUp(ARMAssembler::StoreUint32, src, ARMRegisters::S0, 0);
587     }
588
589     void store32(TrustedImm32 imm, const void* address)
590     {
591         m_assembler.ldrUniqueImmediate(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
592         m_assembler.moveImm(imm.m_value, ARMRegisters::S1);
593         m_assembler.dtrUp(ARMAssembler::StoreUint32, ARMRegisters::S1, ARMRegisters::S0, 0);
594     }
595
596     void pop(RegisterID dest)
597     {
598         m_assembler.pop(dest);
599     }
600
601     void popPair(RegisterID dest1, RegisterID dest2)
602     {
603         m_assembler.pop(dest1);
604         m_assembler.pop(dest2);
605     }
606
607     void push(RegisterID src)
608     {
609         m_assembler.push(src);
610     }
611
612     void push(Address address)
613     {
614         load32(address, ARMRegisters::S1);
615         push(ARMRegisters::S1);
616     }
617
618     void push(TrustedImm32 imm)
619     {
620         move(imm, ARMRegisters::S0);
621         push(ARMRegisters::S0);
622     }
623
624     void pushPair(RegisterID src1, RegisterID src2)
625     {
626         m_assembler.push(src2);
627         m_assembler.push(src1);
628     }
629
630     void move(TrustedImm32 imm, RegisterID dest)
631     {
632         m_assembler.moveImm(imm.m_value, dest);
633     }
634
635     void move(RegisterID src, RegisterID dest)
636     {
637         if (src != dest)
638             m_assembler.mov(dest, src);
639     }
640
641     void move(TrustedImmPtr imm, RegisterID dest)
642     {
643         move(TrustedImm32(imm), dest);
644     }
645
646     void swap(RegisterID reg1, RegisterID reg2)
647     {
648         xor32(reg1, reg2);
649         xor32(reg2, reg1);
650         xor32(reg1, reg2);
651     }
652
653     void signExtend32ToPtr(RegisterID src, RegisterID dest)
654     {
655         if (src != dest)
656             move(src, dest);
657     }
658
659     void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
660     {
661         if (src != dest)
662             move(src, dest);
663     }
664
665     Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
666     {
667         TrustedImm32 right8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, right);
668         MacroAssemblerHelpers::load8OnCondition(*this, cond, left, ARMRegisters::S1);
669         return branch32(cond, ARMRegisters::S1, right8);
670     }
671
672     Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
673     {
674         TrustedImm32 right8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, right);
675         MacroAssemblerHelpers::load8OnCondition(*this, cond, left, ARMRegisters::S1);
676         return branch32(cond, ARMRegisters::S1, right8);
677     }
678
679     Jump branch8(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
680     {
681         TrustedImm32 right8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, right);
682         move(TrustedImmPtr(left.m_ptr), ARMRegisters::S1);
683         MacroAssemblerHelpers::load8OnCondition(*this, cond, Address(ARMRegisters::S1), ARMRegisters::S1);
684         return branch32(cond, ARMRegisters::S1, right8);
685     }
686
687     Jump branchPtr(RelationalCondition cond, BaseIndex left, RegisterID right)
688     {
689         load32(left, ARMRegisters::S1);
690         return branch32(cond, ARMRegisters::S1, right);
691     }
692
693     Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right, int useConstantPool = 0)
694     {
695         m_assembler.cmp(left, right);
696         return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool));
697     }
698
699     Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right, int useConstantPool = 0)
700     {
701         internalCompare32(left, right);
702         return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool));
703     }
704
705     Jump branch32(RelationalCondition cond, RegisterID left, Address right)
706     {
707         load32(right, ARMRegisters::S1);
708         return branch32(cond, left, ARMRegisters::S1);
709     }
710
711     Jump branch32(RelationalCondition cond, Address left, RegisterID right)
712     {
713         load32(left, ARMRegisters::S1);
714         return branch32(cond, ARMRegisters::S1, right);
715     }
716
717     Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
718     {
719         load32(left, ARMRegisters::S1);
720         return branch32(cond, ARMRegisters::S1, right);
721     }
722
723     Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
724     {
725         load32(left, ARMRegisters::S1);
726         return branch32(cond, ARMRegisters::S1, right);
727     }
728
729     Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
730     {
731         load32WithUnalignedHalfWords(left, ARMRegisters::S1);
732         return branch32(cond, ARMRegisters::S1, right);
733     }
734
735     Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
736     {
737         TrustedImm32 mask8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, mask);
738         MacroAssemblerHelpers::load8OnCondition(*this, cond, address, ARMRegisters::S1);
739         return branchTest32(cond, ARMRegisters::S1, mask8);
740     }
741
742     Jump branchTest8(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
743     {
744         TrustedImm32 mask8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, mask);
745         MacroAssemblerHelpers::load8OnCondition(*this, cond, address, ARMRegisters::S1);
746         return branchTest32(cond, ARMRegisters::S1, mask8);
747     }
748
749     Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
750     {
751         TrustedImm32 mask8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, mask);
752         move(TrustedImmPtr(address.m_ptr), ARMRegisters::S1);
753         MacroAssemblerHelpers::load8OnCondition(*this, cond, Address(ARMRegisters::S1), ARMRegisters::S1);
754         return branchTest32(cond, ARMRegisters::S1, mask8);
755     }
756
757     Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
758     {
759         ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == PositiveOrZero);
760         m_assembler.tst(reg, mask);
761         return Jump(m_assembler.jmp(ARMCondition(cond)));
762     }
763
764     Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
765     {
766         ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == PositiveOrZero);
767         ARMWord w = m_assembler.getImm(mask.m_value, ARMRegisters::S0, true);
768         if (w & ARMAssembler::Op2InvertedImmediate)
769             m_assembler.bics(ARMRegisters::S0, reg, w & ~ARMAssembler::Op2InvertedImmediate);
770         else
771             m_assembler.tst(reg, w);
772         return Jump(m_assembler.jmp(ARMCondition(cond)));
773     }
774
775     Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
776     {
777         load32(address, ARMRegisters::S1);
778         return branchTest32(cond, ARMRegisters::S1, mask);
779     }
780
781     Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
782     {
783         load32(address, ARMRegisters::S1);
784         return branchTest32(cond, ARMRegisters::S1, mask);
785     }
786
787     Jump jump()
788     {
789         return Jump(m_assembler.jmp());
790     }
791
792     void jump(RegisterID target, PtrTag)
793     {
794         m_assembler.bx(target);
795     }
796
797     void jump(Address address, PtrTag)
798     {
799         load32(address, ARMRegisters::pc);
800     }
801
802     void jump(AbsoluteAddress address, PtrTag)
803     {
804         move(TrustedImmPtr(address.m_ptr), ARMRegisters::S0);
805         load32(Address(ARMRegisters::S0, 0), ARMRegisters::pc);
806     }
807
808     void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2)
809     {
810         m_assembler.vmov(dest1, dest2, src);
811     }
812
813     void moveIntsToDouble(RegisterID src1, RegisterID src2, FPRegisterID dest, FPRegisterID)
814     {
815         m_assembler.vmov(dest, src1, src2);
816     }
817
818     Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
819     {
820         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero)
821             || (cond == NonZero) || (cond == PositiveOrZero));
822         add32(src, dest);
823         return Jump(m_assembler.jmp(ARMCondition(cond)));
824     }
825
826     Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
827     {
828         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero)
829             || (cond == NonZero) || (cond == PositiveOrZero));
830         add32(op1, op2, dest);
831         return Jump(m_assembler.jmp(ARMCondition(cond)));
832     }
833
834     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
835     {
836         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero)
837             || (cond == NonZero) || (cond == PositiveOrZero));
838         add32(imm, dest);
839         return Jump(m_assembler.jmp(ARMCondition(cond)));
840     }
841
842     Jump branchAdd32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
843     {
844         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero)
845             || (cond == NonZero) || (cond == PositiveOrZero));
846         add32(src, imm, dest);
847         return Jump(m_assembler.jmp(ARMCondition(cond)));
848     }
849
850     Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
851     {
852         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero)
853             || (cond == NonZero) || (cond == PositiveOrZero));
854         add32(imm, dest);
855         return Jump(m_assembler.jmp(ARMCondition(cond)));
856     }
857
858     Jump branchAdd32(ResultCondition cond, Address src, RegisterID dest)
859     {
860         load32(src, ARMRegisters::S0);
861         return branchAdd32(cond, dest, ARMRegisters::S0, dest);
862     }
863     void mull32(RegisterID op1, RegisterID op2, RegisterID dest)
864     {
865         if (op2 == dest) {
866             if (op1 == dest) {
867                 move(op2, ARMRegisters::S0);
868                 op2 = ARMRegisters::S0;
869             } else {
870                 // Swap the operands.
871                 RegisterID tmp = op1;
872                 op1 = op2;
873                 op2 = tmp;
874             }
875         }
876         m_assembler.mull(ARMRegisters::S1, dest, op1, op2);
877         m_assembler.cmp(ARMRegisters::S1, m_assembler.asr(dest, 31));
878     }
879
880     Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
881     {
882         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
883         if (cond == Overflow) {
884             mull32(src1, src2, dest);
885             cond = NonZero;
886         }
887         else
888             mul32(src1, src2, dest);
889         return Jump(m_assembler.jmp(ARMCondition(cond)));
890     }
891
892     Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
893     {
894         return branchMul32(cond, src, dest, dest);
895     }
896
897     Jump branchMul32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
898     {
899         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
900         if (cond == Overflow) {
901             move(imm, ARMRegisters::S0);
902             mull32(ARMRegisters::S0, src, dest);
903             cond = NonZero;
904         }
905         else
906             mul32(imm, src, dest);
907         return Jump(m_assembler.jmp(ARMCondition(cond)));
908     }
909
910     Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
911     {
912         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
913         sub32(src, dest);
914         return Jump(m_assembler.jmp(ARMCondition(cond)));
915     }
916
917     Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
918     {
919         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
920         sub32(imm, dest);
921         return Jump(m_assembler.jmp(ARMCondition(cond)));
922     }
923
924     Jump branchSub32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
925     {
926         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
927         sub32(src, imm, dest);
928         return Jump(m_assembler.jmp(ARMCondition(cond)));
929     }
930
931     Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
932     {
933         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
934         m_assembler.subs(dest, op1, op2);
935         return Jump(m_assembler.jmp(ARMCondition(cond)));
936     }
937
938     Jump branchNeg32(ResultCondition cond, RegisterID srcDest)
939     {
940         ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
941         neg32(srcDest);
942         return Jump(m_assembler.jmp(ARMCondition(cond)));
943     }
944
945     Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
946     {
947         ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
948         or32(src, dest);
949         return Jump(m_assembler.jmp(ARMCondition(cond)));
950     }
951
952     PatchableJump patchableJump()
953     {
954         return PatchableJump(m_assembler.jmp(ARMAssembler::AL, 1));
955     }
956
957     PatchableJump patchableBranch32(RelationalCondition cond, RegisterID reg, TrustedImm32 imm)
958     {
959         internalCompare32(reg, imm);
960         Jump jump(m_assembler.loadBranchTarget(ARMRegisters::S1, ARMCondition(cond), true));
961         m_assembler.bx(ARMRegisters::S1, ARMCondition(cond));
962         return PatchableJump(jump);
963     }
964
965     PatchableJump patchableBranch32(RelationalCondition cond, Address address, TrustedImm32 imm)
966     {
967         internalCompare32(address, imm);
968         Jump jump(m_assembler.loadBranchTarget(ARMRegisters::S1, ARMCondition(cond), false));
969         m_assembler.bx(ARMRegisters::S1, ARMCondition(cond));
970         return PatchableJump(jump);
971     }
972
973     void breakpoint()
974     {
975         m_assembler.bkpt(0);
976     }
977
978     static bool isBreakpoint(void* address) { return ARMAssembler::isBkpt(address); }
979
980     Call nearCall()
981     {
982         m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true);
983         return Call(m_assembler.blx(ARMRegisters::S1), Call::LinkableNear);
984     }
985
986     Call nearTailCall()
987     {
988         return Call(m_assembler.jmp(), Call::LinkableNearTail);
989     }
990
991     Call call(RegisterID target, PtrTag)
992     {
993         return Call(m_assembler.blx(target), Call::None);
994     }
995
996     void call(Address address, PtrTag)
997     {
998         call32(address.base, address.offset);
999     }
1000
1001     void ret()
1002     {
1003         m_assembler.bx(linkRegister);
1004     }
1005
1006     void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
1007     {
1008         m_assembler.cmp(left, right);
1009         m_assembler.mov(dest, ARMAssembler::getOp2Byte(0));
1010         m_assembler.mov(dest, ARMAssembler::getOp2Byte(1), ARMCondition(cond));
1011     }
1012
1013     void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1014     {
1015         m_assembler.cmp(left, m_assembler.getImm(right.m_value, ARMRegisters::S0));
1016         m_assembler.mov(dest, ARMAssembler::getOp2Byte(0));
1017         m_assembler.mov(dest, ARMAssembler::getOp2Byte(1), ARMCondition(cond));
1018     }
1019
1020     void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest)
1021     {
1022         TrustedImm32 right8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, right);
1023         MacroAssemblerHelpers::load8OnCondition(*this, cond, left, ARMRegisters::S1);
1024         compare32(cond, ARMRegisters::S1, right8, dest);
1025     }
1026
1027     void test32(ResultCondition cond, RegisterID reg, TrustedImm32 mask, RegisterID dest)
1028     {
1029         if (mask.m_value == -1)
1030             m_assembler.tst(reg, reg);
1031         else
1032             m_assembler.tst(reg, m_assembler.getImm(mask.m_value, ARMRegisters::S0));
1033         m_assembler.mov(dest, ARMAssembler::getOp2Byte(0));
1034         m_assembler.mov(dest, ARMAssembler::getOp2Byte(1), ARMCondition(cond));
1035     }
1036
1037     void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1038     {
1039         load32(address, ARMRegisters::S1);
1040         test32(cond, ARMRegisters::S1, mask, dest);
1041     }
1042
1043     void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1044     {
1045         TrustedImm32 mask8 = MacroAssemblerHelpers::mask8OnCondition(*this, cond, mask);
1046         MacroAssemblerHelpers::load8OnCondition(*this, cond, address, ARMRegisters::S1);
1047         test32(cond, ARMRegisters::S1, mask8, dest);
1048     }
1049
1050     void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
1051     {
1052         m_assembler.add(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0));
1053     }
1054
1055     void add32(TrustedImm32 imm, AbsoluteAddress address)
1056     {
1057         load32(address.m_ptr, ARMRegisters::S1);
1058         add32(imm, ARMRegisters::S1);
1059         store32(ARMRegisters::S1, address.m_ptr);
1060     }
1061
1062     void add64(TrustedImm32 imm, AbsoluteAddress address)
1063     {
1064         ARMWord tmp;
1065
1066         move(TrustedImmPtr(address.m_ptr), ARMRegisters::S1);
1067         m_assembler.dtrUp(ARMAssembler::LoadUint32, ARMRegisters::S0, ARMRegisters::S1, 0);
1068
1069         if ((tmp = ARMAssembler::getOp2(imm.m_value)) != ARMAssembler::InvalidImmediate)
1070             m_assembler.adds(ARMRegisters::S0, ARMRegisters::S0, tmp);
1071         else if ((tmp = ARMAssembler::getOp2(-imm.m_value)) != ARMAssembler::InvalidImmediate)
1072             m_assembler.subs(ARMRegisters::S0, ARMRegisters::S0, tmp);
1073         else {
1074             m_assembler.adds(ARMRegisters::S0, ARMRegisters::S0, m_assembler.getImm(imm.m_value, ARMRegisters::S1));
1075             move(TrustedImmPtr(address.m_ptr), ARMRegisters::S1);
1076         }
1077         m_assembler.dtrUp(ARMAssembler::StoreUint32, ARMRegisters::S0, ARMRegisters::S1, 0);
1078
1079         m_assembler.dtrUp(ARMAssembler::LoadUint32, ARMRegisters::S0, ARMRegisters::S1, sizeof(ARMWord));
1080         if (imm.m_value >= 0)
1081             m_assembler.adc(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(0));
1082         else
1083             m_assembler.sbc(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(0));
1084         m_assembler.dtrUp(ARMAssembler::StoreUint32, ARMRegisters::S0, ARMRegisters::S1, sizeof(ARMWord));
1085     }
1086
1087     void sub32(TrustedImm32 imm, AbsoluteAddress address)
1088     {
1089         load32(address.m_ptr, ARMRegisters::S1);
1090         sub32(imm, ARMRegisters::S1);
1091         store32(ARMRegisters::S1, address.m_ptr);
1092     }
1093
1094     void load32(const void* address, RegisterID dest)
1095     {
1096         m_assembler.ldrUniqueImmediate(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
1097         m_assembler.dtrUp(ARMAssembler::LoadUint32, dest, ARMRegisters::S0, 0);
1098     }
1099
1100     Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
1101     {
1102         load32(left.m_ptr, ARMRegisters::S1);
1103         return branch32(cond, ARMRegisters::S1, right);
1104     }
1105
1106     Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
1107     {
1108         load32(left.m_ptr, ARMRegisters::S1);
1109         return branch32(cond, ARMRegisters::S1, right);
1110     }
1111
1112     void relativeTableJump(RegisterID index, int scale)
1113     {
1114         ASSERT(scale >= 0 && scale <= 31);
1115         m_assembler.add(ARMRegisters::pc, ARMRegisters::pc, m_assembler.lsl(index, scale));
1116
1117         // NOP the default prefetching
1118         m_assembler.mov(ARMRegisters::r0, ARMRegisters::r0);
1119     }
1120
1121     Call call(PtrTag)
1122     {
1123         ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord));
1124         m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true);
1125         return Call(m_assembler.blx(ARMRegisters::S1), Call::Linkable);
1126     }
1127
1128     Call tailRecursiveCall()
1129     {
1130         return Call::fromTailJump(jump());
1131     }
1132
1133     Call makeTailRecursiveCall(Jump oldJump)
1134     {
1135         return Call::fromTailJump(oldJump);
1136     }
1137
1138     DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
1139     {
1140         DataLabelPtr dataLabel(this);
1141         m_assembler.ldrUniqueImmediate(dest, reinterpret_cast<ARMWord>(initialValue.m_value));
1142         return dataLabel;
1143     }
1144
1145     DataLabel32 moveWithPatch(TrustedImm32 initialValue, RegisterID dest)
1146     {
1147         DataLabel32 dataLabel(this);
1148         m_assembler.ldrUniqueImmediate(dest, static_cast<ARMWord>(initialValue.m_value));
1149         return dataLabel;
1150     }
1151
1152     Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(nullptr))
1153     {
1154         ensureSpace(3 * sizeof(ARMWord), 2 * sizeof(ARMWord));
1155         dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S1);
1156         Jump jump = branch32(cond, left, ARMRegisters::S1, true);
1157         return jump;
1158     }
1159
1160     Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(nullptr))
1161     {
1162         load32(left, ARMRegisters::S1);
1163         ensureSpace(3 * sizeof(ARMWord), 2 * sizeof(ARMWord));
1164         dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S0);
1165         Jump jump = branch32(cond, ARMRegisters::S0, ARMRegisters::S1, true);
1166         return jump;
1167     }
1168
1169     Jump branch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0))
1170     {
1171         load32(left, ARMRegisters::S1);
1172         ensureSpace(3 * sizeof(ARMWord), 2 * sizeof(ARMWord));
1173         dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S0);
1174         Jump jump = branch32(cond, ARMRegisters::S0, ARMRegisters::S1, true);
1175         return jump;
1176     }
1177
1178     DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
1179     {
1180         DataLabelPtr dataLabel = moveWithPatch(initialValue, ARMRegisters::S1);
1181         store32(ARMRegisters::S1, address);
1182         return dataLabel;
1183     }
1184
1185     DataLabelPtr storePtrWithPatch(ImplicitAddress address)
1186     {
1187         return storePtrWithPatch(TrustedImmPtr(nullptr), address);
1188     }
1189
1190     // Floating point operators
1191     static bool supportsFloatingPoint()
1192     {
1193         return s_isVFPPresent;
1194     }
1195
1196     static bool supportsFloatingPointTruncate()
1197     {
1198         return false;
1199     }
1200
1201     static bool supportsFloatingPointSqrt()
1202     {
1203         return s_isVFPPresent;
1204     }
1205     static bool supportsFloatingPointAbs() { return false; }
1206     static bool supportsFloatingPointRounding() { return false; }
1207
1208
1209     void loadFloat(ImplicitAddress address, FPRegisterID dest)
1210     {
1211         m_assembler.dataTransferFloat(ARMAssembler::LoadFloat, dest, address.base, address.offset);
1212     }
1213
1214     void loadFloat(BaseIndex address, FPRegisterID dest)
1215     {
1216         m_assembler.baseIndexTransferFloat(ARMAssembler::LoadFloat, dest, address.base, address.index, static_cast<int>(address.scale), address.offset);
1217     }
1218
1219     void loadDouble(ImplicitAddress address, FPRegisterID dest)
1220     {
1221         m_assembler.dataTransferFloat(ARMAssembler::LoadDouble, dest, address.base, address.offset);
1222     }
1223
1224     void loadDouble(BaseIndex address, FPRegisterID dest)
1225     {
1226         m_assembler.baseIndexTransferFloat(ARMAssembler::LoadDouble, dest, address.base, address.index, static_cast<int>(address.scale), address.offset);
1227     }
1228
1229     void loadDouble(TrustedImmPtr address, FPRegisterID dest)
1230     {
1231         move(TrustedImm32(reinterpret_cast<ARMWord>(address.m_value)), ARMRegisters::S0);
1232         m_assembler.doubleDtrUp(ARMAssembler::LoadDouble, dest, ARMRegisters::S0, 0);
1233     }
1234
1235     NO_RETURN_DUE_TO_CRASH void ceilDouble(FPRegisterID, FPRegisterID)
1236     {
1237         ASSERT(!supportsFloatingPointRounding());
1238         CRASH();
1239     }
1240
1241     NO_RETURN_DUE_TO_CRASH void floorDouble(FPRegisterID, FPRegisterID)
1242     {
1243         ASSERT(!supportsFloatingPointRounding());
1244         CRASH();
1245     }
1246
1247     NO_RETURN_DUE_TO_CRASH void roundTowardZeroDouble(FPRegisterID, FPRegisterID)
1248     {
1249         ASSERT(!supportsFloatingPointRounding());
1250         CRASH();
1251     }
1252
1253     void storeFloat(FPRegisterID src, ImplicitAddress address)
1254     {
1255         m_assembler.dataTransferFloat(ARMAssembler::StoreFloat, src, address.base, address.offset);
1256     }
1257
1258     void storeFloat(FPRegisterID src, BaseIndex address)
1259     {
1260         m_assembler.baseIndexTransferFloat(ARMAssembler::StoreFloat, src, address.base, address.index, static_cast<int>(address.scale), address.offset);
1261     }
1262
1263     void storeDouble(FPRegisterID src, ImplicitAddress address)
1264     {
1265         m_assembler.dataTransferFloat(ARMAssembler::StoreDouble, src, address.base, address.offset);
1266     }
1267
1268     void storeDouble(FPRegisterID src, BaseIndex address)
1269     {
1270         m_assembler.baseIndexTransferFloat(ARMAssembler::StoreDouble, src, address.base, address.index, static_cast<int>(address.scale), address.offset);
1271     }
1272
1273     void storeDouble(FPRegisterID src, TrustedImmPtr address)
1274     {
1275         move(TrustedImm32(reinterpret_cast<ARMWord>(address.m_value)), ARMRegisters::S0);
1276         m_assembler.dataTransferFloat(ARMAssembler::StoreDouble, src, ARMRegisters::S0, 0);
1277     }
1278
1279     void moveDouble(FPRegisterID src, FPRegisterID dest)
1280     {
1281         if (src != dest)
1282             m_assembler.vmov_f64(dest, src);
1283     }
1284
1285     void moveZeroToDouble(FPRegisterID reg)
1286     {
1287         static double zeroConstant = 0.;
1288         loadDouble(TrustedImmPtr(&zeroConstant), reg);
1289     }
1290
1291     void addDouble(FPRegisterID src, FPRegisterID dest)
1292     {
1293         m_assembler.vadd_f64(dest, dest, src);
1294     }
1295
1296     void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1297     {
1298         m_assembler.vadd_f64(dest, op1, op2);
1299     }
1300
1301     void addDouble(Address src, FPRegisterID dest)
1302     {
1303         loadDouble(src, ARMRegisters::SD0);
1304         addDouble(ARMRegisters::SD0, dest);
1305     }
1306
1307     void addDouble(AbsoluteAddress address, FPRegisterID dest)
1308     {
1309         loadDouble(TrustedImmPtr(address.m_ptr), ARMRegisters::SD0);
1310         addDouble(ARMRegisters::SD0, dest);
1311     }
1312
1313     void divDouble(FPRegisterID src, FPRegisterID dest)
1314     {
1315         m_assembler.vdiv_f64(dest, dest, src);
1316     }
1317
1318     void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1319     {
1320         m_assembler.vdiv_f64(dest, op1, op2);
1321     }
1322
1323     void divDouble(Address src, FPRegisterID dest)
1324     {
1325         RELEASE_ASSERT_NOT_REACHED(); // Untested
1326         loadDouble(src, ARMRegisters::SD0);
1327         divDouble(ARMRegisters::SD0, dest);
1328     }
1329
1330     void subDouble(FPRegisterID src, FPRegisterID dest)
1331     {
1332         m_assembler.vsub_f64(dest, dest, src);
1333     }
1334
1335     void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1336     {
1337         m_assembler.vsub_f64(dest, op1, op2);
1338     }
1339
1340     void subDouble(Address src, FPRegisterID dest)
1341     {
1342         loadDouble(src, ARMRegisters::SD0);
1343         subDouble(ARMRegisters::SD0, dest);
1344     }
1345
1346     void mulDouble(FPRegisterID src, FPRegisterID dest)
1347     {
1348         m_assembler.vmul_f64(dest, dest, src);
1349     }
1350
1351     void mulDouble(Address src, FPRegisterID dest)
1352     {
1353         loadDouble(src, ARMRegisters::SD0);
1354         mulDouble(ARMRegisters::SD0, dest);
1355     }
1356
1357     void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1358     {
1359         m_assembler.vmul_f64(dest, op1, op2);
1360     }
1361
1362     void sqrtDouble(FPRegisterID src, FPRegisterID dest)
1363     {
1364         m_assembler.vsqrt_f64(dest, src);
1365     }
1366     
1367     void absDouble(FPRegisterID src, FPRegisterID dest)
1368     {
1369         m_assembler.vabs_f64(dest, src);
1370     }
1371
1372     void negateDouble(FPRegisterID src, FPRegisterID dest)
1373     {
1374         m_assembler.vneg_f64(dest, src);
1375     }
1376
1377     void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
1378     {
1379         m_assembler.vmov_vfp32(dest << 1, src);
1380         m_assembler.vcvt_f64_s32(dest, dest << 1);
1381     }
1382
1383     void convertInt32ToDouble(Address src, FPRegisterID dest)
1384     {
1385         load32(src, ARMRegisters::S1);
1386         convertInt32ToDouble(ARMRegisters::S1, dest);
1387     }
1388
1389     void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
1390     {
1391         move(TrustedImmPtr(src.m_ptr), ARMRegisters::S1);
1392         load32(Address(ARMRegisters::S1), ARMRegisters::S1);
1393         convertInt32ToDouble(ARMRegisters::S1, dest);
1394     }
1395
1396     void convertFloatToDouble(FPRegisterID src, FPRegisterID dst)
1397     {
1398         m_assembler.vcvt_f64_f32(dst, src);
1399     }
1400
1401     void convertDoubleToFloat(FPRegisterID src, FPRegisterID dst)
1402     {
1403         m_assembler.vcvt_f32_f64(dst, src);
1404     }
1405
1406     Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
1407     {
1408         m_assembler.vcmp_f64(left, right);
1409         m_assembler.vmrs_apsr();
1410         if (cond & DoubleConditionBitSpecial)
1411             m_assembler.cmp(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::VS);
1412         return Jump(m_assembler.jmp(static_cast<ARMAssembler::Condition>(cond & ~DoubleConditionMask)));
1413     }
1414
1415     // Truncates 'src' to an integer, and places the resulting 'dest'.
1416     // If the result is not representable as a 32 bit value, branch.
1417     // May also branch for some values that are representable in 32 bits
1418     // (specifically, in this case, INT_MIN).
1419     enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
1420     Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
1421     {
1422         truncateDoubleToInt32(src, dest);
1423
1424         m_assembler.add(ARMRegisters::S0, dest, ARMAssembler::getOp2Byte(1));
1425         m_assembler.bic(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(1));
1426
1427         ARMWord w = ARMAssembler::getOp2(0x80000000);
1428         ASSERT(w != ARMAssembler::InvalidImmediate);
1429         m_assembler.cmp(ARMRegisters::S0, w);
1430         return Jump(m_assembler.jmp(branchType == BranchIfTruncateFailed ? ARMAssembler::EQ : ARMAssembler::NE));
1431     }
1432
1433     // Result is undefined if the value is outside of the integer range.
1434     void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
1435     {
1436         m_assembler.vcvt_s32_f64(ARMRegisters::SD0 << 1, src);
1437         m_assembler.vmov_arm32(dest, ARMRegisters::SD0 << 1);
1438     }
1439
1440     void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
1441     {
1442         m_assembler.vcvt_u32_f64(ARMRegisters::SD0 << 1, src);
1443         m_assembler.vmov_arm32(dest, ARMRegisters::SD0 << 1);
1444     }
1445
1446     // Convert 'src' to an integer, and places the resulting 'dest'.
1447     // If the result is not representable as a 32 bit value, branch.
1448     // May also branch for some values that are representable in 32 bits
1449     // (specifically, in this case, 0).
1450     void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID, bool negZeroCheck = true)
1451     {
1452         m_assembler.vcvt_s32_f64(ARMRegisters::SD0 << 1, src);
1453         m_assembler.vmov_arm32(dest, ARMRegisters::SD0 << 1);
1454
1455         // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
1456         m_assembler.vcvt_f64_s32(ARMRegisters::SD0, ARMRegisters::SD0 << 1);
1457         failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, ARMRegisters::SD0));
1458
1459         // If the result is zero, it might have been -0.0, and 0.0 equals to -0.0
1460         if (negZeroCheck)
1461             failureCases.append(branchTest32(Zero, dest));
1462     }
1463
1464     Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
1465     {
1466         m_assembler.mov(ARMRegisters::S0, ARMAssembler::getOp2Byte(0));
1467         convertInt32ToDouble(ARMRegisters::S0, scratch);
1468         return branchDouble(DoubleNotEqual, reg, scratch);
1469     }
1470
1471     Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch)
1472     {
1473         m_assembler.mov(ARMRegisters::S0, ARMAssembler::getOp2Byte(0));
1474         convertInt32ToDouble(ARMRegisters::S0, scratch);
1475         return branchDouble(DoubleEqualOrUnordered, reg, scratch);
1476     }
1477
1478     // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
1479     static RelationalCondition invert(RelationalCondition cond)
1480     {
1481         ASSERT((static_cast<uint32_t>(cond & 0x0fffffff)) == 0 && static_cast<uint32_t>(cond) < static_cast<uint32_t>(ARMAssembler::AL));
1482         return static_cast<RelationalCondition>(cond ^ 0x10000000);
1483     }
1484
1485     void nop()
1486     {
1487         m_assembler.nop();
1488     }
1489
1490     void memoryFence()
1491     {
1492         m_assembler.dmbSY();
1493     }
1494
1495     void storeFence()
1496     {
1497         m_assembler.dmbISHST();
1498     }
1499
1500     static FunctionPtr readCallTarget(CodeLocationCall call)
1501     {
1502         return FunctionPtr(reinterpret_cast<void(*)()>(ARMAssembler::readCallTarget(call.dataLocation())), CodeEntryPtrTag);
1503     }
1504
1505     static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
1506     {
1507         ARMAssembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
1508     }
1509     
1510     static ptrdiff_t maxJumpReplacementSize()
1511     {
1512         return ARMAssembler::maxJumpReplacementSize();
1513     }
1514
1515     static ptrdiff_t patchableJumpSize()
1516     {
1517         return ARMAssembler::patchableJumpSize();
1518     }
1519
1520     static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; }
1521     static bool canJumpReplacePatchableBranch32WithPatch() { return false; }
1522
1523     static CodeLocationLabel startOfPatchableBranch32WithPatchOnAddress(CodeLocationDataLabel32)
1524     {
1525         UNREACHABLE_FOR_PLATFORM();
1526         return CodeLocationLabel();
1527     }
1528
1529     static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr)
1530     {
1531         UNREACHABLE_FOR_PLATFORM();
1532         return CodeLocationLabel();
1533     }
1534
1535     static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label)
1536     {
1537         return label.labelAtOffset(0);
1538     }
1539
1540     static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID reg, void* initialValue)
1541     {
1542         ARMAssembler::revertBranchPtrWithPatch(instructionStart.dataLocation(), reg, reinterpret_cast<uintptr_t>(initialValue) & 0xffff);
1543     }
1544
1545     static void revertJumpReplacementToPatchableBranch32WithPatch(CodeLocationLabel, Address, int32_t)
1546     {
1547         UNREACHABLE_FOR_PLATFORM();
1548     }
1549
1550     static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel, Address, void*)
1551     {
1552         UNREACHABLE_FOR_PLATFORM();
1553     }
1554
1555     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
1556     {
1557         ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
1558     }
1559
1560     static void repatchCall(CodeLocationCall call, FunctionPtr destination)
1561     {
1562         ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
1563     }
1564
1565 protected:
1566     ARMAssembler::Condition ARMCondition(RelationalCondition cond)
1567     {
1568         return static_cast<ARMAssembler::Condition>(cond);
1569     }
1570
1571     ARMAssembler::Condition ARMCondition(ResultCondition cond)
1572     {
1573         return static_cast<ARMAssembler::Condition>(cond);
1574     }
1575
1576     void ensureSpace(int insnSpace, int constSpace)
1577     {
1578         m_assembler.ensureSpace(insnSpace, constSpace);
1579     }
1580
1581     int sizeOfConstantPool()
1582     {
1583         return m_assembler.sizeOfConstantPool();
1584     }
1585
1586     void call32(RegisterID base, int32_t offset)
1587     {
1588         load32(Address(base, offset), ARMRegisters::S1);
1589         m_assembler.blx(ARMRegisters::S1);
1590     }
1591
1592 private:
1593     friend class LinkBuffer;
1594
1595     void internalCompare32(RegisterID left, TrustedImm32 right)
1596     {
1597         ARMWord tmp = (!right.m_value || static_cast<unsigned>(right.m_value) == 0x80000000) ? ARMAssembler::InvalidImmediate : m_assembler.getOp2(-right.m_value);
1598         if (tmp != ARMAssembler::InvalidImmediate)
1599             m_assembler.cmn(left, tmp);
1600         else
1601             m_assembler.cmp(left, m_assembler.getImm(right.m_value, ARMRegisters::S0));
1602     }
1603
1604     void internalCompare32(Address left, TrustedImm32 right)
1605     {
1606         ARMWord tmp = (!right.m_value || static_cast<unsigned>(right.m_value) == 0x80000000) ? ARMAssembler::InvalidImmediate : m_assembler.getOp2(-right.m_value);
1607         load32(left, ARMRegisters::S1);
1608         if (tmp != ARMAssembler::InvalidImmediate)
1609             m_assembler.cmn(ARMRegisters::S1, tmp);
1610         else
1611             m_assembler.cmp(ARMRegisters::S1, m_assembler.getImm(right.m_value, ARMRegisters::S0));
1612     }
1613
1614     static void linkCall(void* code, Call call, FunctionPtr function)
1615     {
1616         if (call.isFlagSet(Call::Tail))
1617             ARMAssembler::linkJump(code, call.m_label, function.value());
1618         else
1619             ARMAssembler::linkCall(code, call.m_label, function.value());
1620     }
1621
1622     static const bool s_isVFPPresent;
1623 };
1624
1625 } // namespace JSC
1626
1627 #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)