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

source code of qtdeclarative/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h