2 * Copyright (C) 2009-2010, 2014-2015 Apple Inc. All rights reserved.
3 * Copyright (C) 2010 University of Szeged
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
27 #ifndef MacroAssemblerARMv7_h
28 #define MacroAssemblerARMv7_h
32 #include "ARMv7Assembler.h"
33 #include "AbstractMacroAssembler.h"
37 class MacroAssemblerARMv7 : public AbstractMacroAssembler<ARMv7Assembler, MacroAssemblerARMv7> {
38 static const RegisterID dataTempRegister = ARMRegisters::ip;
39 static const RegisterID addressTempRegister = ARMRegisters::r6;
41 static const ARMRegisters::FPDoubleRegisterID fpTempRegister = ARMRegisters::d7;
42 inline ARMRegisters::FPSingleRegisterID fpTempRegisterAsSingle() { return ARMRegisters::asSingle(fpTempRegister); }
45 static const unsigned numGPRs = 16;
46 static const unsigned numFPRs = 16;
49 : m_makeJumpPatchable(false)
53 typedef ARMv7Assembler::LinkRecord LinkRecord;
54 typedef ARMv7Assembler::JumpType JumpType;
55 typedef ARMv7Assembler::JumpLinkType JumpLinkType;
56 typedef ARMv7Assembler::Condition Condition;
58 static const ARMv7Assembler::Condition DefaultCondition = ARMv7Assembler::ConditionInvalid;
59 static const ARMv7Assembler::JumpType DefaultJump = ARMv7Assembler::JumpNoConditionFixedSize;
61 static bool isCompactPtrAlignedAddressOffset(ptrdiff_t value)
63 return value >= -255 && value <= 255;
66 Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink() { return m_assembler.jumpsToLink(); }
67 void* unlinkedCode() { return m_assembler.unlinkedCode(); }
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 static void link(LinkRecord& record, uint8_t* from, const uint8_t* fromInstruction, uint8_t* to) { return ARMv7Assembler::link(record, from, fromInstruction, to); }
88 explicit ArmAddress(RegisterID base, int32_t offset = 0)
95 explicit ArmAddress(RegisterID base, RegisterID index, Scale scale = TimesOne)
105 static const Scale ScalePtr = TimesFour;
107 enum RelationalCondition {
108 Equal = ARMv7Assembler::ConditionEQ,
109 NotEqual = ARMv7Assembler::ConditionNE,
110 Above = ARMv7Assembler::ConditionHI,
111 AboveOrEqual = ARMv7Assembler::ConditionHS,
112 Below = ARMv7Assembler::ConditionLO,
113 BelowOrEqual = ARMv7Assembler::ConditionLS,
114 GreaterThan = ARMv7Assembler::ConditionGT,
115 GreaterThanOrEqual = ARMv7Assembler::ConditionGE,
116 LessThan = ARMv7Assembler::ConditionLT,
117 LessThanOrEqual = ARMv7Assembler::ConditionLE
120 enum ResultCondition {
121 Overflow = ARMv7Assembler::ConditionVS,
122 Signed = ARMv7Assembler::ConditionMI,
123 PositiveOrZero = ARMv7Assembler::ConditionPL,
124 Zero = ARMv7Assembler::ConditionEQ,
125 NonZero = ARMv7Assembler::ConditionNE
128 enum DoubleCondition {
129 // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
130 DoubleEqual = ARMv7Assembler::ConditionEQ,
131 DoubleNotEqual = ARMv7Assembler::ConditionVC, // Not the right flag! check for this & handle differently.
132 DoubleGreaterThan = ARMv7Assembler::ConditionGT,
133 DoubleGreaterThanOrEqual = ARMv7Assembler::ConditionGE,
134 DoubleLessThan = ARMv7Assembler::ConditionLO,
135 DoubleLessThanOrEqual = ARMv7Assembler::ConditionLS,
136 // If either operand is NaN, these conditions always evaluate to true.
137 DoubleEqualOrUnordered = ARMv7Assembler::ConditionVS, // Not the right flag! check for this & handle differently.
138 DoubleNotEqualOrUnordered = ARMv7Assembler::ConditionNE,
139 DoubleGreaterThanOrUnordered = ARMv7Assembler::ConditionHI,
140 DoubleGreaterThanOrEqualOrUnordered = ARMv7Assembler::ConditionHS,
141 DoubleLessThanOrUnordered = ARMv7Assembler::ConditionLT,
142 DoubleLessThanOrEqualOrUnordered = ARMv7Assembler::ConditionLE,
145 static const RegisterID stackPointerRegister = ARMRegisters::sp;
146 static const RegisterID framePointerRegister = ARMRegisters::fp;
147 static const RegisterID linkRegister = ARMRegisters::lr;
149 // Integer arithmetic operations:
151 // Operations are typically two operand - operation(source, srcDst)
152 // For many operations the source may be an TrustedImm32, the srcDst operand
153 // may often be a memory location (explictly described using an Address
156 void add32(RegisterID src, RegisterID dest)
158 m_assembler.add(dest, dest, src);
161 void add32(RegisterID left, RegisterID right, RegisterID dest)
163 m_assembler.add(dest, left, right);
166 void add32(TrustedImm32 imm, RegisterID dest)
168 add32(imm, dest, dest);
171 void add32(AbsoluteAddress src, RegisterID dest)
173 load32(src.m_ptr, dataTempRegister);
174 add32(dataTempRegister, dest);
177 void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
179 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
181 // For adds with stack pointer destination, moving the src first to sp is
182 // needed to avoid unpredictable instruction
183 if (dest == ARMRegisters::sp && src != dest) {
184 move(src, ARMRegisters::sp);
185 src = ARMRegisters::sp;
188 if (armImm.isValid())
189 m_assembler.add(dest, src, armImm);
191 move(imm, dataTempRegister);
192 m_assembler.add(dest, src, dataTempRegister);
196 void add32(TrustedImm32 imm, Address address)
198 load32(address, dataTempRegister);
200 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
201 if (armImm.isValid())
202 m_assembler.add(dataTempRegister, dataTempRegister, armImm);
204 // Hrrrm, since dataTempRegister holds the data loaded,
205 // use addressTempRegister to hold the immediate.
206 move(imm, addressTempRegister);
207 m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister);
210 store32(dataTempRegister, address);
213 void add32(Address src, RegisterID dest)
215 load32(src, dataTempRegister);
216 add32(dataTempRegister, dest);
219 void add32(TrustedImm32 imm, AbsoluteAddress address)
221 load32(address.m_ptr, dataTempRegister);
223 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
224 if (armImm.isValid())
225 m_assembler.add(dataTempRegister, dataTempRegister, armImm);
227 // Hrrrm, since dataTempRegister holds the data loaded,
228 // use addressTempRegister to hold the immediate.
229 move(imm, addressTempRegister);
230 m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister);
233 store32(dataTempRegister, address.m_ptr);
236 void addPtrNoFlags(TrustedImm32 imm, RegisterID srcDest)
241 void add64(TrustedImm32 imm, AbsoluteAddress address)
243 move(TrustedImmPtr(address.m_ptr), addressTempRegister);
245 m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(0));
246 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
247 if (armImm.isValid())
248 m_assembler.add_S(dataTempRegister, dataTempRegister, armImm);
250 move(imm, addressTempRegister);
251 m_assembler.add_S(dataTempRegister, dataTempRegister, addressTempRegister);
252 move(TrustedImmPtr(address.m_ptr), addressTempRegister);
254 m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(0));
256 m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(4));
257 m_assembler.adc(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(imm.m_value >> 31));
258 m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(4));
261 void and32(RegisterID op1, RegisterID op2, RegisterID dest)
263 m_assembler.ARM_and(dest, op1, op2);
266 void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
268 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
269 if (armImm.isValid())
270 m_assembler.ARM_and(dest, src, armImm);
272 move(imm, dataTempRegister);
273 m_assembler.ARM_and(dest, src, dataTempRegister);
277 void and32(RegisterID src, RegisterID dest)
279 and32(dest, src, dest);
282 void and32(TrustedImm32 imm, RegisterID dest)
284 and32(imm, dest, dest);
287 void and32(Address src, RegisterID dest)
289 load32(src, dataTempRegister);
290 and32(dataTempRegister, dest);
293 void countLeadingZeros32(RegisterID src, RegisterID dest)
295 m_assembler.clz(dest, src);
298 void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
300 // Clamp the shift to the range 0..31
301 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
302 ASSERT(armImm.isValid());
303 m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
305 m_assembler.lsl(dest, src, dataTempRegister);
308 void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
310 m_assembler.lsl(dest, src, imm.m_value & 0x1f);
313 void lshift32(RegisterID shiftAmount, RegisterID dest)
315 lshift32(dest, shiftAmount, dest);
318 void lshift32(TrustedImm32 imm, RegisterID dest)
320 lshift32(dest, imm, dest);
323 void mul32(RegisterID src, RegisterID dest)
325 m_assembler.smull(dest, dataTempRegister, dest, src);
328 void mul32(RegisterID left, RegisterID right, RegisterID dest)
330 m_assembler.smull(dest, dataTempRegister, left, right);
333 void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
335 move(imm, dataTempRegister);
336 m_assembler.smull(dest, dataTempRegister, src, dataTempRegister);
339 void neg32(RegisterID srcDest)
341 m_assembler.neg(srcDest, srcDest);
344 void or32(RegisterID src, RegisterID dest)
346 m_assembler.orr(dest, dest, src);
349 void or32(RegisterID src, AbsoluteAddress dest)
351 move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
352 load32(addressTempRegister, dataTempRegister);
353 or32(src, dataTempRegister);
354 store32(dataTempRegister, addressTempRegister);
357 void or32(TrustedImm32 imm, AbsoluteAddress address)
359 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
360 if (armImm.isValid()) {
361 move(TrustedImmPtr(address.m_ptr), addressTempRegister);
362 load32(addressTempRegister, dataTempRegister);
363 m_assembler.orr(dataTempRegister, dataTempRegister, armImm);
364 store32(dataTempRegister, addressTempRegister);
366 move(TrustedImmPtr(address.m_ptr), addressTempRegister);
367 load32(addressTempRegister, dataTempRegister);
368 move(imm, addressTempRegister);
369 m_assembler.orr(dataTempRegister, dataTempRegister, addressTempRegister);
370 move(TrustedImmPtr(address.m_ptr), addressTempRegister);
371 store32(dataTempRegister, addressTempRegister);
375 void or32(TrustedImm32 imm, Address address)
377 load32(address, dataTempRegister);
378 or32(imm, dataTempRegister, dataTempRegister);
379 store32(dataTempRegister, address);
382 void or32(TrustedImm32 imm, RegisterID dest)
384 or32(imm, dest, dest);
387 void or32(RegisterID op1, RegisterID op2, RegisterID dest)
389 m_assembler.orr(dest, op1, op2);
392 void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
394 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
395 if (armImm.isValid())
396 m_assembler.orr(dest, src, armImm);
398 ASSERT(src != dataTempRegister);
399 move(imm, dataTempRegister);
400 m_assembler.orr(dest, src, dataTempRegister);
404 void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
406 // Clamp the shift to the range 0..31
407 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
408 ASSERT(armImm.isValid());
409 m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
411 m_assembler.asr(dest, src, dataTempRegister);
414 void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
419 m_assembler.asr(dest, src, imm.m_value & 0x1f);
422 void rshift32(RegisterID shiftAmount, RegisterID dest)
424 rshift32(dest, shiftAmount, dest);
427 void rshift32(TrustedImm32 imm, RegisterID dest)
429 rshift32(dest, imm, dest);
432 void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
434 // Clamp the shift to the range 0..31
435 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
436 ASSERT(armImm.isValid());
437 m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm);
439 m_assembler.lsr(dest, src, dataTempRegister);
442 void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
447 m_assembler.lsr(dest, src, imm.m_value & 0x1f);
450 void urshift32(RegisterID shiftAmount, RegisterID dest)
452 urshift32(dest, shiftAmount, dest);
455 void urshift32(TrustedImm32 imm, RegisterID dest)
457 urshift32(dest, imm, dest);
460 void sub32(RegisterID src, RegisterID dest)
462 m_assembler.sub(dest, dest, src);
465 void sub32(TrustedImm32 imm, RegisterID dest)
467 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
468 if (armImm.isValid())
469 m_assembler.sub(dest, dest, armImm);
471 move(imm, dataTempRegister);
472 m_assembler.sub(dest, dest, dataTempRegister);
476 void sub32(TrustedImm32 imm, Address address)
478 load32(address, dataTempRegister);
480 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
481 if (armImm.isValid())
482 m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
484 // Hrrrm, since dataTempRegister holds the data loaded,
485 // use addressTempRegister to hold the immediate.
486 move(imm, addressTempRegister);
487 m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
490 store32(dataTempRegister, address);
493 void sub32(Address src, RegisterID dest)
495 load32(src, dataTempRegister);
496 sub32(dataTempRegister, dest);
499 void sub32(TrustedImm32 imm, AbsoluteAddress address)
501 load32(address.m_ptr, dataTempRegister);
503 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value);
504 if (armImm.isValid())
505 m_assembler.sub(dataTempRegister, dataTempRegister, armImm);
507 // Hrrrm, since dataTempRegister holds the data loaded,
508 // use addressTempRegister to hold the immediate.
509 move(imm, addressTempRegister);
510 m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister);
513 store32(dataTempRegister, address.m_ptr);
516 void xor32(RegisterID op1, RegisterID op2, RegisterID dest)
518 m_assembler.eor(dest, op1, op2);
521 void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
523 if (imm.m_value == -1) {
524 m_assembler.mvn(dest, src);
528 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
529 if (armImm.isValid())
530 m_assembler.eor(dest, src, armImm);
532 move(imm, dataTempRegister);
533 m_assembler.eor(dest, src, dataTempRegister);
537 void xor32(RegisterID src, RegisterID dest)
539 xor32(dest, src, dest);
542 void xor32(TrustedImm32 imm, RegisterID dest)
544 if (imm.m_value == -1)
545 m_assembler.mvn(dest, dest);
547 xor32(imm, dest, dest);
551 // Memory access operations:
553 // Loads are of the form load(address, destination) and stores of the form
554 // store(source, address). The source for a store may be an TrustedImm32. Address
555 // operand objects to loads and store will be implicitly constructed if a
556 // register is passed.
559 void load32(ArmAddress address, RegisterID dest)
561 if (address.type == ArmAddress::HasIndex)
562 m_assembler.ldr(dest, address.base, address.u.index, address.u.scale);
563 else if (address.u.offset >= 0) {
564 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
565 ASSERT(armImm.isValid());
566 m_assembler.ldr(dest, address.base, armImm);
568 ASSERT(address.u.offset >= -255);
569 m_assembler.ldr(dest, address.base, address.u.offset, true, false);
573 void load16(ArmAddress address, RegisterID dest)
575 if (address.type == ArmAddress::HasIndex)
576 m_assembler.ldrh(dest, address.base, address.u.index, address.u.scale);
577 else if (address.u.offset >= 0) {
578 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
579 ASSERT(armImm.isValid());
580 m_assembler.ldrh(dest, address.base, armImm);
582 ASSERT(address.u.offset >= -255);
583 m_assembler.ldrh(dest, address.base, address.u.offset, true, false);
587 void load16SignedExtendTo32(ArmAddress address, RegisterID dest)
589 ASSERT(address.type == ArmAddress::HasIndex);
590 m_assembler.ldrsh(dest, address.base, address.u.index, address.u.scale);
593 void load8(ArmAddress address, RegisterID dest)
595 if (address.type == ArmAddress::HasIndex)
596 m_assembler.ldrb(dest, address.base, address.u.index, address.u.scale);
597 else if (address.u.offset >= 0) {
598 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
599 ASSERT(armImm.isValid());
600 m_assembler.ldrb(dest, address.base, armImm);
602 ASSERT(address.u.offset >= -255);
603 m_assembler.ldrb(dest, address.base, address.u.offset, true, false);
607 void load8SignedExtendTo32(ArmAddress address, RegisterID dest)
609 ASSERT(address.type == ArmAddress::HasIndex);
610 m_assembler.ldrsb(dest, address.base, address.u.index, address.u.scale);
614 void store32(RegisterID src, ArmAddress address)
616 if (address.type == ArmAddress::HasIndex)
617 m_assembler.str(src, address.base, address.u.index, address.u.scale);
618 else if (address.u.offset >= 0) {
619 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
620 ASSERT(armImm.isValid());
621 m_assembler.str(src, address.base, armImm);
623 ASSERT(address.u.offset >= -255);
624 m_assembler.str(src, address.base, address.u.offset, true, false);
629 void store8(RegisterID src, ArmAddress address)
631 if (address.type == ArmAddress::HasIndex)
632 m_assembler.strb(src, address.base, address.u.index, address.u.scale);
633 else if (address.u.offset >= 0) {
634 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
635 ASSERT(armImm.isValid());
636 m_assembler.strb(src, address.base, armImm);
638 ASSERT(address.u.offset >= -255);
639 m_assembler.strb(src, address.base, address.u.offset, true, false);
643 void store16(RegisterID src, ArmAddress address)
645 if (address.type == ArmAddress::HasIndex)
646 m_assembler.strh(src, address.base, address.u.index, address.u.scale);
647 else if (address.u.offset >= 0) {
648 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset);
649 ASSERT(armImm.isValid());
650 m_assembler.strh(src, address.base, armImm);
652 ASSERT(address.u.offset >= -255);
653 m_assembler.strh(src, address.base, address.u.offset, true, false);
658 void load32(ImplicitAddress address, RegisterID dest)
660 load32(setupArmAddress(address), dest);
663 void load32(BaseIndex address, RegisterID dest)
665 load32(setupArmAddress(address), dest);
668 void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
670 load32(setupArmAddress(address), dest);
673 void load16Unaligned(BaseIndex address, RegisterID dest)
675 load16(setupArmAddress(address), dest);
678 void load32(const void* address, RegisterID dest)
680 move(TrustedImmPtr(address), addressTempRegister);
681 m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
684 void abortWithReason(AbortReason reason)
686 move(TrustedImm32(reason), dataTempRegister);
690 void abortWithReason(AbortReason reason, intptr_t misc)
692 move(TrustedImm32(misc), addressTempRegister);
693 abortWithReason(reason);
696 ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
698 ConvertibleLoadLabel result(this);
699 ASSERT(address.offset >= 0 && address.offset <= 255);
700 m_assembler.ldrWide8BitImmediate(dest, address.base, address.offset);
704 void load8(ImplicitAddress address, RegisterID dest)
706 load8(setupArmAddress(address), dest);
709 void load8SignedExtendTo32(ImplicitAddress, RegisterID)
711 UNREACHABLE_FOR_PLATFORM();
714 void load8(BaseIndex address, RegisterID dest)
716 load8(setupArmAddress(address), dest);
719 void load8SignedExtendTo32(BaseIndex address, RegisterID dest)
721 load8SignedExtendTo32(setupArmAddress(address), dest);
724 void load8(const void* address, RegisterID dest)
726 move(TrustedImmPtr(address), dest);
730 DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
732 DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
733 load32(ArmAddress(address.base, dataTempRegister), dest);
737 DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest)
741 RegisterID base = address.base;
743 DataLabelCompact label(this);
744 ASSERT(isCompactPtrAlignedAddressOffset(address.offset));
746 m_assembler.ldr(dest, base, address.offset, true, false);
750 void load16(BaseIndex address, RegisterID dest)
752 m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale);
755 void load16SignedExtendTo32(BaseIndex address, RegisterID dest)
757 load16SignedExtendTo32(setupArmAddress(address), dest);
760 void load16(ImplicitAddress address, RegisterID dest)
762 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.offset);
763 if (armImm.isValid())
764 m_assembler.ldrh(dest, address.base, armImm);
766 move(TrustedImm32(address.offset), dataTempRegister);
767 m_assembler.ldrh(dest, address.base, dataTempRegister);
771 void load16SignedExtendTo32(ImplicitAddress, RegisterID)
773 UNREACHABLE_FOR_PLATFORM();
776 DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
778 DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
779 store32(src, ArmAddress(address.base, dataTempRegister));
783 void store32(RegisterID src, ImplicitAddress address)
785 store32(src, setupArmAddress(address));
788 void store32(RegisterID src, BaseIndex address)
790 store32(src, setupArmAddress(address));
793 void store32(TrustedImm32 imm, ImplicitAddress address)
795 move(imm, dataTempRegister);
796 store32(dataTempRegister, setupArmAddress(address));
799 void store32(TrustedImm32 imm, BaseIndex address)
801 move(imm, dataTempRegister);
802 store32(dataTempRegister, setupArmAddress(address));
805 void store32(RegisterID src, const void* address)
807 move(TrustedImmPtr(address), addressTempRegister);
808 m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
811 void store32(TrustedImm32 imm, const void* address)
813 move(imm, dataTempRegister);
814 store32(dataTempRegister, address);
817 void store8(RegisterID src, Address address)
819 store8(src, setupArmAddress(address));
822 void store8(RegisterID src, BaseIndex address)
824 store8(src, setupArmAddress(address));
827 void store8(RegisterID src, void* address)
829 move(TrustedImmPtr(address), addressTempRegister);
830 store8(src, ArmAddress(addressTempRegister, 0));
833 void store8(TrustedImm32 imm, void* address)
835 TrustedImm32 imm8(static_cast<int8_t>(imm.m_value));
836 move(imm8, dataTempRegister);
837 store8(dataTempRegister, address);
840 void store8(TrustedImm32 imm, Address address)
842 TrustedImm32 imm8(static_cast<int8_t>(imm.m_value));
843 move(imm8, dataTempRegister);
844 store8(dataTempRegister, address);
847 void store16(RegisterID src, BaseIndex address)
849 store16(src, setupArmAddress(address));
852 // Possibly clobbers src, but not on this architecture.
853 void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2)
855 m_assembler.vmov(dest1, dest2, src);
858 void moveIntsToDouble(RegisterID src1, RegisterID src2, FPRegisterID dest, FPRegisterID scratch)
860 UNUSED_PARAM(scratch);
861 m_assembler.vmov(dest, src1, src2);
864 static bool shouldBlindForSpecificArch(uint32_t value)
866 ARMThumbImmediate immediate = ARMThumbImmediate::makeEncodedImm(value);
868 // Couldn't be encoded as an immediate, so assume it's untrusted.
869 if (!immediate.isValid())
872 // If we can encode the immediate, we have less than 16 attacker
874 if (immediate.isEncodedImm())
877 // Don't let any more than 12 bits of an instruction word
878 // be controlled by an attacker.
879 return !immediate.isUInt12();
882 // Floating-point operations:
884 static bool supportsFloatingPoint() { return true; }
885 static bool supportsFloatingPointTruncate() { return true; }
886 static bool supportsFloatingPointSqrt() { return true; }
887 static bool supportsFloatingPointAbs() { return true; }
888 static bool supportsFloatingPointRounding() { return false; }
890 void loadDouble(ImplicitAddress address, FPRegisterID dest)
892 RegisterID base = address.base;
893 int32_t offset = address.offset;
895 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
896 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
897 add32(TrustedImm32(offset), base, addressTempRegister);
898 base = addressTempRegister;
902 m_assembler.vldr(dest, base, offset);
905 void loadFloat(ImplicitAddress address, FPRegisterID dest)
907 RegisterID base = address.base;
908 int32_t offset = address.offset;
910 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
911 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
912 add32(TrustedImm32(offset), base, addressTempRegister);
913 base = addressTempRegister;
917 m_assembler.flds(ARMRegisters::asSingle(dest), base, offset);
920 void loadDouble(BaseIndex address, FPRegisterID dest)
922 move(address.index, addressTempRegister);
923 lshift32(TrustedImm32(address.scale), addressTempRegister);
924 add32(address.base, addressTempRegister);
925 loadDouble(Address(addressTempRegister, address.offset), dest);
928 void loadFloat(BaseIndex address, FPRegisterID dest)
930 move(address.index, addressTempRegister);
931 lshift32(TrustedImm32(address.scale), addressTempRegister);
932 add32(address.base, addressTempRegister);
933 loadFloat(Address(addressTempRegister, address.offset), dest);
936 void moveDouble(FPRegisterID src, FPRegisterID dest)
939 m_assembler.vmov(dest, src);
942 void moveZeroToDouble(FPRegisterID reg)
944 static double zeroConstant = 0.;
945 loadDouble(TrustedImmPtr(&zeroConstant), reg);
948 void loadDouble(TrustedImmPtr address, FPRegisterID dest)
950 move(address, addressTempRegister);
951 m_assembler.vldr(dest, addressTempRegister, 0);
954 void storeDouble(FPRegisterID src, ImplicitAddress address)
956 RegisterID base = address.base;
957 int32_t offset = address.offset;
959 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
960 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
961 add32(TrustedImm32(offset), base, addressTempRegister);
962 base = addressTempRegister;
966 m_assembler.vstr(src, base, offset);
969 void storeFloat(FPRegisterID src, ImplicitAddress address)
971 RegisterID base = address.base;
972 int32_t offset = address.offset;
974 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2.
975 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) {
976 add32(TrustedImm32(offset), base, addressTempRegister);
977 base = addressTempRegister;
981 m_assembler.fsts(ARMRegisters::asSingle(src), base, offset);
984 void storeDouble(FPRegisterID src, TrustedImmPtr address)
986 move(address, addressTempRegister);
987 storeDouble(src, addressTempRegister);
990 void storeDouble(FPRegisterID src, BaseIndex address)
992 move(address.index, addressTempRegister);
993 lshift32(TrustedImm32(address.scale), addressTempRegister);
994 add32(address.base, addressTempRegister);
995 storeDouble(src, Address(addressTempRegister, address.offset));
998 void storeFloat(FPRegisterID src, BaseIndex address)
1000 move(address.index, addressTempRegister);
1001 lshift32(TrustedImm32(address.scale), addressTempRegister);
1002 add32(address.base, addressTempRegister);
1003 storeFloat(src, Address(addressTempRegister, address.offset));
1006 void addDouble(FPRegisterID src, FPRegisterID dest)
1008 m_assembler.vadd(dest, dest, src);
1011 void addDouble(Address src, FPRegisterID dest)
1013 loadDouble(src, fpTempRegister);
1014 addDouble(fpTempRegister, dest);
1017 void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1019 m_assembler.vadd(dest, op1, op2);
1022 void addDouble(AbsoluteAddress address, FPRegisterID dest)
1024 loadDouble(TrustedImmPtr(address.m_ptr), fpTempRegister);
1025 m_assembler.vadd(dest, dest, fpTempRegister);
1028 void divDouble(FPRegisterID src, FPRegisterID dest)
1030 m_assembler.vdiv(dest, dest, src);
1033 void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1035 m_assembler.vdiv(dest, op1, op2);
1038 void subDouble(FPRegisterID src, FPRegisterID dest)
1040 m_assembler.vsub(dest, dest, src);
1043 void subDouble(Address src, FPRegisterID dest)
1045 loadDouble(src, fpTempRegister);
1046 subDouble(fpTempRegister, dest);
1049 void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1051 m_assembler.vsub(dest, op1, op2);
1054 void mulDouble(FPRegisterID src, FPRegisterID dest)
1056 m_assembler.vmul(dest, dest, src);
1059 void mulDouble(Address src, FPRegisterID dest)
1061 loadDouble(src, fpTempRegister);
1062 mulDouble(fpTempRegister, dest);
1065 void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
1067 m_assembler.vmul(dest, op1, op2);
1070 void sqrtDouble(FPRegisterID src, FPRegisterID dest)
1072 m_assembler.vsqrt(dest, src);
1075 void absDouble(FPRegisterID src, FPRegisterID dest)
1077 m_assembler.vabs(dest, src);
1080 void negateDouble(FPRegisterID src, FPRegisterID dest)
1082 m_assembler.vneg(dest, src);
1085 NO_RETURN_DUE_TO_CRASH void ceilDouble(FPRegisterID, FPRegisterID)
1087 ASSERT(!supportsFloatingPointRounding());
1091 NO_RETURN_DUE_TO_CRASH void floorDouble(FPRegisterID, FPRegisterID)
1093 ASSERT(!supportsFloatingPointRounding());
1097 NO_RETURN_DUE_TO_CRASH void roundTowardZeroDouble(FPRegisterID, FPRegisterID)
1099 ASSERT(!supportsFloatingPointRounding());
1103 void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
1105 m_assembler.vmov(fpTempRegister, src, src);
1106 m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
1109 void convertInt32ToDouble(Address address, FPRegisterID dest)
1111 // Fixme: load directly into the fpr!
1112 load32(address, dataTempRegister);
1113 m_assembler.vmov(fpTempRegister, dataTempRegister, dataTempRegister);
1114 m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
1117 void convertInt32ToDouble(AbsoluteAddress address, FPRegisterID dest)
1119 // Fixme: load directly into the fpr!
1120 load32(address.m_ptr, dataTempRegister);
1121 m_assembler.vmov(fpTempRegister, dataTempRegister, dataTempRegister);
1122 m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
1125 void convertFloatToDouble(FPRegisterID src, FPRegisterID dst)
1127 m_assembler.vcvtds(dst, ARMRegisters::asSingle(src));
1130 void convertDoubleToFloat(FPRegisterID src, FPRegisterID dst)
1132 m_assembler.vcvtsd(ARMRegisters::asSingle(dst), src);
1135 Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
1137 m_assembler.vcmp(left, right);
1140 if (cond == DoubleNotEqual) {
1141 // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump.
1142 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1143 Jump result = makeBranch(ARMv7Assembler::ConditionNE);
1144 unordered.link(this);
1147 if (cond == DoubleEqualOrUnordered) {
1148 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1149 Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
1150 unordered.link(this);
1151 // We get here if either unordered or equal.
1152 Jump result = jump();
1153 notEqual.link(this);
1156 return makeBranch(cond);
1159 enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
1160 Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
1162 // Convert into dest.
1163 m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1164 m_assembler.vmov(dest, fpTempRegisterAsSingle());
1166 // Calculate 2x dest. If the value potentially underflowed, it will have
1167 // clamped to 0x80000000, so 2x dest is zero in this case. In the case of
1168 // overflow the result will be equal to -2.
1169 Jump underflow = branchAdd32(Zero, dest, dest, dataTempRegister);
1170 Jump noOverflow = branch32(NotEqual, dataTempRegister, TrustedImm32(-2));
1172 // For BranchIfTruncateSuccessful, we branch if 'noOverflow' jumps.
1173 underflow.link(this);
1174 if (branchType == BranchIfTruncateSuccessful)
1177 // We'll reach the current point in the code on failure, so plant a
1178 // jump here & link the success case.
1179 Jump failure = jump();
1180 noOverflow.link(this);
1184 // Result is undefined if the value is outside of the integer range.
1185 void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
1187 m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1188 m_assembler.vmov(dest, fpTempRegisterAsSingle());
1191 void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
1193 m_assembler.vcvt_floatingPointToUnsigned(fpTempRegisterAsSingle(), src);
1194 m_assembler.vmov(dest, fpTempRegisterAsSingle());
1197 // Convert 'src' to an integer, and places the resulting 'dest'.
1198 // If the result is not representable as a 32 bit value, branch.
1199 // May also branch for some values that are representable in 32 bits
1200 // (specifically, in this case, 0).
1201 void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID, bool negZeroCheck = true)
1203 m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src);
1204 m_assembler.vmov(dest, fpTempRegisterAsSingle());
1206 // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
1207 m_assembler.vcvt_signedToFloatingPoint(fpTempRegister, fpTempRegisterAsSingle());
1208 failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, fpTempRegister));
1210 // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
1212 failureCases.append(branchTest32(Zero, dest));
1215 Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID)
1217 m_assembler.vcmpz(reg);
1219 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1220 Jump result = makeBranch(ARMv7Assembler::ConditionNE);
1221 unordered.link(this);
1225 Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID)
1227 m_assembler.vcmpz(reg);
1229 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
1230 Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
1231 unordered.link(this);
1232 // We get here if either unordered or equal.
1233 Jump result = jump();
1234 notEqual.link(this);
1238 // Stack manipulation operations:
1240 // The ABI is assumed to provide a stack abstraction to memory,
1241 // containing machine word sized units of data. Push and pop
1242 // operations add and remove a single register sized unit of data
1243 // to or from the stack. Peek and poke operations read or write
1244 // values on the stack, without moving the current stack position.
1246 void pop(RegisterID dest)
1248 m_assembler.pop(dest);
1251 void push(RegisterID src)
1253 m_assembler.push(src);
1256 void push(Address address)
1258 load32(address, dataTempRegister);
1259 push(dataTempRegister);
1262 void push(TrustedImm32 imm)
1264 move(imm, dataTempRegister);
1265 push(dataTempRegister);
1268 void popPair(RegisterID dest1, RegisterID dest2)
1270 m_assembler.pop(1 << dest1 | 1 << dest2);
1273 void pushPair(RegisterID src1, RegisterID src2)
1275 m_assembler.push(1 << src1 | 1 << src2);
1278 // Register move operations:
1280 // Move values in registers.
1282 void move(TrustedImm32 imm, RegisterID dest)
1284 uint32_t value = imm.m_value;
1286 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(value);
1288 if (armImm.isValid())
1289 m_assembler.mov(dest, armImm);
1290 else if ((armImm = ARMThumbImmediate::makeEncodedImm(~value)).isValid())
1291 m_assembler.mvn(dest, armImm);
1293 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(value));
1294 if (value & 0xffff0000)
1295 m_assembler.movt(dest, ARMThumbImmediate::makeUInt16(value >> 16));
1299 void move(RegisterID src, RegisterID dest)
1302 m_assembler.mov(dest, src);
1305 void move(TrustedImmPtr imm, RegisterID dest)
1307 move(TrustedImm32(imm), dest);
1310 void swap(RegisterID reg1, RegisterID reg2)
1312 move(reg1, dataTempRegister);
1314 move(dataTempRegister, reg2);
1317 void signExtend32ToPtr(RegisterID src, RegisterID dest)
1322 void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
1327 // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
1328 static RelationalCondition invert(RelationalCondition cond)
1330 return static_cast<RelationalCondition>(cond ^ 1);
1340 m_assembler.dmbSY();
1343 static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
1345 ARMv7Assembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
1348 static ptrdiff_t maxJumpReplacementSize()
1350 return ARMv7Assembler::maxJumpReplacementSize();
1353 // Forwards / external control flow operations:
1355 // This set of jump and conditional branch operations return a Jump
1356 // object which may linked at a later point, allow forwards jump,
1357 // or jumps that will require external linkage (after the code has been
1360 // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
1361 // respecitvely, for unsigned comparisons the names b, a, be, and ae are
1362 // used (representing the names 'below' and 'above').
1364 // Operands to the comparision are provided in the expected order, e.g.
1365 // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
1366 // treated as a signed 32bit value, is less than or equal to 5.
1368 // jz and jnz test whether the first operand is equal to zero, and take
1369 // an optional second operand of a mask under which to perform the test.
1372 // Should we be using TEQ for equal/not-equal?
1373 void compare32AndSetFlags(RegisterID left, TrustedImm32 right)
1375 int32_t imm = right.m_value;
1376 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
1377 if (armImm.isValid())
1378 m_assembler.cmp(left, armImm);
1379 else if ((armImm = ARMThumbImmediate::makeEncodedImm(-imm)).isValid())
1380 m_assembler.cmn(left, armImm);
1382 move(TrustedImm32(imm), dataTempRegister);
1383 m_assembler.cmp(left, dataTempRegister);
1388 void test32(RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1390 int32_t imm = mask.m_value;
1393 m_assembler.tst(reg, reg);
1395 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm);
1396 if (armImm.isValid()) {
1397 if (reg == ARMRegisters::sp) {
1398 move(reg, addressTempRegister);
1399 m_assembler.tst(addressTempRegister, armImm);
1401 m_assembler.tst(reg, armImm);
1403 move(mask, dataTempRegister);
1404 if (reg == ARMRegisters::sp) {
1405 move(reg, addressTempRegister);
1406 m_assembler.tst(addressTempRegister, dataTempRegister);
1408 m_assembler.tst(reg, dataTempRegister);
1413 Jump branch(ResultCondition cond)
1415 return Jump(makeBranch(cond));
1418 Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
1420 m_assembler.cmp(left, right);
1421 return Jump(makeBranch(cond));
1424 Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1426 compare32AndSetFlags(left, right);
1427 return Jump(makeBranch(cond));
1430 Jump branch32(RelationalCondition cond, RegisterID left, Address right)
1432 load32(right, dataTempRegister);
1433 return branch32(cond, left, dataTempRegister);
1436 Jump branch32(RelationalCondition cond, Address left, RegisterID right)
1438 load32(left, dataTempRegister);
1439 return branch32(cond, dataTempRegister, right);
1442 Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
1444 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1445 load32(left, addressTempRegister);
1446 return branch32(cond, addressTempRegister, right);
1449 Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1451 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1452 load32(left, addressTempRegister);
1453 return branch32(cond, addressTempRegister, right);
1456 Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1458 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1459 load32WithUnalignedHalfWords(left, addressTempRegister);
1460 return branch32(cond, addressTempRegister, right);
1463 Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
1465 load32(left.m_ptr, dataTempRegister);
1466 return branch32(cond, dataTempRegister, right);
1469 Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
1471 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1472 load32(left.m_ptr, addressTempRegister);
1473 return branch32(cond, addressTempRegister, right);
1476 Jump branchPtr(RelationalCondition cond, BaseIndex left, RegisterID right)
1478 load32(left, dataTempRegister);
1479 return branch32(cond, dataTempRegister, right);
1482 Jump branch8(RelationalCondition cond, RegisterID left, TrustedImm32 right)
1484 TrustedImm32 right8(static_cast<int8_t>(right.m_value));
1485 compare32AndSetFlags(left, right8);
1486 return Jump(makeBranch(cond));
1489 Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
1491 // use addressTempRegister incase the branch8 we call uses dataTempRegister. :-/
1492 TrustedImm32 right8(static_cast<int8_t>(right.m_value));
1493 load8(left, addressTempRegister);
1494 return branch8(cond, addressTempRegister, right8);
1497 Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
1499 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
1500 TrustedImm32 right8(static_cast<int8_t>(right.m_value));
1501 load8(left, addressTempRegister);
1502 return branch32(cond, addressTempRegister, right8);
1505 Jump branch8(RelationalCondition cond, AbsoluteAddress address, TrustedImm32 right)
1507 // Use addressTempRegister instead of dataTempRegister, since branch32 uses dataTempRegister.
1508 TrustedImm32 right8(static_cast<int8_t>(right.m_value));
1509 move(TrustedImmPtr(address.m_ptr), addressTempRegister);
1510 load8(Address(addressTempRegister), addressTempRegister);
1511 return branch32(cond, addressTempRegister, right8);
1514 Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
1516 ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == PositiveOrZero);
1517 m_assembler.tst(reg, mask);
1518 return Jump(makeBranch(cond));
1521 Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1523 ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == PositiveOrZero);
1525 return Jump(makeBranch(cond));
1528 Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1530 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1531 load32(address, addressTempRegister);
1532 return branchTest32(cond, addressTempRegister, mask);
1535 Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1537 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/
1538 load32(address, addressTempRegister);
1539 return branchTest32(cond, addressTempRegister, mask);
1542 Jump branchTest8(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
1544 // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1545 TrustedImm32 mask8(static_cast<int8_t>(mask.m_value));
1546 load8(address, addressTempRegister);
1547 return branchTest32(cond, addressTempRegister, mask8);
1550 Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
1552 // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1553 TrustedImm32 mask8(static_cast<int8_t>(mask.m_value));
1554 load8(address, addressTempRegister);
1555 return branchTest32(cond, addressTempRegister, mask8);
1558 Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
1560 // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
1561 TrustedImm32 mask8(static_cast<int8_t>(mask.m_value));
1562 move(TrustedImmPtr(address.m_ptr), addressTempRegister);
1563 load8(Address(addressTempRegister), addressTempRegister);
1564 return branchTest32(cond, addressTempRegister, mask8);
1567 void jump(RegisterID target)
1569 m_assembler.bx(target);
1572 // Address is a memory location containing the address to jump to
1573 void jump(Address address)
1575 load32(address, dataTempRegister);
1576 m_assembler.bx(dataTempRegister);
1579 void jump(AbsoluteAddress address)
1581 move(TrustedImmPtr(address.m_ptr), dataTempRegister);
1582 load32(Address(dataTempRegister), dataTempRegister);
1583 m_assembler.bx(dataTempRegister);
1587 // Arithmetic control flow operations:
1589 // This set of conditional branch operations branch based
1590 // on the result of an arithmetic operation. The operation
1591 // is performed as normal, storing the result.
1593 // * jz operations branch if the result is zero.
1594 // * jo operations branch if the (signed) arithmetic
1595 // operation caused an overflow to occur.
1597 Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1599 m_assembler.add_S(dest, op1, op2);
1600 return Jump(makeBranch(cond));
1603 Jump branchAdd32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
1605 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1606 if (armImm.isValid())
1607 m_assembler.add_S(dest, op1, armImm);
1609 move(imm, dataTempRegister);
1610 m_assembler.add_S(dest, op1, dataTempRegister);
1612 return Jump(makeBranch(cond));
1615 Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
1617 return branchAdd32(cond, dest, src, dest);
1620 Jump branchAdd32(ResultCondition cond, Address src, RegisterID dest)
1622 load32(src, dataTempRegister);
1623 return branchAdd32(cond, dest, dataTempRegister, dest);
1626 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1628 return branchAdd32(cond, dest, imm, dest);
1631 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
1633 // Move the high bits of the address into addressTempRegister,
1634 // and load the value into dataTempRegister.
1635 move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
1636 m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
1639 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1640 if (armImm.isValid())
1641 m_assembler.add_S(dataTempRegister, dataTempRegister, armImm);
1643 // If the operand does not fit into an immediate then load it temporarily
1644 // into addressTempRegister; since we're overwriting addressTempRegister
1645 // we'll need to reload it with the high bits of the address afterwards.
1646 move(imm, addressTempRegister);
1647 m_assembler.add_S(dataTempRegister, dataTempRegister, addressTempRegister);
1648 move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
1651 // Store the result.
1652 m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
1654 return Jump(makeBranch(cond));
1657 Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
1659 m_assembler.smull(dest, dataTempRegister, src1, src2);
1661 if (cond == Overflow) {
1662 m_assembler.asr(addressTempRegister, dest, 31);
1663 return branch32(NotEqual, addressTempRegister, dataTempRegister);
1666 return branchTest32(cond, dest);
1669 Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
1671 return branchMul32(cond, src, dest, dest);
1674 Jump branchMul32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
1676 move(imm, dataTempRegister);
1677 return branchMul32(cond, dataTempRegister, src, dest);
1680 Jump branchNeg32(ResultCondition cond, RegisterID srcDest)
1682 ARMThumbImmediate zero = ARMThumbImmediate::makeUInt12(0);
1683 m_assembler.sub_S(srcDest, zero, srcDest);
1684 return Jump(makeBranch(cond));
1687 Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
1689 m_assembler.orr_S(dest, dest, src);
1690 return Jump(makeBranch(cond));
1693 Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
1695 m_assembler.sub_S(dest, op1, op2);
1696 return Jump(makeBranch(cond));
1699 Jump branchSub32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest)
1701 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value);
1702 if (armImm.isValid())
1703 m_assembler.sub_S(dest, op1, armImm);
1705 move(imm, dataTempRegister);
1706 m_assembler.sub_S(dest, op1, dataTempRegister);
1708 return Jump(makeBranch(cond));
1711 Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
1713 return branchSub32(cond, dest, src, dest);
1716 Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
1718 return branchSub32(cond, dest, imm, dest);
1721 void relativeTableJump(RegisterID index, int scale)
1723 ASSERT(scale >= 0 && scale <= 31);
1725 // dataTempRegister will point after the jump if index register contains zero
1726 move(ARMRegisters::pc, dataTempRegister);
1727 m_assembler.add(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(9));
1729 ShiftTypeAndAmount shift(SRType_LSL, scale);
1730 m_assembler.add(dataTempRegister, dataTempRegister, index, shift);
1731 jump(dataTempRegister);
1734 // Miscellaneous operations:
1736 void breakpoint(uint8_t imm = 0)
1738 m_assembler.bkpt(imm);
1741 ALWAYS_INLINE Call nearCall()
1743 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1744 return Call(m_assembler.blx(dataTempRegister), Call::LinkableNear);
1747 ALWAYS_INLINE Call nearTailCall()
1749 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1750 return Call(m_assembler.bx(dataTempRegister), Call::LinkableNearTail);
1753 ALWAYS_INLINE Call call()
1755 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1756 return Call(m_assembler.blx(dataTempRegister), Call::Linkable);
1759 ALWAYS_INLINE Call call(RegisterID target)
1761 return Call(m_assembler.blx(target), Call::None);
1764 ALWAYS_INLINE Call call(Address address)
1766 load32(address, dataTempRegister);
1767 return Call(m_assembler.blx(dataTempRegister), Call::None);
1770 ALWAYS_INLINE void ret()
1772 m_assembler.bx(linkRegister);
1775 void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
1777 m_assembler.cmp(left, right);
1778 m_assembler.it(armV7Condition(cond), false);
1779 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1780 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1783 void compare32(RelationalCondition cond, Address left, RegisterID right, RegisterID dest)
1785 load32(left, dataTempRegister);
1786 compare32(cond, dataTempRegister, right, dest);
1789 void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest)
1791 TrustedImm32 right8(static_cast<int8_t>(right.m_value));
1792 load8(left, addressTempRegister);
1793 compare32(cond, addressTempRegister, right8, dest);
1796 void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
1798 compare32AndSetFlags(left, right);
1799 m_assembler.it(armV7Condition(cond), false);
1800 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1801 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1805 // The mask should be optional... paerhaps the argument order should be
1806 // dest-src, operations always have a dest? ... possibly not true, considering
1807 // asm ops like test, or pseudo ops like pop().
1808 void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1810 load32(address, dataTempRegister);
1811 test32(dataTempRegister, mask);
1812 m_assembler.it(armV7Condition(cond), false);
1813 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1814 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1817 void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
1819 TrustedImm32 mask8(static_cast<int8_t>(mask.m_value));
1820 load8(address, dataTempRegister);
1821 test32(dataTempRegister, mask8);
1822 m_assembler.it(armV7Condition(cond), false);
1823 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1));
1824 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0));
1827 ALWAYS_INLINE DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dst)
1830 moveFixedWidthEncoding(imm, dst);
1831 return DataLabel32(this);
1834 ALWAYS_INLINE DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst)
1837 moveFixedWidthEncoding(TrustedImm32(imm), dst);
1838 return DataLabelPtr(this);
1841 ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1843 dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1844 return branch32(cond, left, dataTempRegister);
1847 ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1849 load32(left, addressTempRegister);
1850 dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1851 return branch32(cond, addressTempRegister, dataTempRegister);
1854 ALWAYS_INLINE Jump branch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0))
1856 load32(left, addressTempRegister);
1857 dataLabel = moveWithPatch(initialRightValue, dataTempRegister);
1858 return branch32(cond, addressTempRegister, dataTempRegister);
1861 PatchableJump patchableBranchPtr(RelationalCondition cond, Address left, TrustedImmPtr right = TrustedImmPtr(0))
1863 m_makeJumpPatchable = true;
1864 Jump result = branch32(cond, left, TrustedImm32(right));
1865 m_makeJumpPatchable = false;
1866 return PatchableJump(result);
1869 PatchableJump patchableBranchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
1871 m_makeJumpPatchable = true;
1872 Jump result = branchTest32(cond, reg, mask);
1873 m_makeJumpPatchable = false;
1874 return PatchableJump(result);
1877 PatchableJump patchableBranch32(RelationalCondition cond, RegisterID reg, TrustedImm32 imm)
1879 m_makeJumpPatchable = true;
1880 Jump result = branch32(cond, reg, imm);
1881 m_makeJumpPatchable = false;
1882 return PatchableJump(result);
1885 PatchableJump patchableBranch32(RelationalCondition cond, Address left, TrustedImm32 imm)
1887 m_makeJumpPatchable = true;
1888 Jump result = branch32(cond, left, imm);
1889 m_makeJumpPatchable = false;
1890 return PatchableJump(result);
1893 PatchableJump patchableBranchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
1895 m_makeJumpPatchable = true;
1896 Jump result = branchPtrWithPatch(cond, left, dataLabel, initialRightValue);
1897 m_makeJumpPatchable = false;
1898 return PatchableJump(result);
1901 PatchableJump patchableBranch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0))
1903 m_makeJumpPatchable = true;
1904 Jump result = branch32WithPatch(cond, left, dataLabel, initialRightValue);
1905 m_makeJumpPatchable = false;
1906 return PatchableJump(result);
1909 PatchableJump patchableJump()
1912 m_makeJumpPatchable = true;
1913 Jump result = jump();
1914 m_makeJumpPatchable = false;
1915 return PatchableJump(result);
1918 ALWAYS_INLINE DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
1920 DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
1921 store32(dataTempRegister, address);
1924 ALWAYS_INLINE DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(TrustedImmPtr(0), address); }
1927 ALWAYS_INLINE Call tailRecursiveCall()
1929 // Like a normal call, but don't link.
1930 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
1931 return Call(m_assembler.bx(dataTempRegister), Call::Linkable);
1934 ALWAYS_INLINE Call makeTailRecursiveCall(Jump oldJump)
1937 return tailRecursiveCall();
1941 static FunctionPtr readCallTarget(CodeLocationCall call)
1943 return FunctionPtr(reinterpret_cast<void(*)()>(ARMv7Assembler::readCallTarget(call.dataLocation())));
1946 static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; }
1947 static bool canJumpReplacePatchableBranch32WithPatch() { return false; }
1949 static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label)
1951 const unsigned twoWordOpSize = 4;
1952 return label.labelAtOffset(-twoWordOpSize * 2);
1955 static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID rd, void* initialValue)
1958 ARMv7Assembler::revertJumpTo_movT3movtcmpT2(instructionStart.dataLocation(), rd, dataTempRegister, reinterpret_cast<uintptr_t>(initialValue));
1961 ARMv7Assembler::revertJumpTo_movT3(instructionStart.dataLocation(), dataTempRegister, ARMThumbImmediate::makeUInt16(reinterpret_cast<uintptr_t>(initialValue) & 0xffff));
1965 static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr)
1967 UNREACHABLE_FOR_PLATFORM();
1968 return CodeLocationLabel();
1971 static CodeLocationLabel startOfPatchableBranch32WithPatchOnAddress(CodeLocationDataLabel32)
1973 UNREACHABLE_FOR_PLATFORM();
1974 return CodeLocationLabel();
1977 static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel, Address, void*)
1979 UNREACHABLE_FOR_PLATFORM();
1982 static void revertJumpReplacementToPatchableBranch32WithPatch(CodeLocationLabel, Address, int32_t)
1984 UNREACHABLE_FOR_PLATFORM();
1987 static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
1989 ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1992 static void repatchCall(CodeLocationCall call, FunctionPtr destination)
1994 ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
1997 #if ENABLE(MASM_PROBE)
1998 void probe(ProbeFunction, void* arg1, void* arg2);
1999 #endif // ENABLE(MASM_PROBE)
2002 ALWAYS_INLINE Jump jump()
2004 m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint.
2005 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
2006 return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpNoConditionFixedSize : ARMv7Assembler::JumpNoCondition);
2009 ALWAYS_INLINE Jump makeBranch(ARMv7Assembler::Condition cond)
2011 m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint.
2012 m_assembler.it(cond, true, true);
2013 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
2014 return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpConditionFixedSize : ARMv7Assembler::JumpCondition, cond);
2016 ALWAYS_INLINE Jump makeBranch(RelationalCondition cond) { return makeBranch(armV7Condition(cond)); }
2017 ALWAYS_INLINE Jump makeBranch(ResultCondition cond) { return makeBranch(armV7Condition(cond)); }
2018 ALWAYS_INLINE Jump makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); }
2020 ArmAddress setupArmAddress(BaseIndex address)
2022 if (address.offset) {
2023 ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
2025 m_assembler.add(addressTempRegister, address.base, imm);
2027 move(TrustedImm32(address.offset), addressTempRegister);
2028 m_assembler.add(addressTempRegister, addressTempRegister, address.base);
2031 return ArmAddress(addressTempRegister, address.index, address.scale);
2033 return ArmAddress(address.base, address.index, address.scale);
2036 ArmAddress setupArmAddress(Address address)
2038 if ((address.offset >= -0xff) && (address.offset <= 0xfff))
2039 return ArmAddress(address.base, address.offset);
2041 move(TrustedImm32(address.offset), addressTempRegister);
2042 return ArmAddress(address.base, addressTempRegister);
2045 ArmAddress setupArmAddress(ImplicitAddress address)
2047 if ((address.offset >= -0xff) && (address.offset <= 0xfff))
2048 return ArmAddress(address.base, address.offset);
2050 move(TrustedImm32(address.offset), addressTempRegister);
2051 return ArmAddress(address.base, addressTempRegister);
2054 RegisterID makeBaseIndexBase(BaseIndex address)
2056 if (!address.offset)
2057 return address.base;
2059 ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset);
2061 m_assembler.add(addressTempRegister, address.base, imm);
2063 move(TrustedImm32(address.offset), addressTempRegister);
2064 m_assembler.add(addressTempRegister, addressTempRegister, address.base);
2067 return addressTempRegister;
2070 void moveFixedWidthEncoding(TrustedImm32 imm, RegisterID dst)
2072 uint32_t value = imm.m_value;
2073 m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff));
2074 m_assembler.movt(dst, ARMThumbImmediate::makeUInt16(value >> 16));
2077 ARMv7Assembler::Condition armV7Condition(RelationalCondition cond)
2079 return static_cast<ARMv7Assembler::Condition>(cond);
2082 ARMv7Assembler::Condition armV7Condition(ResultCondition cond)
2084 return static_cast<ARMv7Assembler::Condition>(cond);
2087 ARMv7Assembler::Condition armV7Condition(DoubleCondition cond)
2089 return static_cast<ARMv7Assembler::Condition>(cond);
2093 friend class LinkBuffer;
2095 static void linkCall(void* code, Call call, FunctionPtr function)
2097 if (call.isFlagSet(Call::Tail))
2098 ARMv7Assembler::linkJump(code, call.m_label, function.value());
2100 ARMv7Assembler::linkCall(code, call.m_label, function.value());
2103 #if ENABLE(MASM_PROBE)
2104 inline TrustedImm32 trustedImm32FromPtr(void* ptr)
2106 return TrustedImm32(TrustedImmPtr(ptr));
2109 inline TrustedImm32 trustedImm32FromPtr(ProbeFunction function)
2111 return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function)));
2114 inline TrustedImm32 trustedImm32FromPtr(void (*function)())
2116 return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function)));
2120 bool m_makeJumpPatchable;
2125 #endif // ENABLE(ASSEMBLER)
2127 #endif // MacroAssemblerARMv7_h