~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

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