| Differences between
and this patch
- JavaScriptCore/ChangeLog +182 lines
Lines 1-3 JavaScriptCore/ChangeLog_sec1
1
2010-02-25  Chao-ying Fu  <fu@mips.com>
2
3
        Reviewed by NOBODY (OOPS!).
4
5
        MIPS JIT Supports
6
        https://bugs.webkit.org/show_bug.cgi?id=30144
7
8
	The following changes are for MIPS JIT.
9
10
        * assembler/AbstractMacroAssembler.h:
11
        (JSC::AbstractMacroAssembler::Imm32::Imm32):
12
        * assembler/MIPSAssembler.h: Added.
13
        (JSC::MIPSRegisters::):
14
        (JSC::MIPSAssembler::MIPSAssembler):
15
        (JSC::MIPSAssembler::):
16
        (JSC::MIPSAssembler::JmpSrc::JmpSrc):
17
        (JSC::MIPSAssembler::JmpDst::JmpDst):
18
        (JSC::MIPSAssembler::JmpDst::isUsed):
19
        (JSC::MIPSAssembler::JmpDst::used):
20
        (JSC::MIPSAssembler::emitInst):
21
        (JSC::MIPSAssembler::nop):
22
        (JSC::MIPSAssembler::loadDelayNop):
23
        (JSC::MIPSAssembler::copDelayNop):
24
        (JSC::MIPSAssembler::move):
25
        (JSC::MIPSAssembler::li):
26
        (JSC::MIPSAssembler::lui):
27
        (JSC::MIPSAssembler::addiu):
28
        (JSC::MIPSAssembler::addu):
29
        (JSC::MIPSAssembler::subu):
30
        (JSC::MIPSAssembler::mult):
31
        (JSC::MIPSAssembler::mfhi):
32
        (JSC::MIPSAssembler::mflo):
33
        (JSC::MIPSAssembler::mul):
34
        (JSC::MIPSAssembler::andInsn):
35
        (JSC::MIPSAssembler::andi):
36
        (JSC::MIPSAssembler::nor):
37
        (JSC::MIPSAssembler::orInsn):
38
        (JSC::MIPSAssembler::ori):
39
        (JSC::MIPSAssembler::xorInsn):
40
        (JSC::MIPSAssembler::xori):
41
        (JSC::MIPSAssembler::slt):
42
        (JSC::MIPSAssembler::sltu):
43
        (JSC::MIPSAssembler::sltiu):
44
        (JSC::MIPSAssembler::sll):
45
        (JSC::MIPSAssembler::sllv):
46
        (JSC::MIPSAssembler::sra):
47
        (JSC::MIPSAssembler::srav):
48
        (JSC::MIPSAssembler::lw):
49
        (JSC::MIPSAssembler::lwl):
50
        (JSC::MIPSAssembler::lwr):
51
        (JSC::MIPSAssembler::lhu):
52
        (JSC::MIPSAssembler::sw):
53
        (JSC::MIPSAssembler::jr):
54
        (JSC::MIPSAssembler::jalr):
55
        (JSC::MIPSAssembler::jal):
56
        (JSC::MIPSAssembler::bkpt):
57
        (JSC::MIPSAssembler::bgez):
58
        (JSC::MIPSAssembler::bltz):
59
        (JSC::MIPSAssembler::beq):
60
        (JSC::MIPSAssembler::bne):
61
        (JSC::MIPSAssembler::bc1t):
62
        (JSC::MIPSAssembler::bc1f):
63
        (JSC::MIPSAssembler::newJmpSrc):
64
        (JSC::MIPSAssembler::appendJump):
65
        (JSC::MIPSAssembler::addd):
66
        (JSC::MIPSAssembler::subd):
67
        (JSC::MIPSAssembler::muld):
68
        (JSC::MIPSAssembler::lwc1):
69
        (JSC::MIPSAssembler::ldc1):
70
        (JSC::MIPSAssembler::swc1):
71
        (JSC::MIPSAssembler::sdc1):
72
        (JSC::MIPSAssembler::mtc1):
73
        (JSC::MIPSAssembler::mfc1):
74
        (JSC::MIPSAssembler::truncwd):
75
        (JSC::MIPSAssembler::cvtdw):
76
        (JSC::MIPSAssembler::ceqd):
77
        (JSC::MIPSAssembler::cngtd):
78
        (JSC::MIPSAssembler::cnged):
79
        (JSC::MIPSAssembler::cltd):
80
        (JSC::MIPSAssembler::cled):
81
        (JSC::MIPSAssembler::cueqd):
82
        (JSC::MIPSAssembler::coled):
83
        (JSC::MIPSAssembler::coltd):
84
        (JSC::MIPSAssembler::culed):
85
        (JSC::MIPSAssembler::cultd):
86
        (JSC::MIPSAssembler::label):
87
        (JSC::MIPSAssembler::align):
88
        (JSC::MIPSAssembler::getRelocatedAddress):
89
        (JSC::MIPSAssembler::getDifferenceBetweenLabels):
90
        (JSC::MIPSAssembler::size):
91
        (JSC::MIPSAssembler::executableCopy):
92
        (JSC::MIPSAssembler::getCallReturnOffset):
93
        (JSC::MIPSAssembler::linkJump):
94
        (JSC::MIPSAssembler::linkCall):
95
        (JSC::MIPSAssembler::linkPointer):
96
        (JSC::MIPSAssembler::relinkJump):
97
        (JSC::MIPSAssembler::relinkCall):
98
        (JSC::MIPSAssembler::repatchInt32):
99
        (JSC::MIPSAssembler::repatchPointer):
100
        (JSC::MIPSAssembler::repatchLoadPtrToLEA):
101
        (JSC::MIPSAssembler::relocateJumps):
102
        (JSC::MIPSAssembler::linkWithOffset):
103
        (JSC::MIPSAssembler::linkCallInternal):
104
        * assembler/MacroAssembler.h:
105
        * assembler/MacroAssemblerMIPS.h: Added.
106
        (JSC::MacroAssemblerMIPS::MacroAssemblerMIPS):
107
        (JSC::MacroAssemblerMIPS::):
108
        (JSC::MacroAssemblerMIPS::add32):
109
        (JSC::MacroAssemblerMIPS::and32):
110
        (JSC::MacroAssemblerMIPS::lshift32):
111
        (JSC::MacroAssemblerMIPS::mul32):
112
        (JSC::MacroAssemblerMIPS::not32):
113
        (JSC::MacroAssemblerMIPS::or32):
114
        (JSC::MacroAssemblerMIPS::rshift32):
115
        (JSC::MacroAssemblerMIPS::sub32):
116
        (JSC::MacroAssemblerMIPS::xor32):
117
        (JSC::MacroAssemblerMIPS::load32):
118
        (JSC::MacroAssemblerMIPS::load32WithUnalignedHalfWords):
119
        (JSC::MacroAssemblerMIPS::load32WithAddressOffsetPatch):
120
        (JSC::MacroAssemblerMIPS::loadPtrWithPatchToLEA):
121
        (JSC::MacroAssemblerMIPS::loadPtrWithAddressOffsetPatch):
122
        (JSC::MacroAssemblerMIPS::load16):
123
        (JSC::MacroAssemblerMIPS::store32WithAddressOffsetPatch):
124
        (JSC::MacroAssemblerMIPS::store32):
125
        (JSC::MacroAssemblerMIPS::supportsFloatingPoint):
126
        (JSC::MacroAssemblerMIPS::supportsFloatingPointTruncate):
127
        (JSC::MacroAssemblerMIPS::pop):
128
        (JSC::MacroAssemblerMIPS::push):
129
        (JSC::MacroAssemblerMIPS::move):
130
        (JSC::MacroAssemblerMIPS::swap):
131
        (JSC::MacroAssemblerMIPS::signExtend32ToPtr):
132
        (JSC::MacroAssemblerMIPS::zeroExtend32ToPtr):
133
        (JSC::MacroAssemblerMIPS::branch32):
134
        (JSC::MacroAssemblerMIPS::branch32WithUnalignedHalfWords):
135
        (JSC::MacroAssemblerMIPS::branch16):
136
        (JSC::MacroAssemblerMIPS::branchTest32):
137
        (JSC::MacroAssemblerMIPS::jump):
138
        (JSC::MacroAssemblerMIPS::branchAdd32):
139
        (JSC::MacroAssemblerMIPS::branchMul32):
140
        (JSC::MacroAssemblerMIPS::branchSub32):
141
        (JSC::MacroAssemblerMIPS::breakpoint):
142
        (JSC::MacroAssemblerMIPS::nearCall):
143
        (JSC::MacroAssemblerMIPS::call):
144
        (JSC::MacroAssemblerMIPS::ret):
145
        (JSC::MacroAssemblerMIPS::set32):
146
        (JSC::MacroAssemblerMIPS::setTest32):
147
        (JSC::MacroAssemblerMIPS::moveWithPatch):
148
        (JSC::MacroAssemblerMIPS::branchPtrWithPatch):
149
        (JSC::MacroAssemblerMIPS::storePtrWithPatch):
150
        (JSC::MacroAssemblerMIPS::tailRecursiveCall):
151
        (JSC::MacroAssemblerMIPS::makeTailRecursiveCall):
152
        (JSC::MacroAssemblerMIPS::loadDouble):
153
        (JSC::MacroAssemblerMIPS::storeDouble):
154
        (JSC::MacroAssemblerMIPS::addDouble):
155
        (JSC::MacroAssemblerMIPS::subDouble):
156
        (JSC::MacroAssemblerMIPS::mulDouble):
157
        (JSC::MacroAssemblerMIPS::convertInt32ToDouble):
158
        (JSC::MacroAssemblerMIPS::insertRelaxationWords):
159
        (JSC::MacroAssemblerMIPS::branchTrue):
160
        (JSC::MacroAssemblerMIPS::branchFalse):
161
        (JSC::MacroAssemblerMIPS::branchEqual):
162
        (JSC::MacroAssemblerMIPS::branchNotEqual):
163
        (JSC::MacroAssemblerMIPS::branchDouble):
164
        (JSC::MacroAssemblerMIPS::branchTruncateDoubleToInt32):
165
        (JSC::MacroAssemblerMIPS::linkCall):
166
        (JSC::MacroAssemblerMIPS::repatchCall):
167
        * jit/ExecutableAllocator.h:
168
        (JSC::ExecutableAllocator::cacheFlush):
169
        * jit/JIT.h:
170
        * jit/JITInlineMethods.h:
171
        (JSC::JIT::preserveReturnAddressAfterCall):
172
        (JSC::JIT::restoreReturnAddressBeforeReturn):
173
        * jit/JITOpcodes.cpp:
174
        * jit/JITStubs.cpp:
175
        (JSC::JITThunks::JITThunks):
176
        * jit/JITStubs.h:
177
        (JSC::JITStackFrame::returnAddressSlot):
178
        * wtf/Platform.h:
179
        * yarr/RegexJIT.cpp:
180
        (JSC::Yarr::RegexGenerator::generateEnter):
181
        (JSC::Yarr::RegexGenerator::generateReturn):
182
1
2010-02-25  Oliver Hunt  <oliver@apple.com>
183
2010-02-25  Oliver Hunt  <oliver@apple.com>
2
184
3
        Reviewed by Geoff Garen.
185
        Reviewed by Geoff Garen.
- JavaScriptCore/assembler/AbstractMacroAssembler.h -3 / +4 lines
Lines 173-179 public: JavaScriptCore/assembler/AbstractMacroAssembler.h_sec1
173
    struct Imm32 {
173
    struct Imm32 {
174
        explicit Imm32(int32_t value)
174
        explicit Imm32(int32_t value)
175
            : m_value(value)
175
            : m_value(value)
176
#if CPU(ARM)
176
#if CPU(ARM) || CPU(MIPS)
177
            , m_isPointer(false)
177
            , m_isPointer(false)
178
#endif
178
#endif
179
        {
179
        {
Lines 182-188 public: JavaScriptCore/assembler/AbstractMacroAssembler.h_sec2
182
#if !CPU(X86_64)
182
#if !CPU(X86_64)
183
        explicit Imm32(ImmPtr ptr)
183
        explicit Imm32(ImmPtr ptr)
184
            : m_value(ptr.asIntptr())
184
            : m_value(ptr.asIntptr())
185
#if CPU(ARM)
185
#if CPU(ARM) || CPU(MIPS)
186
            , m_isPointer(true)
186
            , m_isPointer(true)
187
#endif
187
#endif
188
        {
188
        {
Lines 190-202 public: JavaScriptCore/assembler/AbstractMacroAssembler.h_sec3
190
#endif
190
#endif
191
191
192
        int32_t m_value;
192
        int32_t m_value;
193
#if CPU(ARM)
193
#if CPU(ARM) || CPU(MIPS)
194
        // We rely on being able to regenerate code to recover exception handling
194
        // We rely on being able to regenerate code to recover exception handling
195
        // information.  Since ARMv7 supports 16-bit immediates there is a danger
195
        // information.  Since ARMv7 supports 16-bit immediates there is a danger
196
        // that if pointer values change the layout of the generated code will change.
196
        // that if pointer values change the layout of the generated code will change.
197
        // To avoid this problem, always generate pointers (and thus Imm32s constructed
197
        // To avoid this problem, always generate pointers (and thus Imm32s constructed
198
        // from ImmPtrs) with a code sequence that is able  to represent  any pointer
198
        // from ImmPtrs) with a code sequence that is able  to represent  any pointer
199
        // value - don't use a more compact form in these cases.
199
        // value - don't use a more compact form in these cases.
200
        // Same for MIPS.
200
        bool m_isPointer;
201
        bool m_isPointer;
201
#endif
202
#endif
202
    };
203
    };
- JavaScriptCore/assembler/MIPSAssembler.h +937 lines
Line 0 JavaScriptCore/assembler/MIPSAssembler.h_sec1
1
/*
2
 * Copyright (C) 2009 Apple Inc. All rights reserved.
3
 * Copyright (C) 2009 University of Szeged
4
 * All rights reserved.
5
 * Copyright (C) 2009 MIPS Technologies, Inc. All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY MIPS TECHNOLOGIES, INC. ``AS IS'' AND ANY
17
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL MIPS TECHNOLOGIES, INC. OR
20
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
28
29
#ifndef MIPSAssembler_h
30
#define MIPSAssembler_h
31
32
#include <wtf/Platform.h>
33
#include <wtf/SegmentedVector.h>
34
35
#if ENABLE(ASSEMBLER) && CPU(MIPS)
36
37
#include "AssemblerBuffer.h"
38
#include <wtf/Assertions.h>
39
40
namespace JSC {
41
42
typedef uint32_t MIPSWord;
43
44
namespace MIPSRegisters {
45
typedef enum {
46
    r0 = 0,
47
    r1,
48
    r2,
49
    r3,
50
    r4,
51
    r5,
52
    r6,
53
    r7,
54
    r8,
55
    r9,
56
    r10,
57
    r11,
58
    r12,
59
    r13,
60
    r14,
61
    r15,
62
    r16,
63
    r17,
64
    r18,
65
    r19,
66
    r20,
67
    r21,
68
    r22,
69
    r23,
70
    r24,
71
    r25,
72
    r26,
73
    r27,
74
    r28,
75
    r29,
76
    r30,
77
    r31,
78
    zero = r0,
79
    at = r1,
80
    v0 = r2,
81
    v1 = r3,
82
    a0 = r4,
83
    a1 = r5,
84
    a2 = r6,
85
    a3 = r7,
86
    t0 = r8,
87
    t1 = r9,
88
    t2 = r10,
89
    t3 = r11,
90
    t4 = r12,
91
    t5 = r13,
92
    t6 = r14,
93
    t7 = r15,
94
    s0 = r16,
95
    s1 = r17,
96
    s2 = r18,
97
    s3 = r19,
98
    s4 = r20,
99
    s5 = r21,
100
    s6 = r22,
101
    s7 = r23,
102
    t8 = r24,
103
    t9 = r25,
104
    k0 = r26,
105
    k1 = r27,
106
    gp = r28,
107
    sp = r29,
108
    fp = r30,
109
    ra = r31
110
} RegisterID;
111
112
typedef enum {
113
    f0,
114
    f1,
115
    f2,
116
    f3,
117
    f4,
118
    f5,
119
    f6,
120
    f7,
121
    f8,
122
    f9,
123
    f10,
124
    f11,
125
    f12,
126
    f13,
127
    f14,
128
    f15,
129
    f16,
130
    f17,
131
    f18,
132
    f19,
133
    f20,
134
    f21,
135
    f22,
136
    f23,
137
    f24,
138
    f25,
139
    f26,
140
    f27,
141
    f28,
142
    f29,
143
    f30,
144
    f31
145
} FPRegisterID;
146
147
} // namespace MIPSRegisters
148
149
class MIPSAssembler {
150
public:
151
    typedef MIPSRegisters::RegisterID RegisterID;
152
    typedef MIPSRegisters::FPRegisterID FPRegisterID;
153
    typedef SegmentedVector<int, 64> Jumps;
154
155
    MIPSAssembler()
156
    {
157
    }
158
159
    // MIPS instruction opcode field position
160
    enum {
161
        OP_SH_RD = 11,
162
        OP_SH_RT = 16,
163
        OP_SH_RS = 21,
164
        OP_SH_SHAMT = 6,
165
        OP_SH_CODE = 16,
166
        OP_SH_FD = 6,
167
        OP_SH_FS = 11,
168
        OP_SH_FT = 16
169
    };
170
171
    class JmpSrc {
172
        friend class MIPSAssembler;
173
    public:
174
        JmpSrc()
175
            : m_offset(-1)
176
        {
177
        }
178
179
    private:
180
        JmpSrc(int offset)
181
            : m_offset(offset)
182
        {
183
        }
184
185
        int m_offset;
186
    };
187
188
    class JmpDst {
189
        friend class MIPSAssembler;
190
    public:
191
        JmpDst()
192
            : m_offset(-1)
193
            , m_used(false)
194
        {
195
        }
196
197
        bool isUsed() const { return m_used; }
198
        void used() { m_used = true; }
199
    private:
200
        JmpDst(int offset)
201
            : m_offset(offset)
202
            , m_used(false)
203
        {
204
            ASSERT(m_offset == offset);
205
        }
206
207
        int m_offset : 31;
208
        int m_used : 1;
209
    };
210
211
    void emitInst(MIPSWord op)
212
    {
213
        void* oldBase = m_buffer.data();
214
215
        m_buffer.putInt(op);
216
217
        void* newBase = m_buffer.data();
218
        if (oldBase != newBase)
219
            relocateJumps(oldBase, newBase);
220
    }
221
222
    void nop()
223
    {
224
        emitInst(0x00000000);
225
    }
226
227
    /* Need to insert one load data delay nop for mips1.  */
228
    void loadDelayNop()
229
    {
230
#if WTF_MIPS_ISA(1)
231
        nop();
232
#endif
233
    }
234
235
    /* Need to insert one coprocessor access delay nop for mips1.  */
236
    void copDelayNop()
237
    {
238
#if WTF_MIPS_ISA(1)
239
        nop();
240
#endif
241
    }
242
243
    void move(RegisterID rd, RegisterID rs)
244
    {
245
        /* addu */
246
        emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS));
247
    }
248
249
    /* Set an immediate value to a register.  This may generate 1 or 2
250
       instructions.  */
251
    void li(RegisterID dest, int imm)
252
    {
253
        if (imm >= -32768 && imm <= 32767)
254
            addiu(dest, MIPSRegisters::zero, imm);
255
        else if (imm >= 0 && imm < 65536)
256
            ori(dest, MIPSRegisters::zero, imm);
257
        else {
258
            lui(dest, imm >> 16);
259
            if (imm & 0xffff)
260
                ori(dest, dest, imm);
261
        }
262
    }
263
264
    void lui(RegisterID rt, int imm)
265
    {
266
        emitInst(0x3c000000 | (rt << OP_SH_RT) | (imm & 0xffff));
267
    }
268
269
    void addiu(RegisterID rt, RegisterID rs, int imm)
270
    {
271
        emitInst(0x24000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
272
                 | (imm & 0xffff));
273
    }
274
275
    void addu(RegisterID rd, RegisterID rs, RegisterID rt)
276
    {
277
        emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
278
                 | (rt << OP_SH_RT));
279
    }
280
281
    void subu(RegisterID rd, RegisterID rs, RegisterID rt)
282
    {
283
        emitInst(0x00000023 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
284
                 | (rt << OP_SH_RT));
285
    }
286
287
    void mult(RegisterID rs, RegisterID rt)
288
    {
289
        emitInst(0x00000018 | (rs << OP_SH_RS) | (rt << OP_SH_RT));
290
    }
291
292
    void mfhi(RegisterID rd)
293
    {
294
        emitInst(0x00000010 | (rd << OP_SH_RD));
295
    }
296
297
    void mflo(RegisterID rd)
298
    {
299
        emitInst(0x00000012 | (rd << OP_SH_RD));
300
    }
301
302
    void mul(RegisterID rd, RegisterID rs, RegisterID rt)
303
    {
304
#if WTF_MIPS_ISA_AT_LEAST(32) 
305
        emitInst(0x70000002 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
306
                 | (rt << OP_SH_RT));
307
#else
308
        mult(rs, rt);
309
        mflo(rd);
310
#endif
311
    }
312
313
    void andInsn(RegisterID rd, RegisterID rs, RegisterID rt)
314
    {
315
        emitInst(0x00000024 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
316
                 | (rt << OP_SH_RT));
317
    }
318
319
    void andi(RegisterID rt, RegisterID rs, int imm)
320
    {
321
        emitInst(0x30000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
322
                 | (imm & 0xffff));
323
    }
324
325
    void nor(RegisterID rd, RegisterID rs, RegisterID rt)
326
    {
327
        emitInst(0x00000027 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
328
                 | (rt << OP_SH_RT));
329
    }
330
331
    void orInsn(RegisterID rd, RegisterID rs, RegisterID rt)
332
    {
333
        emitInst(0x00000025 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
334
                 | (rt << OP_SH_RT));
335
    }
336
337
    void ori(RegisterID rt, RegisterID rs, int imm)
338
    {
339
        emitInst(0x34000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
340
                 | (imm & 0xffff));
341
    }
342
343
    void xorInsn(RegisterID rd, RegisterID rs, RegisterID rt)
344
    {
345
        emitInst(0x00000026 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
346
                 | (rt << OP_SH_RT));
347
    }
348
349
    void xori(RegisterID rt, RegisterID rs, int imm)
350
    {
351
        emitInst(0x38000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
352
                 | (imm & 0xffff));
353
    }
354
355
    void slt(RegisterID rd, RegisterID rs, RegisterID rt)
356
    {
357
        emitInst(0x0000002a | (rd << OP_SH_RD) | (rs << OP_SH_RS)
358
                 | (rt << OP_SH_RT));
359
    }
360
361
    void sltu(RegisterID rd, RegisterID rs, RegisterID rt)
362
    {
363
        emitInst(0x0000002b | (rd << OP_SH_RD) | (rs << OP_SH_RS)
364
                 | (rt << OP_SH_RT));
365
    }
366
367
    void sltiu(RegisterID rt, RegisterID rs, int imm)
368
    {
369
        emitInst(0x2c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
370
                 | (imm & 0xffff));
371
    }
372
373
    void sll(RegisterID rd, RegisterID rt, int shamt)
374
    {
375
        emitInst(0x00000000 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
376
                 | ((shamt & 0x1f) << OP_SH_SHAMT));
377
    }
378
379
    void sllv(RegisterID rd, RegisterID rt, int rs)
380
    {
381
        emitInst(0x00000004 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
382
                 | (rs << OP_SH_RS));
383
    }
384
385
    void sra(RegisterID rd, RegisterID rt, int shamt)
386
    {
387
        emitInst(0x00000003 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
388
                 | ((shamt & 0x1f) << OP_SH_SHAMT));
389
    }
390
391
    void srav(RegisterID rd, RegisterID rt, RegisterID rs)
392
    {
393
        emitInst(0x00000007 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
394
                 | (rs << OP_SH_RS));
395
    }
396
397
    void lw(RegisterID rt, RegisterID rs, int offset)
398
    {
399
        emitInst(0x8c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
400
                 | (offset & 0xffff));
401
        loadDelayNop();
402
    }
403
404
    void lwl(RegisterID rt, RegisterID rs, int offset)
405
    {
406
        emitInst(0x88000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
407
                 | (offset & 0xffff));
408
        loadDelayNop();
409
    }
410
411
    void lwr(RegisterID rt, RegisterID rs, int offset)
412
    {
413
        emitInst(0x98000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
414
                 | (offset & 0xffff));
415
        loadDelayNop();
416
    }
417
418
    void lhu(RegisterID rt, RegisterID rs, int offset)
419
    {
420
        emitInst(0x94000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
421
                 | (offset & 0xffff));
422
        loadDelayNop();
423
    }
424
425
    void sw(RegisterID rt, RegisterID rs, int offset)
426
    {
427
        emitInst(0xac000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
428
                 | (offset & 0xffff));
429
    }
430
431
    void jr(RegisterID rs)
432
    {
433
        emitInst(0x00000008 | (rs << OP_SH_RS));
434
    }
435
436
    void jalr(RegisterID rs)
437
    {
438
        emitInst(0x0000f809 | (rs << OP_SH_RS));
439
    }
440
441
    void jal()
442
    {
443
        emitInst(0x0c000000);
444
    }
445
446
    void bkpt()
447
    {
448
        int value = 512; /* BRK_BUG */
449
        emitInst(0x0000000d | ((value & 0x3ff) << OP_SH_CODE));
450
    }
451
452
    void bgez(RegisterID rs, int imm)
453
    {
454
        emitInst(0x04010000 | (rs << OP_SH_RS) | (imm & 0xffff));
455
    }
456
457
    void bltz(RegisterID rs, int imm)
458
    {
459
        emitInst(0x04000000 | (rs << OP_SH_RS) | (imm & 0xffff));
460
    }
461
462
    void beq(RegisterID rs, RegisterID rt, int imm)
463
    {
464
        emitInst(0x10000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff));
465
    }
466
467
    void bne(RegisterID rs, RegisterID rt, int imm)
468
    {
469
        emitInst(0x14000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff));
470
    }
471
472
    void bc1t()
473
    {
474
        emitInst(0x45010000);
475
    }
476
477
    void bc1f()
478
    {
479
        emitInst(0x45000000);
480
    }
481
482
    JmpSrc newJmpSrc()
483
    {
484
        return JmpSrc(m_buffer.size());
485
    }
486
487
    void appendJump()
488
    {
489
        m_jumps.append(m_buffer.size());
490
    }
491
492
    void addd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
493
    {
494
        emitInst(0x46200000 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
495
                 | (ft << OP_SH_FT));
496
    }
497
498
    void subd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
499
    {
500
        emitInst(0x46200001 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
501
                 | (ft << OP_SH_FT));
502
    }
503
504
    void muld(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
505
    {
506
        emitInst(0x46200002 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
507
                 | (ft << OP_SH_FT));
508
    }
509
510
    void lwc1(FPRegisterID ft, RegisterID rs, int offset)
511
    {
512
        emitInst(0xc4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
513
                 | (offset & 0xffff));
514
        copDelayNop();
515
    }
516
517
    void ldc1(FPRegisterID ft, RegisterID rs, int offset)
518
    {
519
        emitInst(0xd4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
520
                 | (offset & 0xffff));
521
    }
522
523
    void swc1(FPRegisterID ft, RegisterID rs, int offset)
524
    {
525
        emitInst(0xe4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
526
                 | (offset & 0xffff));
527
    }
528
529
    void sdc1(FPRegisterID ft, RegisterID rs, int offset)
530
    {
531
        emitInst(0xf4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
532
                 | (offset & 0xffff));
533
    }
534
535
    void mtc1(RegisterID rt, FPRegisterID fs)
536
    {
537
        emitInst(0x44800000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
538
        copDelayNop();
539
    }
540
541
    void mfc1(RegisterID rt, FPRegisterID fs)
542
    {
543
        emitInst(0x44000000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
544
        copDelayNop();
545
    }
546
547
    void truncwd(FPRegisterID fd, FPRegisterID fs)
548
    {
549
        emitInst(0x4620000d | (fd << OP_SH_FD) | (fs << OP_SH_FS));
550
    }
551
552
    void cvtdw(FPRegisterID fd, FPRegisterID fs)
553
    {
554
        emitInst(0x46800021 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
555
    }
556
557
    void ceqd(FPRegisterID fs, FPRegisterID ft)
558
    {
559
        emitInst(0x46200032 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
560
        copDelayNop();
561
    }
562
563
    void cngtd(FPRegisterID fs, FPRegisterID ft)
564
    {
565
        emitInst(0x4620003f | (fs << OP_SH_FS) | (ft << OP_SH_FT));
566
        copDelayNop();
567
    }
568
569
    void cnged(FPRegisterID fs, FPRegisterID ft)
570
    {
571
        emitInst(0x4620003d | (fs << OP_SH_FS) | (ft << OP_SH_FT));
572
        copDelayNop();
573
    }
574
575
    void cltd(FPRegisterID fs, FPRegisterID ft)
576
    {
577
        emitInst(0x4620003c | (fs << OP_SH_FS) | (ft << OP_SH_FT));
578
        copDelayNop();
579
    }
580
581
    void cled(FPRegisterID fs, FPRegisterID ft)
582
    {
583
        emitInst(0x4620003e | (fs << OP_SH_FS) | (ft << OP_SH_FT));
584
        copDelayNop();
585
    }
586
587
    void cueqd(FPRegisterID fs, FPRegisterID ft)
588
    {
589
        emitInst(0x46200033 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
590
        copDelayNop();
591
    }
592
593
    void coled(FPRegisterID fs, FPRegisterID ft)
594
    {
595
        emitInst(0x46200036 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
596
        copDelayNop();
597
    }
598
599
    void coltd(FPRegisterID fs, FPRegisterID ft)
600
    {
601
        emitInst(0x46200034 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
602
        copDelayNop();
603
    }
604
605
    void culed(FPRegisterID fs, FPRegisterID ft)
606
    {
607
        emitInst(0x46200037 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
608
        copDelayNop();
609
    }
610
611
    void cultd(FPRegisterID fs, FPRegisterID ft)
612
    {
613
        emitInst(0x46200035 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
614
        copDelayNop();
615
    }
616
617
    // General helpers
618
619
    JmpDst label()
620
    {
621
        return JmpDst(m_buffer.size());
622
    }
623
624
    JmpDst align(int alignment)
625
    {
626
        while (!m_buffer.isAligned(alignment))
627
            bkpt();
628
629
        return label();
630
    }
631
632
    static void* getRelocatedAddress(void* code, JmpSrc jump)
633
    {
634
        ASSERT(jump.m_offset != -1);
635
        void* b = reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code)) + jump.m_offset);
636
        return b;
637
    }
638
639
    static void* getRelocatedAddress(void* code, JmpDst label)
640
    {
641
        void* b = reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code)) + label.m_offset);
642
        return b;
643
    }
644
645
    static int getDifferenceBetweenLabels(JmpDst from, JmpDst to)
646
    {
647
        return to.m_offset - from.m_offset;
648
    }
649
650
    static int getDifferenceBetweenLabels(JmpDst from, JmpSrc to)
651
    {
652
        return to.m_offset - from.m_offset;
653
    }
654
655
    static int getDifferenceBetweenLabels(JmpSrc from, JmpDst to)
656
    {
657
        return to.m_offset - from.m_offset;
658
    }
659
660
    // Assembler admin methods:
661
662
    size_t size() const
663
    {
664
        return m_buffer.size();
665
    }
666
667
    void* executableCopy(ExecutablePool* allocator)
668
    {
669
        void *result = m_buffer.executableCopy(allocator);
670
        if (!result)
671
            return 0;
672
673
        relocateJumps(m_buffer.data(), result);
674
        return result;
675
    }
676
677
    static unsigned getCallReturnOffset(JmpSrc call)
678
    {
679
        // The return address is after a call and a delay slot instruction
680
        return call.m_offset;
681
    }
682
683
    // Linking & patching:
684
    //
685
    // 'link' and 'patch' methods are for use on unprotected code - such as the code
686
    // within the AssemblerBuffer, and code being patched by the patch buffer.  Once
687
    // code has been finalized it is (platform support permitting) within a non-
688
    // writable region of memory; to modify the code in an execute-only execuable
689
    // pool the 'repatch' and 'relink' methods should be used.
690
691
    void linkJump(JmpSrc from, JmpDst to)
692
    {
693
        ASSERT(to.m_offset != -1);
694
        ASSERT(from.m_offset != -1);
695
        MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + from.m_offset);
696
        MIPSWord* toPos = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + to.m_offset);
697
698
        ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
699
        insn = insn - 6;
700
        linkWithOffset(insn, toPos);
701
    }
702
703
    static void linkJump(void* code, JmpSrc from, void* to)
704
    {
705
        ASSERT(from.m_offset != -1);
706
        MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
707
708
        ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
709
        insn = insn - 6;
710
        linkWithOffset(insn, to);
711
    }
712
713
    static void linkCall(void* code, JmpSrc from, void* to)
714
    {
715
        MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
716
        linkCallInternal(insn, to);
717
    }
718
719
    static void linkPointer(void* code, JmpDst from, void* to)
720
    {
721
        MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
722
        ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
723
        *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
724
        insn++;
725
        ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
726
        *insn = (*insn & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
727
    }
728
729
    static void relinkJump(void* from, void* to)
730
    {
731
        MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
732
733
        ASSERT(!(*(insn - 1)) && !(*(insn - 5)));
734
        insn = insn - 6;
735
        int flushSize = linkWithOffset(insn, to);
736
737
        ExecutableAllocator::cacheFlush(insn, flushSize);
738
    }
739
740
    static void relinkCall(void* from, void* to)
741
    {
742
        void* start;
743
        int size = linkCallInternal(from, to);
744
        if (size == sizeof(MIPSWord))
745
            start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 2 * sizeof(MIPSWord));
746
        else
747
            start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 4 * sizeof(MIPSWord));
748
749
        ExecutableAllocator::cacheFlush(start, size);
750
    }
751
752
    static void repatchInt32(void* from, int32_t to)
753
    {
754
        MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
755
        ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
756
        *insn = (*insn & 0xffff0000) | ((to >> 16) & 0xffff);
757
        insn++;
758
        ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
759
        *insn = (*insn & 0xffff0000) | (to & 0xffff);
760
        insn--;
761
        ExecutableAllocator::cacheFlush(insn, 2 * sizeof(MIPSWord));
762
    }
763
764
    static void repatchPointer(void* from, void* to)
765
    {
766
        repatchInt32(from, reinterpret_cast<int32_t>(to));
767
    }
768
769
    static void repatchLoadPtrToLEA(void* from)
770
    {
771
        MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
772
        insn = insn + 3;
773
        ASSERT((*insn & 0xfc000000) == 0x8c000000); // lw
774
        /* lw -> addiu */
775
        *insn = 0x24000000 | (*insn & 0x03ffffff);
776
777
        ExecutableAllocator::cacheFlush(insn, sizeof(MIPSWord));
778
    }
779
780
private:
781
782
    /* Update each jump in the buffer of newBase.  */
783
    void relocateJumps(void* oldBase, void* newBase)
784
    {
785
        // Check each jump
786
        for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
787
            int pos = *iter;
788
            MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(newBase) + pos);
789
            insn = insn + 2;
790
            // Need to make sure we have 5 valid instructions after pos
791
            if ((unsigned int)pos >= m_buffer.size() - 5 * sizeof(MIPSWord))
792
                continue;
793
794
            if ((*insn & 0xfc000000) == 0x08000000) { // j
795
                int offset = *insn & 0x03ffffff;
796
                int oldInsnAddress = (int)insn - (int)newBase + (int)oldBase;
797
                int topFourBits = (oldInsnAddress + 4) >> 28;
798
                int oldTargetAddress = (topFourBits << 28) | (offset << 2);
799
                int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
800
                int newInsnAddress = (int)insn;
801
                if (((newInsnAddress + 4) >> 28) == (newTargetAddress >> 28))
802
                    *insn = 0x08000000 | ((newTargetAddress >> 2) & 0x3ffffff);
803
                else {
804
                    /* lui */
805
                    *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
806
                    /* ori */
807
                    *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
808
                    /* jr */
809
                    *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
810
                }
811
            } else if ((*insn & 0xffe00000) == 0x3c000000) { // lui
812
                int high = (*insn & 0xffff) << 16;
813
                int low = *(insn + 1) & 0xffff;
814
                int oldTargetAddress = high | low;
815
                int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
816
                /* lui */
817
                *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
818
                /* ori */
819
                *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
820
            }
821
        }
822
    }
823
824
    static int linkWithOffset(MIPSWord* insn, void* to)
825
    {
826
        ASSERT((*insn & 0xfc000000) == 0x10000000 // beq
827
               || (*insn & 0xfc000000) == 0x14000000 // bne
828
               || (*insn & 0xffff0000) == 0x45010000 // bc1t
829
               || (*insn & 0xffff0000) == 0x45000000); // bc1f
830
        intptr_t diff = (reinterpret_cast<intptr_t>(to)
831
                         - reinterpret_cast<intptr_t>(insn) - 4) >> 2;
832
833
        if (diff < -32768 || diff > 32767 || *(insn + 2) != 0x10000003) {
834
            /*
835
                Convert the sequence:
836
                  beq $2, $3, target
837
                  nop
838
                  b 1f
839
                  nop
840
                  nop
841
                  nop
842
                1:
843
844
                to the new sequence if possible:
845
                  bne $2, $3, 1f
846
                  nop
847
                  j    target
848
                  nop
849
                  nop
850
                  nop
851
                1:
852
853
                OR to the new sequence:
854
                  bne $2, $3, 1f
855
                  nop
856
                  lui $25, target >> 16
857
                  ori $25, $25, target & 0xffff
858
                  jr $25
859
                  nop
860
                1:
861
862
                Note: beq/bne/bc1t are converted to bne/beq/bc1f.
863
            */
864
865
            if (*(insn + 2) == 0x10000003) {
866
                if ((*insn & 0xfc000000) == 0x10000000) // beq
867
                    *insn = (*insn & 0x03ff0000) | 0x14000005; // bne
868
                else if ((*insn & 0xfc000000) == 0x14000000) // bne
869
                    *insn = (*insn & 0x03ff0000) | 0x10000005; // beq
870
                else if ((*insn & 0xffff0000) == 0x45010000) // bc1t
871
                    *insn = 0x45000005; // bc1f
872
                else
873
                    ASSERT(0);
874
            }
875
876
            insn = insn + 2;
877
            if ((reinterpret_cast<intptr_t>(insn) + 4) >> 28
878
                == reinterpret_cast<intptr_t>(to) >> 28) {
879
                *insn = 0x08000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
880
                *(insn + 1) = 0;
881
                return 4 * sizeof(MIPSWord);
882
            }
883
884
            intptr_t newTargetAddress = reinterpret_cast<intptr_t>(to);
885
            /* lui */
886
            *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
887
            /* ori */
888
            *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
889
            /* jr */
890
            *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
891
            return 5 * sizeof(MIPSWord);
892
        }
893
894
        *insn = (*insn & 0xffff0000) | (diff & 0xffff);
895
        return sizeof(MIPSWord);
896
    }
897
898
    static int linkCallInternal(void* from, void* to)
899
    {
900
        MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
901
        insn = insn - 4;
902
903
        if ((*(insn + 2) & 0xfc000000) == 0x0c000000) { // jal
904
            if ((reinterpret_cast<intptr_t>(from) - 4) >> 28
905
                == reinterpret_cast<intptr_t>(to) >> 28) {
906
                *(insn + 2) = 0x0c000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
907
                return sizeof(MIPSWord);
908
            }
909
910
            /* lui $25, (to >> 16) & 0xffff */
911
            *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
912
            /* ori $25, $25, to & 0xffff */
913
            *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (reinterpret_cast<intptr_t>(to) & 0xffff);
914
            /* jalr $25 */
915
            *(insn + 2) = 0x0000f809 | (MIPSRegisters::t9 << OP_SH_RS);
916
            return 3 * sizeof(MIPSWord);
917
        }
918
919
        ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
920
        ASSERT((*(insn + 1) & 0xfc000000) == 0x34000000); // ori
921
922
        /* lui */
923
        *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
924
        /* ori */
925
        *(insn + 1) = (*(insn + 1) & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
926
        return 2 * sizeof(MIPSWord);
927
    }
928
929
    AssemblerBuffer m_buffer;
930
    Jumps m_jumps;
931
};
932
933
} // namespace JSC
934
935
#endif // ENABLE(ASSEMBLER) && CPU(MIPS)
936
937
#endif // MIPSAssembler_h
- JavaScriptCore/assembler/MacroAssembler.h +4 lines
Lines 38-43 namespace JSC { typedef MacroAssemblerAR JavaScriptCore/assembler/MacroAssembler.h_sec1
38
#include "MacroAssemblerARM.h"
38
#include "MacroAssemblerARM.h"
39
namespace JSC { typedef MacroAssemblerARM MacroAssemblerBase; };
39
namespace JSC { typedef MacroAssemblerARM MacroAssemblerBase; };
40
40
41
#elif CPU(MIPS)
42
#include "MacroAssemblerMIPS.h"
43
namespace JSC { typedef MacroAssemblerMIPS MacroAssemblerBase; };
44
41
#elif CPU(X86)
45
#elif CPU(X86)
42
#include "MacroAssemblerX86.h"
46
#include "MacroAssemblerX86.h"
43
namespace JSC { typedef MacroAssemblerX86 MacroAssemblerBase; };
47
namespace JSC { typedef MacroAssemblerX86 MacroAssemblerBase; };
- JavaScriptCore/assembler/MacroAssemblerMIPS.h +1660 lines
Line 0 JavaScriptCore/assembler/MacroAssemblerMIPS.h_sec1
1
/*
2
 * Copyright (C) 2008 Apple Inc. All rights reserved.
3
 * Copyright (C) 2009 MIPS Technologies, Inc. All rights reserved.
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 MIPS TECHNOLOGIES, 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 MIPS TECHNOLOGIES, 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 MacroAssemblerMIPS_h
28
#define MacroAssemblerMIPS_h
29
30
#include <wtf/Platform.h>
31
32
#if ENABLE(ASSEMBLER) && CPU(MIPS)
33
34
#include "MIPSAssembler.h"
35
#include "AbstractMacroAssembler.h"
36
37
namespace JSC {
38
39
class MacroAssemblerMIPS : public AbstractMacroAssembler<MIPSAssembler> {
40
public:
41
42
    MacroAssemblerMIPS()
43
        : m_fixedWidth(false)
44
    {
45
    }
46
47
    static const Scale ScalePtr = TimesFour;
48
49
    // For storing immediate number
50
    static const RegisterID immTempRegister = MIPSRegisters::t0;
51
    // For storing data loaded from the memory
52
    static const RegisterID dataTempRegister = MIPSRegisters::t1;
53
    // For storing address base
54
    static const RegisterID addrTempRegister = MIPSRegisters::t2;
55
    // For storing compare result
56
    static const RegisterID cmpTempRegister = MIPSRegisters::t3;
57
58
    // FP temp register
59
    static const FPRegisterID fpTempRegister = MIPSRegisters::f16;
60
61
    enum Condition {
62
        Equal,
63
        NotEqual,
64
        Above,
65
        AboveOrEqual,
66
        Below,
67
        BelowOrEqual,
68
        GreaterThan,
69
        GreaterThanOrEqual,
70
        LessThan,
71
        LessThanOrEqual,
72
        Overflow,
73
        Signed,
74
        Zero,
75
        NonZero
76
    };
77
78
    enum DoubleCondition {
79
        DoubleEqual,
80
        DoubleNotEqual,
81
        DoubleGreaterThan,
82
        DoubleGreaterThanOrEqual,
83
        DoubleLessThan,
84
        DoubleLessThanOrEqual,
85
        DoubleEqualOrUnordered,
86
        DoubleNotEqualOrUnordered,
87
        DoubleGreaterThanOrUnordered,
88
        DoubleGreaterThanOrEqualOrUnordered,
89
        DoubleLessThanOrUnordered,
90
        DoubleLessThanOrEqualOrUnordered
91
    };
92
93
    static const RegisterID stackPointerRegister = MIPSRegisters::sp;
94
    static const RegisterID returnAddressRegister = MIPSRegisters::ra;
95
96
    // Integer arithmetic operations:
97
    //
98
    // Operations are typically two operand - operation(source, srcDst)
99
    // For many operations the source may be an Imm32, the srcDst operand
100
    // may often be a memory location (explictly described using an Address
101
    // object).
102
103
    void add32(RegisterID src, RegisterID dest)
104
    {
105
        m_assembler.addu(dest, dest, src);
106
    }
107
108
    void add32(Imm32 imm, RegisterID dest)
109
    {
110
        add32(imm, dest, dest);
111
    }
112
113
    void add32(Imm32 imm, RegisterID src, RegisterID dest)
114
    {
115
        if (!imm.m_isPointer && imm.m_value >= -32768 && imm.m_value <= 32767
116
            && !m_fixedWidth) {
117
            /*
118
              addiu     dest, src, imm
119
            */
120
            m_assembler.addiu(dest, src, imm.m_value);
121
        } else {
122
            /*
123
              li        immTemp, imm
124
              addu      dest, src, immTemp
125
            */
126
            move(imm, immTempRegister);
127
            m_assembler.addu(dest, src, immTempRegister);
128
        }
129
    }
130
131
    void add32(Imm32 imm, Address address)
132
    {
133
        if (address.offset >= -32768 && address.offset <= 32767
134
            && !m_fixedWidth) {
135
            /*
136
              lw        dataTemp, offset(base)
137
              li        immTemp, imm
138
              addu      dataTemp, dataTemp, immTemp
139
              sw        dataTemp, offset(base)
140
            */
141
            m_assembler.lw(dataTempRegister, address.base, address.offset);
142
            if (!imm.m_isPointer
143
                && imm.m_value >= -32768 && imm.m_value <= 32767
144
                && !m_fixedWidth)
145
                m_assembler.addiu(dataTempRegister, dataTempRegister,
146
                                  imm.m_value);
147
            else {
148
                move(imm, immTempRegister);
149
                m_assembler.addu(dataTempRegister, dataTempRegister,
150
                                 immTempRegister);
151
            }
152
            m_assembler.sw(dataTempRegister, address.base, address.offset);
153
        } else {
154
            /*
155
              lui       addrTemp, (offset + 0x8000) >> 16
156
              addu      addrTemp, addrTemp, base
157
              lw        dataTemp, (offset & 0xffff)(addrTemp)
158
              li        immtemp, imm
159
              addu      dataTemp, dataTemp, immTemp
160
              sw        dataTemp, (offset & 0xffff)(addrTemp)
161
            */
162
            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
163
            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
164
            m_assembler.lw(dataTempRegister, addrTempRegister, address.offset);
165
166
            if (imm.m_value >= -32768 && imm.m_value <= 32767 && !m_fixedWidth)
167
                m_assembler.addiu(dataTempRegister, dataTempRegister,
168
                                  imm.m_value);
169
            else {
170
                move(imm, immTempRegister);
171
                m_assembler.addu(dataTempRegister, dataTempRegister,
172
                                 immTempRegister);
173
            }
174
            m_assembler.sw(dataTempRegister, addrTempRegister, address.offset);
175
        }
176
    }
177
178
    void add32(Address src, RegisterID dest)
179
    {
180
        load32(src, dataTempRegister);
181
        add32(dataTempRegister, dest);
182
    }
183
184
    void add32(RegisterID src, Address dest)
185
    {
186
        if (dest.offset >= -32768 && dest.offset <= 32767 && !m_fixedWidth) {
187
            /*
188
              lw        dataTemp, offset(base)
189
              addu      dataTemp, dataTemp, src
190
              sw        dataTemp, offset(base)
191
            */
192
            m_assembler.lw(dataTempRegister, dest.base, dest.offset);
193
            m_assembler.addu(dataTempRegister, dataTempRegister, src);
194
            m_assembler.sw(dataTempRegister, dest.base, dest.offset);
195
        } else {
196
            /*
197
              lui       addrTemp, (offset + 0x8000) >> 16
198
              addu      addrTemp, addrTemp, base
199
              lw        dataTemp, (offset & 0xffff)(addrTemp)
200
              addu      dataTemp, dataTemp, src
201
              sw        dataTemp, (offset & 0xffff)(addrTemp)
202
            */
203
            m_assembler.lui(addrTempRegister, (dest.offset + 0x8000) >> 16);
204
            m_assembler.addu(addrTempRegister, addrTempRegister, dest.base);
205
            m_assembler.lw(dataTempRegister, addrTempRegister, dest.offset);
206
            m_assembler.addu(dataTempRegister, dataTempRegister, src);
207
            m_assembler.sw(dataTempRegister, addrTempRegister, dest.offset);
208
        }
209
    }
210
211
    void add32(Imm32 imm, AbsoluteAddress address)
212
    {
213
        /*
214
           li   addrTemp, address
215
           li   immTemp, imm
216
           lw   dataTemp, 0(addrTemp)
217
           addu dataTemp, dataTemp, immTemp
218
           sw   dataTemp, 0(addrTemp)
219
        */
220
        move(ImmPtr(address.m_ptr), addrTempRegister);
221
        m_assembler.lw(dataTempRegister, addrTempRegister, 0);
222
        if (!imm.m_isPointer && imm.m_value >= -32768 && imm.m_value <= 32767
223
            && !m_fixedWidth)
224
            m_assembler.addiu(dataTempRegister, dataTempRegister, imm.m_value);
225
        else {
226
            move(imm, immTempRegister);
227
            m_assembler.addu(dataTempRegister, dataTempRegister, immTempRegister);
228
        }
229
        m_assembler.sw(dataTempRegister, addrTempRegister, 0);
230
    }
231
232
    void and32(RegisterID src, RegisterID dest)
233
    {
234
        m_assembler.andInsn(dest, dest, src);
235
    }
236
237
    void and32(Imm32 imm, RegisterID dest)
238
    {
239
        if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
240
            move(MIPSRegisters::zero, dest);
241
        else if (!imm.m_isPointer && imm.m_value > 0 && imm.m_value < 65535
242
                 && !m_fixedWidth)
243
            m_assembler.andi(dest, dest, imm.m_value);
244
        else {
245
            /*
246
              li        immTemp, imm
247
              and       dest, dest, immTemp
248
            */
249
            move(imm, immTempRegister);
250
            m_assembler.andInsn(dest, dest, immTempRegister);
251
        }
252
    }
253
254
    void lshift32(Imm32 imm, RegisterID dest)
255
    {
256
        m_assembler.sll(dest, dest, imm.m_value);
257
    }
258
259
    void lshift32(RegisterID shiftAmount, RegisterID dest)
260
    {
261
        m_assembler.sllv(dest, dest, shiftAmount);
262
    }
263
264
    void mul32(RegisterID src, RegisterID dest)
265
    {
266
        m_assembler.mul(dest, dest, src);
267
    }
268
269
    void mul32(Imm32 imm, RegisterID src, RegisterID dest)
270
    {
271
        if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
272
            move(MIPSRegisters::zero, dest);
273
        else if (!imm.m_isPointer && imm.m_value == 1 && !m_fixedWidth)
274
            move(src, dest);
275
        else {
276
            /*
277
                li      dataTemp, imm
278
                mul     dest, src, dataTemp
279
            */
280
            move(imm, dataTempRegister);
281
            m_assembler.mul(dest, src, dataTempRegister);
282
        }
283
    }
284
285
    void not32(RegisterID srcDest)
286
    {
287
        m_assembler.nor(srcDest, srcDest, MIPSRegisters::zero);
288
    }
289
290
    void or32(RegisterID src, RegisterID dest)
291
    {
292
        m_assembler.orInsn(dest, dest, src);
293
    }
294
295
    void or32(Imm32 imm, RegisterID dest)
296
    {
297
        if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
298
            return;
299
300
        if (!imm.m_isPointer && imm.m_value > 0 && imm.m_value < 65535
301
            && !m_fixedWidth) {
302
            m_assembler.ori(dest, dest, imm.m_value);
303
            return;
304
        }
305
306
        /*
307
            li      dataTemp, imm
308
            or      dest, dest, dataTemp
309
        */
310
        move(imm, dataTempRegister);
311
        m_assembler.orInsn(dest, dest, dataTempRegister);
312
    }
313
314
    void rshift32(RegisterID shiftAmount, RegisterID dest)
315
    {
316
        m_assembler.srav(dest, dest, shiftAmount);
317
    }
318
319
    void rshift32(Imm32 imm, RegisterID dest)
320
    {
321
        m_assembler.sra(dest, dest, imm.m_value);
322
    }
323
324
    void sub32(RegisterID src, RegisterID dest)
325
    {
326
        m_assembler.subu(dest, dest, src);
327
    }
328
329
    void sub32(Imm32 imm, RegisterID dest)
330
    {
331
        if (!imm.m_isPointer && imm.m_value >= -32767 && imm.m_value <= 32768
332
            && !m_fixedWidth) {
333
            /*
334
              addiu     dest, src, imm
335
            */
336
            m_assembler.addiu(dest, dest, -imm.m_value);
337
        } else {
338
            /*
339
              li        immTemp, imm
340
              subu      dest, src, immTemp
341
            */
342
            move(imm, immTempRegister);
343
            m_assembler.subu(dest, dest, immTempRegister);
344
        }
345
    }
346
347
    void sub32(Imm32 imm, Address address)
348
    {
349
        if (address.offset >= -32768 && address.offset <= 32767
350
            && !m_fixedWidth) {
351
            /*
352
              lw        dataTemp, offset(base)
353
              li        immTemp, imm
354
              subu      dataTemp, dataTemp, immTemp
355
              sw        dataTemp, offset(base)
356
            */
357
            m_assembler.lw(dataTempRegister, address.base, address.offset);
358
            if (!imm.m_isPointer
359
                && imm.m_value >= -32767 && imm.m_value <= 32768
360
                && !m_fixedWidth)
361
                m_assembler.addiu(dataTempRegister, dataTempRegister,
362
                                  -imm.m_value);
363
            else {
364
                move(imm, immTempRegister);
365
                m_assembler.subu(dataTempRegister, dataTempRegister,
366
                                 immTempRegister);
367
            }
368
            m_assembler.sw(dataTempRegister, address.base, address.offset);
369
        } else {
370
            /*
371
              lui       addrTemp, (offset + 0x8000) >> 16
372
              addu      addrTemp, addrTemp, base
373
              lw        dataTemp, (offset & 0xffff)(addrTemp)
374
              li        immtemp, imm
375
              subu      dataTemp, dataTemp, immTemp
376
              sw        dataTemp, (offset & 0xffff)(addrTemp)
377
            */
378
            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
379
            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
380
            m_assembler.lw(dataTempRegister, addrTempRegister, address.offset);
381
382
            if (!imm.m_isPointer
383
                && imm.m_value >= -32767 && imm.m_value <= 32768
384
                && !m_fixedWidth)
385
                m_assembler.addiu(dataTempRegister, dataTempRegister,
386
                                  -imm.m_value);
387
            else {
388
                move(imm, immTempRegister);
389
                m_assembler.subu(dataTempRegister, dataTempRegister,
390
                                 immTempRegister);
391
            }
392
            m_assembler.sw(dataTempRegister, addrTempRegister, address.offset);
393
        }
394
    }
395
396
    void sub32(Address src, RegisterID dest)
397
    {
398
        load32(src, dataTempRegister);
399
        sub32(dataTempRegister, dest);
400
    }
401
402
    void sub32(Imm32 imm, AbsoluteAddress address)
403
    {
404
        /*
405
           li   addrTemp, address
406
           li   immTemp, imm
407
           lw   dataTemp, 0(addrTemp)
408
           subu dataTemp, dataTemp, immTemp
409
           sw   dataTemp, 0(addrTemp)
410
        */
411
        move(ImmPtr(address.m_ptr), addrTempRegister);
412
        m_assembler.lw(dataTempRegister, addrTempRegister, 0);
413
414
        if (!imm.m_isPointer && imm.m_value >= -32767 && imm.m_value <= 32768
415
            && !m_fixedWidth) {
416
            m_assembler.addiu(dataTempRegister, dataTempRegister,
417
                              -imm.m_value);
418
        } else {
419
            move(imm, immTempRegister);
420
            m_assembler.subu(dataTempRegister, dataTempRegister, immTempRegister);
421
        }
422
        m_assembler.sw(dataTempRegister, addrTempRegister, 0);
423
    }
424
425
    void xor32(RegisterID src, RegisterID dest)
426
    {
427
        m_assembler.xorInsn(dest, dest, src);
428
    }
429
430
    void xor32(Imm32 imm, RegisterID dest)
431
    {
432
        /*
433
            li  immTemp, imm
434
            xor dest, dest, immTemp
435
        */
436
        move(imm, immTempRegister);
437
        m_assembler.xorInsn(dest, dest, immTempRegister);
438
    }
439
440
    // Memory access operations:
441
    //
442
    // Loads are of the form load(address, destination) and stores of the form
443
    // store(source, address).  The source for a store may be an Imm32.  Address
444
    // operand objects to loads and store will be implicitly constructed if a
445
    // register is passed.
446
447
    void load32(ImplicitAddress address, RegisterID dest)
448
    {
449
        if (address.offset >= -32768 && address.offset <= 32767
450
            && !m_fixedWidth)
451
            m_assembler.lw(dest, address.base, address.offset);
452
        else {
453
            /*
454
                lui     addrTemp, (offset + 0x8000) >> 16
455
                addu    addrTemp, addrTemp, base
456
                lw      dest, (offset & 0xffff)(addrTemp)
457
              */
458
            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
459
            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
460
            m_assembler.lw(dest, addrTempRegister, address.offset);
461
        }
462
    }
463
464
    void load32(BaseIndex address, RegisterID dest)
465
    {
466
        if (address.offset >= -32768 && address.offset <= 32767
467
            && !m_fixedWidth) {
468
            /*
469
                sll     addrTemp, address.index, address.scale
470
                addu    addrTemp, addrTemp, address.base
471
                lw      dest, address.offset(addrTemp)
472
            */
473
            m_assembler.sll(addrTempRegister, address.index, address.scale);
474
            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
475
            m_assembler.lw(dest, addrTempRegister, address.offset);
476
        } else {
477
            /*
478
                sll     addrTemp, address.index, address.scale
479
                addu    addrTemp, addrTemp, address.base
480
                lui     immTemp, (address.offset + 0x8000) >> 16
481
                addu    addrTemp, addrTemp, immTemp
482
                lw      dest, (address.offset & 0xffff)(at)
483
            */
484
            m_assembler.sll(addrTempRegister, address.index, address.scale);
485
            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
486
            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
487
            m_assembler.addu(addrTempRegister, addrTempRegister,
488
                             immTempRegister);
489
            m_assembler.lw(dest, addrTempRegister, address.offset);
490
        }
491
    }
492
493
    void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
494
    {
495
        if (address.offset >= -32768 && address.offset <= 32764
496
            && !m_fixedWidth) {
497
            /*
498
                sll     addrTemp, address.index, address.scale
499
                addu    addrTemp, addrTemp, address.base
500
                (Big-Endian)
501
                lwl     dest, address.offset(addrTemp)
502
                lwr     dest, address.offset+3(addrTemp)
503
                (Little-Endian)
504
                lwl     dest, address.offset+3(addrTemp)
505
                lwr     dest, address.offset(addrTemp)
506
            */
507
            m_assembler.sll(addrTempRegister, address.index, address.scale);
508
            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
509
#if CPU(BIG_ENDIAN)
510
            m_assembler.lwl(dest, addrTempRegister, address.offset);
511
            m_assembler.lwr(dest, addrTempRegister, address.offset + 3);
512
#else
513
            m_assembler.lwl(dest, addrTempRegister, address.offset + 3);
514
            m_assembler.lwr(dest, addrTempRegister, address.offset);
515
516
#endif
517
        } else {
518
            /*
519
                sll     addrTemp, address.index, address.scale
520
                addu    addrTemp, addrTemp, address.base
521
                lui     immTemp, address.offset >> 16
522
                ori     immTemp, immTemp, address.offset & 0xffff
523
                addu    addrTemp, addrTemp, immTemp
524
                (Big-Endian)
525
                lw      dest, 0(at)
526
                lw      dest, 3(at)
527
                (Little-Endian)
528
                lw      dest, 3(at)
529
                lw      dest, 0(at)
530
            */
531
            m_assembler.sll(addrTempRegister, address.index, address.scale);
532
            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
533
            m_assembler.lui(immTempRegister, address.offset >> 16);
534
            m_assembler.ori(immTempRegister, immTempRegister, address.offset);
535
            m_assembler.addu(addrTempRegister, addrTempRegister,
536
                             immTempRegister);
537
#if CPU(BIG_ENDIAN)
538
            m_assembler.lwl(dest, addrTempRegister, 0);
539
            m_assembler.lwr(dest, addrTempRegister, 3);
540
#else
541
            m_assembler.lwl(dest, addrTempRegister, 3);
542
            m_assembler.lwr(dest, addrTempRegister, 0);
543
#endif
544
        }
545
    }
546
547
    void load32(void* address, RegisterID dest)
548
    {
549
        /*
550
            li  addrTemp, address
551
            lw  dest, 0(addrTemp)
552
        */
553
        move(ImmPtr(address), addrTempRegister);
554
        m_assembler.lw(dest, addrTempRegister, 0);
555
    }
556
557
    DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
558
    {
559
        m_fixedWidth = true;
560
        /*
561
            lui addrTemp, address.offset >> 16
562
            ori addrTemp, addrTemp, address.offset & 0xffff
563
            addu        addrTemp, addrTemp, address.base
564
            lw  dest, 0(addrTemp)
565
        */
566
        DataLabel32 dataLabel(this);
567
        move(Imm32(address.offset), addrTempRegister);
568
        m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
569
        m_assembler.lw(dest, addrTempRegister, 0);
570
        m_fixedWidth = false;
571
        return dataLabel;
572
    }
573
574
    Label loadPtrWithPatchToLEA(Address address, RegisterID dest)
575
    {
576
        m_fixedWidth = true;
577
        /*
578
            lui         addrTemp, address.offset >> 16
579
            ori         addrTemp, addrTemp, address.offset & 0xffff
580
            addu        addrTemp, addrTemp, address.base
581
            lw          dest, 0(addrTemp)
582
        */
583
        Label label(this);
584
        move(Imm32(address.offset), addrTempRegister);
585
        m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
586
        m_assembler.lw(dest, addrTempRegister, 0);
587
        m_fixedWidth = false;
588
        return label;
589
    }
590
591
    Label loadPtrWithAddressOffsetPatch(Address address, RegisterID dest)
592
    {
593
        return loadPtrWithPatchToLEA(address, dest);
594
    }
595
596
    /* Need to use zero-extened load half-word for load16.  */
597
    void load16(BaseIndex address, RegisterID dest)
598
    {
599
        if (address.offset >= -32768 && address.offset <= 32767
600
            && !m_fixedWidth) {
601
            /*
602
                sll     addrTemp, address.index, address.scale
603
                addu    addrTemp, addrTemp, address.base
604
                lhu     dest, address.offset(addrTemp)
605
            */
606
            m_assembler.sll(addrTempRegister, address.index, address.scale);
607
            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
608
            m_assembler.lhu(dest, addrTempRegister, address.offset);
609
        } else {
610
            /*
611
                sll     addrTemp, address.index, address.scale
612
                addu    addrTemp, addrTemp, address.base
613
                lui     immTemp, (address.offset + 0x8000) >> 16
614
                addu    addrTemp, addrTemp, immTemp
615
                lhu     dest, (address.offset & 0xffff)(addrTemp)
616
            */
617
            m_assembler.sll(addrTempRegister, address.index, address.scale);
618
            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
619
            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
620
            m_assembler.addu(addrTempRegister, addrTempRegister,
621
                             immTempRegister);
622
            m_assembler.lhu(dest, addrTempRegister, address.offset);
623
        }
624
    }
625
626
    DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
627
    {
628
        m_fixedWidth = true;
629
        /*
630
            lui addrTemp, address.offset >> 16
631
            ori addrTemp, addrTemp, address.offset & 0xffff
632
            addu        addrTemp, addrTemp, address.base
633
            sw  src, 0(addrTemp)
634
        */
635
        DataLabel32 dataLabel(this);
636
        move(Imm32(address.offset), addrTempRegister);
637
        m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
638
        m_assembler.sw(src, addrTempRegister, 0);
639
        m_fixedWidth = false;
640
        return dataLabel;
641
    }
642
643
    void store32(RegisterID src, ImplicitAddress address)
644
    {
645
        if (address.offset >= -32768 && address.offset <= 32767
646
            && !m_fixedWidth)
647
            m_assembler.sw(src, address.base, address.offset);
648
        else {
649
            /*
650
                lui     addrTemp, (offset + 0x8000) >> 16
651
                addu    addrTemp, addrTemp, base
652
                sw      src, (offset & 0xffff)(addrTemp)
653
              */
654
            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
655
            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
656
            m_assembler.sw(src, addrTempRegister, address.offset);
657
        }
658
    }
659
660
    void store32(RegisterID src, BaseIndex address)
661
    {
662
        if (address.offset >= -32768 && address.offset <= 32767
663
            && !m_fixedWidth) {
664
            /*
665
                sll     addrTemp, address.index, address.scale
666
                addu    addrTemp, addrTemp, address.base
667
                sw      src, address.offset(addrTemp)
668
            */
669
            m_assembler.sll(addrTempRegister, address.index, address.scale);
670
            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
671
            m_assembler.sw(src, addrTempRegister, address.offset);
672
        } else {
673
            /*
674
                sll     addrTemp, address.index, address.scale
675
                addu    addrTemp, addrTemp, address.base
676
                lui     immTemp, (address.offset + 0x8000) >> 16
677
                addu    addrTemp, addrTemp, immTemp
678
                sw      src, (address.offset & 0xffff)(at)
679
            */
680
            m_assembler.sll(addrTempRegister, address.index, address.scale);
681
            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
682
            m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
683
            m_assembler.addu(addrTempRegister, addrTempRegister,
684
                             immTempRegister);
685
            m_assembler.sw(src, addrTempRegister, address.offset);
686
        }
687
    }
688
689
    void store32(Imm32 imm, ImplicitAddress address)
690
    {
691
        if (address.offset >= -32768 && address.offset <= 32767
692
            && !m_fixedWidth) {
693
            if (!imm.m_isPointer && !imm.m_value)
694
                m_assembler.sw(MIPSRegisters::zero, address.base,
695
                               address.offset);
696
            else {
697
                move(imm, immTempRegister);
698
                m_assembler.sw(immTempRegister, address.base, address.offset);
699
            }
700
        } else {
701
            /*
702
                lui     addrTemp, (offset + 0x8000) >> 16
703
                addu    addrTemp, addrTemp, base
704
                sw      immTemp, (offset & 0xffff)(addrTemp)
705
              */
706
            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
707
            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
708
            if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
709
                m_assembler.sw(MIPSRegisters::zero, addrTempRegister,
710
                               address.offset);
711
            else {
712
                move(imm, immTempRegister);
713
                m_assembler.sw(immTempRegister, addrTempRegister,
714
                               address.offset);
715
            }
716
        }
717
    }
718
719
    void store32(RegisterID src, void* address)
720
    {
721
        /*
722
            li  addrTemp, address
723
            sw  src, 0(addrTemp)
724
        */
725
        move(ImmPtr(address), addrTempRegister);
726
        m_assembler.sw(src, addrTempRegister, 0);
727
    }
728
729
    void store32(Imm32 imm, void* address)
730
    {
731
        /*
732
            li  immTemp, imm
733
            li  addrTemp, address
734
            sw  src, 0(addrTemp)
735
        */
736
        if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) {
737
            move(ImmPtr(address), addrTempRegister);
738
            m_assembler.sw(MIPSRegisters::zero, addrTempRegister, 0);
739
        } else {
740
            move(imm, immTempRegister);
741
            move(ImmPtr(address), addrTempRegister);
742
            m_assembler.sw(immTempRegister, addrTempRegister, 0);
743
        }
744
    }
745
746
    // Floating-point operations:
747
748
    bool supportsFloatingPoint() const
749
    {
750
#if WTF_MIPS_DOUBLE_FLOAT
751
        return true;
752
#else
753
        return false;
754
#endif
755
    }
756
757
    bool supportsFloatingPointTruncate() const
758
    {
759
#if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2)
760
        return true;
761
#else
762
        return false;
763
#endif
764
    }
765
766
    // Stack manipulation operations:
767
    //
768
    // The ABI is assumed to provide a stack abstraction to memory,
769
    // containing machine word sized units of data.  Push and pop
770
    // operations add and remove a single register sized unit of data
771
    // to or from the stack.  Peek and poke operations read or write
772
    // values on the stack, without moving the current stack position.
773
774
    void pop(RegisterID dest)
775
    {
776
        m_assembler.lw(dest, MIPSRegisters::sp, 0);
777
        m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, 4);
778
    }
779
780
    void push(RegisterID src)
781
    {
782
        m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, -4);
783
        m_assembler.sw(src, MIPSRegisters::sp, 0);
784
    }
785
786
    void push(Address address)
787
    {
788
        load32(address, dataTempRegister);
789
        push(dataTempRegister);
790
    }
791
792
    void push(Imm32 imm)
793
    {
794
        move(imm, immTempRegister);
795
        push(immTempRegister);
796
    }
797
798
    // Register move operations:
799
    //
800
    // Move values in registers.
801
802
    void move(Imm32 imm, RegisterID dest)
803
    {
804
        if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
805
            move(MIPSRegisters::zero, dest);
806
        else if (imm.m_isPointer || m_fixedWidth) {
807
            m_assembler.lui(dest, imm.m_value >> 16);
808
            m_assembler.ori(dest, dest, imm.m_value);
809
        } else
810
            m_assembler.li(dest, imm.m_value);
811
    }
812
813
    void move(RegisterID src, RegisterID dest)
814
    {
815
        if (src != dest || m_fixedWidth)
816
            m_assembler.move(dest, src);
817
    }
818
819
    void move(ImmPtr imm, RegisterID dest)
820
    {
821
        move(Imm32(imm), dest);
822
    }
823
824
    void swap(RegisterID reg1, RegisterID reg2)
825
    {
826
        move(reg1, immTempRegister);
827
        move(reg2, reg1);
828
        move(immTempRegister, reg2);
829
    }
830
831
    void signExtend32ToPtr(RegisterID src, RegisterID dest)
832
    {
833
        if (src != dest || m_fixedWidth)
834
            move(src, dest);
835
    }
836
837
    void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
838
    {
839
        if (src != dest || m_fixedWidth)
840
            move(src, dest);
841
    }
842
843
    // Forwards / external control flow operations:
844
    //
845
    // This set of jump and conditional branch operations return a Jump
846
    // object which may linked at a later point, allow forwards jump,
847
    // or jumps that will require external linkage (after the code has been
848
    // relocated).
849
    //
850
    // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
851
    // respecitvely, for unsigned comparisons the names b, a, be, and ae are
852
    // used (representing the names 'below' and 'above').
853
    //
854
    // Operands to the comparision are provided in the expected order, e.g.
855
    // jle32(reg1, Imm32(5)) will branch if the value held in reg1, when
856
    // treated as a signed 32bit value, is less than or equal to 5.
857
    //
858
    // jz and jnz test whether the first operand is equal to zero, and take
859
    // an optional second operand of a mask under which to perform the test.
860
861
    Jump branch32(Condition cond, RegisterID left, RegisterID right)
862
    {
863
        if (cond == Equal || cond == Zero)
864
            return branchEqual(left, right);
865
        if (cond == NotEqual || cond == NonZero)
866
            return branchNotEqual(left, right);
867
        if (cond == Above) {
868
            m_assembler.sltu(cmpTempRegister, right, left);
869
            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
870
        }
871
        if (cond == AboveOrEqual) {
872
            m_assembler.sltu(cmpTempRegister, left, right);
873
            return branchEqual(cmpTempRegister, MIPSRegisters::zero);
874
        }
875
        if (cond == Below) {
876
            m_assembler.sltu(cmpTempRegister, left, right);
877
            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
878
        }
879
        if (cond == BelowOrEqual) {
880
            m_assembler.sltu(cmpTempRegister, right, left);
881
            return branchEqual(cmpTempRegister, MIPSRegisters::zero);
882
        }
883
        if (cond == GreaterThan) {
884
            m_assembler.slt(cmpTempRegister, right, left);
885
            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
886
        }
887
        if (cond == GreaterThanOrEqual) {
888
            m_assembler.slt(cmpTempRegister, left, right);
889
            return branchEqual(cmpTempRegister, MIPSRegisters::zero);
890
        }
891
        if (cond == LessThan) {
892
            m_assembler.slt(cmpTempRegister, left, right);
893
            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
894
        }
895
        if (cond == LessThanOrEqual) {
896
            m_assembler.slt(cmpTempRegister, right, left);
897
            return branchEqual(cmpTempRegister, MIPSRegisters::zero);
898
        }
899
        if (cond == Overflow) {
900
            /*
901
                xor     cmpTemp, left, right
902
                bgez    No_overflow, cmpTemp    # same sign bit -> no overflow
903
                nop
904
                subu    cmpTemp, left, right
905
                xor     cmpTemp, cmpTemp, left
906
                bgez    No_overflow, cmpTemp    # same sign bit -> no overflow
907
                nop
908
                b       Overflow
909
                nop
910
                nop
911
                nop
912
                nop
913
                nop
914
              No_overflow:
915
            */
916
            m_assembler.xorInsn(cmpTempRegister, left, right);
917
            m_assembler.bgez(cmpTempRegister, 11);
918
            m_assembler.nop();
919
            m_assembler.subu(cmpTempRegister, left, right);
920
            m_assembler.xorInsn(cmpTempRegister, cmpTempRegister, left);
921
            m_assembler.bgez(cmpTempRegister, 7);
922
            m_assembler.nop();
923
            return jump();
924
        }
925
        if (cond == Signed) {
926
            m_assembler.subu(cmpTempRegister, left, right);
927
            // Check if the result is negative.
928
            m_assembler.slt(cmpTempRegister, cmpTempRegister,
929
                            MIPSRegisters::zero);
930
            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
931
        }
932
        ASSERT(0);
933
934
        return Jump();
935
    }
936
937
    Jump branch32(Condition cond, RegisterID left, Imm32 right)
938
    {
939
        move(right, immTempRegister);
940
        return branch32(cond, left, immTempRegister);
941
    }
942
943
    Jump branch32(Condition cond, RegisterID left, Address right)
944
    {
945
        load32(right, dataTempRegister);
946
        return branch32(cond, left, dataTempRegister);
947
    }
948
949
    Jump branch32(Condition cond, Address left, RegisterID right)
950
    {
951
        load32(left, dataTempRegister);
952
        return branch32(cond, dataTempRegister, right);
953
    }
954
955
    Jump branch32(Condition cond, Address left, Imm32 right)
956
    {
957
        load32(left, dataTempRegister);
958
        move(right, immTempRegister);
959
        return branch32(cond, dataTempRegister, immTempRegister);
960
    }
961
962
    Jump branch32(Condition cond, BaseIndex left, Imm32 right)
963
    {
964
        load32(left, dataTempRegister);
965
        // Be careful that the previous load32() uses immTempRegister.
966
        // So, we need to put move() after load32().
967
        move(right, immTempRegister);
968
        return branch32(cond, dataTempRegister, immTempRegister);
969
    }
970
971
    Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
972
    {
973
        load32WithUnalignedHalfWords(left, dataTempRegister);
974
        // Be careful that the previous load32WithUnalignedHalfWords()
975
        // uses immTempRegister.
976
        // So, we need to put move() after load32WithUnalignedHalfWords().
977
        move(right, immTempRegister);
978
        return branch32(cond, dataTempRegister, immTempRegister);
979
    }
980
981
    Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right)
982
    {
983
        load32(left.m_ptr, dataTempRegister);
984
        return branch32(cond, dataTempRegister, right);
985
    }
986
987
    Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right)
988
    {
989
        load32(left.m_ptr, dataTempRegister);
990
        move(right, immTempRegister);
991
        return branch32(cond, dataTempRegister, immTempRegister);
992
    }
993
994
    Jump branch16(Condition cond, BaseIndex left, RegisterID right)
995
    {
996
        load16(left, dataTempRegister);
997
        return branch32(cond, dataTempRegister, right);
998
    }
999
1000
    Jump branch16(Condition cond, BaseIndex left, Imm32 right)
1001
    {
1002
        ASSERT(!(right.m_value & 0xFFFF0000));
1003
        load16(left, dataTempRegister);
1004
        // Be careful that the previous load16() uses immTempRegister.
1005
        // So, we need to put move() after load16().
1006
        move(right, immTempRegister);
1007
        return branch32(cond, dataTempRegister, immTempRegister);
1008
    }
1009
1010
    Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask)
1011
    {
1012
        ASSERT((cond == Zero) || (cond == NonZero));
1013
        m_assembler.andInsn(cmpTempRegister, reg, mask);
1014
        if (cond == Zero)
1015
            return branchEqual(cmpTempRegister, MIPSRegisters::zero);
1016
        return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1017
    }
1018
1019
    Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1))
1020
    {
1021
        ASSERT((cond == Zero) || (cond == NonZero));
1022
        if (mask.m_value == -1 && !m_fixedWidth) {
1023
            if (cond == Zero)
1024
                return branchEqual(reg, MIPSRegisters::zero);
1025
            return branchNotEqual(reg, MIPSRegisters::zero);
1026
        }
1027
        move(mask, immTempRegister);
1028
        return branchTest32(cond, reg, immTempRegister);
1029
    }
1030
1031
    Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1))
1032
    {
1033
        load32(address, dataTempRegister);
1034
        return branchTest32(cond, dataTempRegister, mask);
1035
    }
1036
1037
    Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1))
1038
    {
1039
        load32(address, dataTempRegister);
1040
        return branchTest32(cond, dataTempRegister, mask);
1041
    }
1042
1043
    Jump jump()
1044
    {
1045
        return branchEqual(MIPSRegisters::zero, MIPSRegisters::zero);
1046
    }
1047
1048
    void jump(RegisterID target)
1049
    {
1050
        m_assembler.jr(target);
1051
        m_assembler.nop();
1052
    }
1053
1054
    void jump(Address address)
1055
    {
1056
        m_fixedWidth = true;
1057
        load32(address, MIPSRegisters::t9);
1058
        m_assembler.jr(MIPSRegisters::t9);
1059
        m_assembler.nop();
1060
        m_fixedWidth = false;
1061
    }
1062
1063
    // Arithmetic control flow operations:
1064
    //
1065
    // This set of conditional branch operations branch based
1066
    // on the result of an arithmetic operation.  The operation
1067
    // is performed as normal, storing the result.
1068
    //
1069
    // * jz operations branch if the result is zero.
1070
    // * jo operations branch if the (signed) arithmetic
1071
    //   operation caused an overflow to occur.
1072
1073
    Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest)
1074
    {
1075
        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1076
        if (cond == Overflow) {
1077
            /*
1078
                move    dest, dataTemp
1079
                xor     cmpTemp, dataTemp, src
1080
                bltz    cmpTemp, No_overflow    # diff sign bit -> no overflow
1081
                addu    dest, dataTemp, src
1082
                xor     cmpTemp, dest, dataTemp
1083
                bgez    cmpTemp, No_overflow    # same sign big -> no overflow
1084
                nop
1085
                b       Overflow
1086
                nop
1087
                nop
1088
                nop
1089
                nop
1090
                nop
1091
            No_overflow:
1092
            */
1093
            move(dest, dataTempRegister);
1094
            m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src);
1095
            m_assembler.bltz(cmpTempRegister, 10);
1096
            m_assembler.addu(dest, dataTempRegister, src);
1097
            m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
1098
            m_assembler.bgez(cmpTempRegister, 7);
1099
            m_assembler.nop();
1100
            return jump();
1101
        }
1102
        if (cond == Signed) {
1103
            add32(src, dest);
1104
            // Check if dest is negative.
1105
            m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1106
            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1107
        }
1108
        if (cond == Zero) {
1109
            add32(src, dest);
1110
            return branchEqual(dest, MIPSRegisters::zero);
1111
        }
1112
        if (cond == NonZero) {
1113
            add32(src, dest);
1114
            return branchNotEqual(dest, MIPSRegisters::zero);
1115
        }
1116
        ASSERT(0);
1117
        return Jump();
1118
    }
1119
1120
    Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest)
1121
    {
1122
        move(imm, immTempRegister);
1123
        return branchAdd32(cond, immTempRegister, dest);
1124
    }
1125
1126
    Jump branchMul32(Condition cond, RegisterID src, RegisterID dest)
1127
    {
1128
        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1129
        if (cond == Overflow) {
1130
            /*
1131
                mult    src, dest
1132
                mfhi    dataTemp
1133
                mflo    dest
1134
                sra     addrTemp, dest, 31
1135
                beq     dataTemp, addrTemp, No_overflow # all sign bits (bit 63 to bit 31) are the same -> no overflow
1136
                nop
1137
                b       Overflow
1138
                nop
1139
                nop
1140
                nop
1141
                nop
1142
                nop
1143
            No_overflow:
1144
            */
1145
            m_assembler.mult(src, dest);
1146
            m_assembler.mfhi(dataTempRegister);
1147
            m_assembler.mflo(dest);
1148
            m_assembler.sra(addrTempRegister, dest, 31);
1149
            m_assembler.beq(dataTempRegister, addrTempRegister, 7);
1150
            m_assembler.nop();
1151
            return jump();
1152
        }
1153
        if (cond == Signed) {
1154
            mul32(src, dest);
1155
            // Check if dest is negative.
1156
            m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1157
            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1158
        }
1159
        if (cond == Zero) {
1160
            mul32(src, dest);
1161
            return branchEqual(dest, MIPSRegisters::zero);
1162
        }
1163
        if (cond == NonZero) {
1164
            mul32(src, dest);
1165
            return branchNotEqual(dest, MIPSRegisters::zero);
1166
        }
1167
        ASSERT(0);
1168
        return Jump();
1169
    }
1170
1171
    Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest)
1172
    {
1173
        move(imm, immTempRegister);
1174
        move(src, dest);
1175
        return branchMul32(cond, immTempRegister, dest);
1176
    }
1177
1178
    Jump branchSub32(Condition cond, RegisterID src, RegisterID dest)
1179
    {
1180
        ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
1181
        if (cond == Overflow) {
1182
            /*
1183
                move    dest, dataTemp
1184
                xor     cmpTemp, dataTemp, src
1185
                bgez    cmpTemp, No_overflow    # same sign bit -> no overflow
1186
                subu    dest, dataTemp, src
1187
                xor     cmpTemp, dest, dataTemp
1188
                bgez    cmpTemp, No_overflow    # same sign bit -> no overflow
1189
                nop
1190
                b       Overflow
1191
                nop
1192
                nop
1193
                nop
1194
                nop
1195
                nop
1196
            No_overflow:
1197
            */
1198
            move(dest, dataTempRegister);
1199
            m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src);
1200
            m_assembler.bgez(cmpTempRegister, 10);
1201
            m_assembler.subu(dest, dataTempRegister, src);
1202
            m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
1203
            m_assembler.bgez(cmpTempRegister, 7);
1204
            m_assembler.nop();
1205
            return jump();
1206
        }
1207
        if (cond == Signed) {
1208
            sub32(src, dest);
1209
            // Check if dest is negative.
1210
            m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
1211
            return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
1212
        }
1213
        if (cond == Zero) {
1214
            sub32(src, dest);
1215
            return branchEqual(dest, MIPSRegisters::zero);
1216
        }
1217
        if (cond == NonZero) {
1218
            sub32(src, dest);
1219
            return branchNotEqual(dest, MIPSRegisters::zero);
1220
        }
1221
        ASSERT(0);
1222
        return Jump();
1223
    }
1224
1225
    Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest)
1226
    {
1227
        move(imm, immTempRegister);
1228
        return branchSub32(cond, immTempRegister, dest);
1229
    }
1230
1231
    // Miscellaneous operations:
1232
1233
    void breakpoint()
1234
    {
1235
        m_assembler.bkpt();
1236
    }
1237
1238
    Call nearCall()
1239
    {
1240
        /* We need two words for relaxation.  */
1241
        m_assembler.nop();
1242
        m_assembler.nop();
1243
        m_assembler.jal();
1244
        m_assembler.nop();
1245
        return Call(m_assembler.newJmpSrc(), Call::LinkableNear);
1246
    }
1247
1248
    Call call()
1249
    {
1250
        m_assembler.lui(MIPSRegisters::t9, 0);
1251
        m_assembler.ori(MIPSRegisters::t9, MIPSRegisters::t9, 0);
1252
        m_assembler.jalr(MIPSRegisters::t9);
1253
        m_assembler.nop();
1254
        return Call(m_assembler.newJmpSrc(), Call::Linkable);
1255
    }
1256
1257
    Call call(RegisterID target)
1258
    {
1259
        m_assembler.jalr(target);
1260
        m_assembler.nop();
1261
        return Call(m_assembler.newJmpSrc(), Call::None);
1262
    }
1263
1264
    Call call(Address address)
1265
    {
1266
        m_fixedWidth = true;
1267
        load32(address, MIPSRegisters::t9);
1268
        m_assembler.jalr(MIPSRegisters::t9);
1269
        m_assembler.nop();
1270
        m_fixedWidth = false;
1271
        return Call(m_assembler.newJmpSrc(), Call::None);
1272
    }
1273
1274
    void ret()
1275
    {
1276
        m_assembler.jr(MIPSRegisters::ra);
1277
        m_assembler.nop();
1278
    }
1279
1280
    void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
1281
    {
1282
        if (cond == Equal || cond == Zero) {
1283
            m_assembler.xorInsn(dest, left, right);
1284
            m_assembler.sltiu(dest, dest, 1);
1285
        } else if (cond == NotEqual || cond == NonZero) {
1286
            m_assembler.xorInsn(dest, left, right);
1287
            m_assembler.sltu(dest, MIPSRegisters::zero, dest);
1288
        } else if (cond == Above)
1289
            m_assembler.sltu(dest, right, left);
1290
        else if (cond == AboveOrEqual) {
1291
            m_assembler.sltu(dest, left, right);
1292
            m_assembler.xori(dest, dest, 1);
1293
        } else if (cond == Below)
1294
            m_assembler.sltu(dest, left, right);
1295
        else if (cond == BelowOrEqual) {
1296
            m_assembler.sltu(dest, right, left);
1297
            m_assembler.xori(dest, dest, 1);
1298
        } else if (cond == GreaterThan)
1299
            m_assembler.slt(dest, right, left);
1300
        else if (cond == GreaterThanOrEqual) {
1301
            m_assembler.slt(dest, left, right);
1302
            m_assembler.xori(dest, dest, 1);
1303
        } else if (cond == LessThan)
1304
            m_assembler.slt(dest, left, right);
1305
        else if (cond == LessThanOrEqual) {
1306
            m_assembler.slt(dest, right, left);
1307
            m_assembler.xori(dest, dest, 1);
1308
        } else if (cond == Overflow) {
1309
            /*
1310
                xor     cmpTemp, left, right
1311
                bgez    Done, cmpTemp   # same sign bit -> no overflow
1312
                move    dest, 0
1313
                subu    cmpTemp, left, right
1314
                xor     cmpTemp, cmpTemp, left # diff sign bit -> overflow
1315
                slt     dest, cmpTemp, 0
1316
              Done:
1317
            */
1318
            m_assembler.xorInsn(cmpTempRegister, left, right);
1319
            m_assembler.bgez(cmpTempRegister, 4);
1320
            m_assembler.move(dest, MIPSRegisters::zero);
1321
            m_assembler.subu(cmpTempRegister, left, right);
1322
            m_assembler.xorInsn(cmpTempRegister, cmpTempRegister, left);
1323
            m_assembler.slt(dest, cmpTempRegister, MIPSRegisters::zero);
1324
        } else if (cond == Signed) {
1325
            m_assembler.subu(dest, left, right);
1326
            // Check if the result is negative.
1327
            m_assembler.slt(dest, dest, MIPSRegisters::zero);
1328
        }
1329
    }
1330
1331
    void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
1332
    {
1333
        move(right, immTempRegister);
1334
        set32(cond, left, immTempRegister, dest);
1335
    }
1336
1337
    void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest)
1338
    {
1339
        ASSERT((cond == Zero) || (cond == NonZero));
1340
        load32(address, dataTempRegister);
1341
        if (mask.m_value == -1 && !m_fixedWidth) {
1342
            if (cond == Zero)
1343
                m_assembler.sltiu(dest, dataTempRegister, 1);
1344
            else
1345
                m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister);
1346
        } else {
1347
            move(mask, immTempRegister);
1348
            m_assembler.andInsn(cmpTempRegister, dataTempRegister,
1349
                                 immTempRegister);
1350
            if (cond == Zero)
1351
                m_assembler.sltiu(dest, cmpTempRegister, 1);
1352
            else
1353
                m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister);
1354
        }
1355
    }
1356
1357
    DataLabel32 moveWithPatch(Imm32 imm, RegisterID dest)
1358
    {
1359
        m_fixedWidth = true;
1360
        DataLabel32 label(this);
1361
        move(imm, dest);
1362
        m_fixedWidth = false;
1363
        return label;
1364
    }
1365
1366
    DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest)
1367
    {
1368
        m_fixedWidth = true;
1369
        DataLabelPtr label(this);
1370
        move(initialValue, dest);
1371
        m_fixedWidth = false;
1372
        return label;
1373
    }
1374
1375
    Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
1376
    {
1377
        m_fixedWidth = true;
1378
        dataLabel = moveWithPatch(initialRightValue, immTempRegister);
1379
        Jump temp = branch32(cond, left, immTempRegister);
1380
        m_fixedWidth = false;
1381
        return temp;
1382
    }
1383
1384
    Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
1385
    {
1386
        m_fixedWidth = true;
1387
        load32(left, dataTempRegister);
1388
        dataLabel = moveWithPatch(initialRightValue, immTempRegister);
1389
        Jump temp = branch32(cond, dataTempRegister, immTempRegister);
1390
        m_fixedWidth = false;
1391
        return temp;
1392
    }
1393
1394
    DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address)
1395
    {
1396
        m_fixedWidth = true;
1397
        DataLabelPtr dataLabel = moveWithPatch(initialValue, dataTempRegister);
1398
        store32(dataTempRegister, address);
1399
        m_fixedWidth = false;
1400
        return dataLabel;
1401
    }
1402
1403
    DataLabelPtr storePtrWithPatch(ImplicitAddress address)
1404
    {
1405
        return storePtrWithPatch(ImmPtr(0), address);
1406
    }
1407
1408
    Call tailRecursiveCall()
1409
    {
1410
        // Like a normal call, but don't update the returned address register
1411
        m_fixedWidth = true;
1412
        move(Imm32(0), MIPSRegisters::t9);
1413
        m_assembler.jr(MIPSRegisters::t9);
1414
        m_assembler.nop();
1415
        m_fixedWidth = false;
1416
        return Call(m_assembler.newJmpSrc(), Call::Linkable);
1417
    }
1418
1419
    Call makeTailRecursiveCall(Jump oldJump)
1420
    {
1421
        oldJump.link(this);
1422
        return tailRecursiveCall();
1423
    }
1424
1425
    void loadDouble(ImplicitAddress address, FPRegisterID dest)
1426
    {
1427
#if WTF_MIPS_ISA(1)
1428
        /*
1429
            li          addrTemp, address.offset
1430
            addu        addrTemp, addrTemp, base
1431
            lwc1        dest, 0(addrTemp)
1432
            lwc1        dest+1, 4(addrTemp)
1433
         */
1434
        move(Imm32(address.offset), addrTempRegister);
1435
        m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1436
        m_assembler.lwc1(dest, addrTempRegister, 0);
1437
        m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4);
1438
#else
1439
        if (address.offset >= -32768 && address.offset <= 32767
1440
            && !m_fixedWidth) {
1441
            m_assembler.ldc1(dest, address.base, address.offset);
1442
        } else {
1443
            /*
1444
                lui     addrTemp, (offset + 0x8000) >> 16
1445
                addu    addrTemp, addrTemp, base
1446
                ldc1    dest, (offset & 0xffff)(addrTemp)
1447
              */
1448
            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
1449
            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1450
            m_assembler.ldc1(dest, addrTempRegister, address.offset);
1451
        }
1452
#endif
1453
    }
1454
1455
    void storeDouble(FPRegisterID src, ImplicitAddress address)
1456
    {
1457
#if WTF_MIPS_ISA(1)
1458
        /*
1459
            li          addrTemp, address.offset
1460
            addu        addrTemp, addrTemp, base
1461
            swc1        dest, 0(addrTemp)
1462
            swc1        dest+1, 4(addrTemp)
1463
         */
1464
        move(Imm32(address.offset), addrTempRegister);
1465
        m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1466
        m_assembler.swc1(src, addrTempRegister, 0);
1467
        m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, 4);
1468
#else
1469
        if (address.offset >= -32768 && address.offset <= 32767
1470
            && !m_fixedWidth)
1471
            m_assembler.sdc1(src, address.base, address.offset);
1472
        else {
1473
            /*
1474
                lui     addrTemp, (offset + 0x8000) >> 16
1475
                addu    addrTemp, addrTemp, base
1476
                sdc1    src, (offset & 0xffff)(addrTemp)
1477
              */
1478
            m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
1479
            m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
1480
            m_assembler.sdc1(src, addrTempRegister, address.offset);
1481
        }
1482
#endif
1483
    }
1484
1485
    void addDouble(FPRegisterID src, FPRegisterID dest)
1486
    {
1487
        m_assembler.addd(dest, dest, src);
1488
    }
1489
1490
    void addDouble(Address src, FPRegisterID dest)
1491
    {
1492
        loadDouble(src, fpTempRegister);
1493
        m_assembler.addd(dest, dest, fpTempRegister);
1494
    }
1495
1496
    void subDouble(FPRegisterID src, FPRegisterID dest)
1497
    {
1498
        m_assembler.subd(dest, dest, src);
1499
    }
1500
1501
    void subDouble(Address src, FPRegisterID dest)
1502
    {
1503
        loadDouble(src, fpTempRegister);
1504
        m_assembler.subd(dest, dest, fpTempRegister);
1505
    }
1506
1507
    void mulDouble(FPRegisterID src, FPRegisterID dest)
1508
    {
1509
        m_assembler.muld(dest, dest, src);
1510
    }
1511
1512
    void mulDouble(Address src, FPRegisterID dest)
1513
    {
1514
        loadDouble(src, fpTempRegister);
1515
        m_assembler.muld(dest, dest, fpTempRegister);
1516
    }
1517
1518
    void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
1519
    {
1520
        m_assembler.mtc1(src, fpTempRegister);
1521
        m_assembler.cvtdw(dest, fpTempRegister);
1522
    }
1523
1524
    void insertRelaxationWords()
1525
    {
1526
        /* We need four words for relaxation. */
1527
        m_assembler.beq(MIPSRegisters::zero, MIPSRegisters::zero, 3); // Jump over nops;
1528
        m_assembler.nop();
1529
        m_assembler.nop();
1530
        m_assembler.nop();
1531
    }
1532
1533
    Jump branchTrue()
1534
    {
1535
        m_assembler.appendJump();
1536
        m_assembler.bc1t();
1537
        m_assembler.nop();
1538
        insertRelaxationWords();
1539
        return Jump(m_assembler.newJmpSrc());
1540
    }
1541
1542
    Jump branchFalse()
1543
    {
1544
        m_assembler.appendJump();
1545
        m_assembler.bc1f();
1546
        m_assembler.nop();
1547
        insertRelaxationWords();
1548
        return Jump(m_assembler.newJmpSrc());
1549
    }
1550
1551
    Jump branchEqual(RegisterID rs, RegisterID rt)
1552
    {
1553
        m_assembler.appendJump();
1554
        m_assembler.beq(rs, rt, 0);
1555
        m_assembler.nop();
1556
        insertRelaxationWords();
1557
        return Jump(m_assembler.newJmpSrc());
1558
    }
1559
1560
    Jump branchNotEqual(RegisterID rs, RegisterID rt)
1561
    {
1562
        m_assembler.appendJump();
1563
        m_assembler.bne(rs, rt, 0);
1564
        m_assembler.nop();
1565
        insertRelaxationWords();
1566
        return Jump(m_assembler.newJmpSrc());
1567
    }
1568
1569
    Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
1570
    {
1571
        if (cond == DoubleEqual) {
1572
            m_assembler.ceqd(left, right);
1573
            return branchTrue();
1574
        }
1575
        if (cond == DoubleNotEqual) {
1576
            m_assembler.ceqd(left, right);
1577
            return branchFalse(); // false
1578
        }
1579
        if (cond == DoubleGreaterThan) {
1580
            m_assembler.cngtd(left, right);
1581
            return branchFalse(); // false
1582
        }
1583
        if (cond == DoubleGreaterThanOrEqual) {
1584
            m_assembler.cnged(right, left);
1585
            return branchFalse(); // false
1586
        }
1587
        if (cond == DoubleLessThan) {
1588
            m_assembler.cltd(left, right);
1589
            return branchTrue();
1590
        }
1591
        if (cond == DoubleLessThanOrEqual) {
1592
            m_assembler.cled(left, right);
1593
            return branchTrue();
1594
        }
1595
        if (cond == DoubleEqualOrUnordered) {
1596
            m_assembler.cueqd(left, right);
1597
            return branchTrue();
1598
        }
1599
        if (cond == DoubleGreaterThanOrUnordered) {
1600
            m_assembler.coled(left, right);
1601
            return branchFalse(); // false
1602
        }
1603
        if (cond == DoubleGreaterThanOrEqualOrUnordered) {
1604
            m_assembler.coltd(left, right);
1605
            return branchFalse(); // false
1606
        }
1607
        if (cond == DoubleLessThanOrUnordered) {
1608
            m_assembler.cultd(left, right);
1609
            return branchTrue();
1610
        }
1611
        if (cond == DoubleLessThanOrEqualOrUnordered) {
1612
            m_assembler.culed(left, right);
1613
            return branchTrue();
1614
        }
1615
        ASSERT(0);
1616
1617
        return Jump();
1618
    }
1619
1620
    // Truncates 'src' to an integer, and places the resulting 'dest'.
1621
    // If the result is not representable as a 32 bit value, branch.
1622
    // May also branch for some values that are representable in 32 bits
1623
    // (specifically, in this case, INT_MAX 0x7fffffff).
1624
    Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest)
1625
    {
1626
        m_assembler.truncwd(fpTempRegister, src);
1627
        m_assembler.mfc1(dest, fpTempRegister);
1628
        return branch32(Equal, dest, Imm32(0x7fffffff));
1629
    }
1630
1631
private:
1632
    // If m_fixedWidth is true, we will generate a fixed number of instructions.
1633
    // Otherwise, we can emit any number of instructions.
1634
    bool m_fixedWidth;
1635
1636
    friend class LinkBuffer;
1637
    friend class RepatchBuffer;
1638
1639
    static void linkCall(void* code, Call call, FunctionPtr function)
1640
    {
1641
        MIPSAssembler::linkCall(code, call.m_jmp, function.value());
1642
    }
1643
1644
    static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
1645
    {
1646
        MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
1647
    }
1648
1649
    static void repatchCall(CodeLocationCall call, FunctionPtr destination)
1650
    {
1651
        MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
1652
    }
1653
1654
};
1655
1656
}
1657
1658
#endif // ENABLE(ASSEMBLER) && CPU(MIPS)
1659
1660
#endif // MacroAssemblerMIPS_h
- JavaScriptCore/jit/ExecutableAllocator.h +30 lines
Lines 43-48 JavaScriptCore/jit/ExecutableAllocator.h_sec1
43
#include <e32std.h>
43
#include <e32std.h>
44
#endif
44
#endif
45
45
46
#if CPU(MIPS) && OS(LINUX)
47
#include <sys/cachectl.h>
48
#endif
49
46
#if OS(WINCE)
50
#if OS(WINCE)
47
// From pkfuncs.h (private header file from the Platform Builder)
51
// From pkfuncs.h (private header file from the Platform Builder)
48
#define CACHE_SYNC_ALL 0x07F
52
#define CACHE_SYNC_ALL 0x07F
Lines 190-195 public: JavaScriptCore/jit/ExecutableAllocator.h_sec2
190
    static void cacheFlush(void*, size_t)
194
    static void cacheFlush(void*, size_t)
191
    {
195
    {
192
    }
196
    }
197
#elif CPU(MIPS)
198
    static void cacheFlush(void* code, size_t size)
199
    {
200
#if COMPILER(GCC) && (GCC_VERSION >= 40300)
201
#if WTF_MIPS_ISA_REV(2) && (GCC_VERSION < 40403)
202
        int lineSize;
203
        asm ("rdhwr %0, $1" : "=r" (lineSize));
204
        //
205
        // Modify "start" and "end" to avoid GCC 4.3.0-4.4.2 bug in
206
        // mips_expand_synci_loop that may execute synci one more time.
207
        // "start" points to the fisrt byte of the cache line.
208
        // "end" points to the last byte of the line before the last cache line.
209
        // Because size is always a multiple of 4, this is safe to set
210
        // "end" to the last byte.
211
        //
212
        intptr_t start = reinterpret_cast<intptr_t>(code) & (-lineSize);
213
        intptr_t end = ((reinterpret_cast<intptr_t>(code) + size - 1) & (-lineSize)) - 1;
214
        __builtin___clear_cache(reinterpret_cast<char*>(start), reinterpret_cast<char*>(end));
215
#else
216
        intptr_t end = reinterpret_cast<intptr_t>(code) + size;
217
        __builtin___clear_cache(reinterpret_cast<char*>(code), reinterpret_cast<char*>(end));
218
#endif
219
#else
220
        _flush_cache(reinterpret_cast<char*>(code), size, BCACHE);
221
#endif
222
    }
193
#elif CPU(ARM_THUMB2) && OS(IPHONE_OS)
223
#elif CPU(ARM_THUMB2) && OS(IPHONE_OS)
194
    static void cacheFlush(void* code, size_t size)
224
    static void cacheFlush(void* code, size_t size)
195
    {
225
    {
- JavaScriptCore/jit/JIT.h +64 lines
Lines 268-273 namespace JSC { JavaScriptCore/jit/JIT.h_sec1
268
        static const FPRegisterID fpRegT0 = ARMRegisters::d0;
268
        static const FPRegisterID fpRegT0 = ARMRegisters::d0;
269
        static const FPRegisterID fpRegT1 = ARMRegisters::d1;
269
        static const FPRegisterID fpRegT1 = ARMRegisters::d1;
270
        static const FPRegisterID fpRegT2 = ARMRegisters::d2;
270
        static const FPRegisterID fpRegT2 = ARMRegisters::d2;
271
#elif CPU(MIPS)
272
        static const RegisterID returnValueRegister = MIPSRegisters::v0;
273
        static const RegisterID cachedResultRegister = MIPSRegisters::v0;
274
        static const RegisterID firstArgumentRegister = MIPSRegisters::a0;
275
276
        // regT0 must be v0 for returning a 32-bit value.
277
        static const RegisterID regT0 = MIPSRegisters::v0;
278
279
        // regT1 must be v1 for returning a pair of 32-bit value.
280
        static const RegisterID regT1 = MIPSRegisters::v1;
281
282
        static const RegisterID regT2 = MIPSRegisters::t4;
283
284
        // regT3 must be saved in the callee, so use an S register.
285
        static const RegisterID regT3 = MIPSRegisters::s2;
286
287
        static const RegisterID callFrameRegister = MIPSRegisters::s0;
288
        static const RegisterID timeoutCheckRegister = MIPSRegisters::s1;
289
290
        static const FPRegisterID fpRegT0 = MIPSRegisters::f4;
291
        static const FPRegisterID fpRegT1 = MIPSRegisters::f6;
292
        static const FPRegisterID fpRegT2 = MIPSRegisters::f8;
271
#else
293
#else
272
    #error "JIT not supported on this platform."
294
    #error "JIT not supported on this platform."
273
#endif
295
#endif
Lines 686-691 namespace JSC { JavaScriptCore/jit/JIT.h_sec2
686
        // sequencePutById
708
        // sequencePutById
687
        static const int sequencePutByIdInstructionSpace = 28;
709
        static const int sequencePutByIdInstructionSpace = 28;
688
        static const int sequencePutByIdConstantSpace = 3;
710
        static const int sequencePutByIdConstantSpace = 3;
711
#elif CPU(MIPS)
712
#if WTF_MIPS_ISA(1)
713
        static const int patchOffsetPutByIdStructure = 16;
714
        static const int patchOffsetPutByIdExternalLoad = 48;
715
        static const int patchLengthPutByIdExternalLoad = 20;
716
        static const int patchOffsetPutByIdPropertyMapOffset = 68;
717
        static const int patchOffsetGetByIdStructure = 16;
718
        static const int patchOffsetGetByIdBranchToSlowCase = 48;
719
        static const int patchOffsetGetByIdExternalLoad = 48;
720
        static const int patchLengthGetByIdExternalLoad = 20;
721
        static const int patchOffsetGetByIdPropertyMapOffset = 68;
722
        static const int patchOffsetGetByIdPutResult = 88;
723
#if ENABLE(OPCODE_SAMPLING)
724
        #error "OPCODE_SAMPLING is not yet supported"
725
#else
726
        static const int patchOffsetGetByIdSlowCaseCall = 40;
727
#endif
728
        static const int patchOffsetOpCallCompareToJump = 32;
729
        static const int patchOffsetMethodCheckProtoObj = 32;
730
        static const int patchOffsetMethodCheckProtoStruct = 56;
731
        static const int patchOffsetMethodCheckPutFunction = 88;
732
#else // WTF_MIPS_ISA(1)
733
        static const int patchOffsetPutByIdStructure = 12;
734
        static const int patchOffsetPutByIdExternalLoad = 44;
735
        static const int patchLengthPutByIdExternalLoad = 16;
736
        static const int patchOffsetPutByIdPropertyMapOffset = 60;
737
        static const int patchOffsetGetByIdStructure = 12;
738
        static const int patchOffsetGetByIdBranchToSlowCase = 44;
739
        static const int patchOffsetGetByIdExternalLoad = 44;
740
        static const int patchLengthGetByIdExternalLoad = 16;
741
        static const int patchOffsetGetByIdPropertyMapOffset = 60;
742
        static const int patchOffsetGetByIdPutResult = 76;
743
#if ENABLE(OPCODE_SAMPLING)
744
        #error "OPCODE_SAMPLING is not yet supported"
745
#else
746
        static const int patchOffsetGetByIdSlowCaseCall = 40;
747
#endif
748
        static const int patchOffsetOpCallCompareToJump = 32;
749
        static const int patchOffsetMethodCheckProtoObj = 32;
750
        static const int patchOffsetMethodCheckProtoStruct = 52;
751
        static const int patchOffsetMethodCheckPutFunction = 84;
752
#endif
689
#endif
753
#endif
690
#endif // USE(JSVALUE32_64)
754
#endif // USE(JSVALUE32_64)
691
755
- JavaScriptCore/jit/JITInlineMethods.h +17 lines
Lines 161-166 ALWAYS_INLINE void JIT::restoreReturnAdd JavaScriptCore/jit/JITInlineMethods.h_sec1
161
    loadPtr(address, linkRegister);
161
    loadPtr(address, linkRegister);
162
}
162
}
163
163
164
#elif CPU(MIPS)
165
166
ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg)
167
{
168
    move(returnAddressRegister, reg);
169
}
170
171
ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg)
172
{
173
    move(reg, returnAddressRegister);
174
}
175
176
ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address)
177
{
178
    loadPtr(address, returnAddressRegister);
179
}
180
164
#else // CPU(X86) || CPU(X86_64)
181
#else // CPU(X86) || CPU(X86_64)
165
182
166
ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg)
183
ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg)
- JavaScriptCore/jit/JITOpcodes.cpp +50 lines
Lines 1780-1785 void JIT::privateCompileCTIMachineTrampo JavaScriptCore/jit/JITOpcodes.cpp_sec1
1780
1780
1781
    addPtr(Imm32(sizeof(ArgList)), stackPointerRegister);
1781
    addPtr(Imm32(sizeof(ArgList)), stackPointerRegister);
1782
1782
1783
#elif CPU(MIPS)
1784
    emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0);
1785
1786
    // Allocate stack space for our arglist
1787
    COMPILE_ASSERT((sizeof(ArgList) & 0x7) == 0, ArgList_should_by_8byte_aligned);
1788
    subPtr(Imm32(sizeof(ArgList) + 24), stackPointerRegister);
1789
1790
    // Set up arguments
1791
    subPtr(Imm32(1), regT0); // Don't include 'this' in argcount
1792
1793
    // Push argcount to 24 + offset($sp)
1794
    storePtr(regT0, Address(stackPointerRegister, 24 + OBJECT_OFFSETOF(ArgList, m_argCount)));
1795
1796
    // Calculate the start of the callframe header, and store in regT1
1797
    move(callFrameRegister, regT1);
1798
    sub32(Imm32(RegisterFile::CallFrameHeaderSize * (int32_t)sizeof(Register)), regT1);
1799
1800
    // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT1)
1801
    mul32(Imm32(sizeof(Register)), regT0, regT0);
1802
    subPtr(regT0, regT1);
1803
1804
    // push pointer to arguments to 24 + offset($sp)
1805
    storePtr(regT1, Address(stackPointerRegister, 24 + OBJECT_OFFSETOF(ArgList, m_args)));
1806
1807
    // Setup arg3: regT1 currently points to the first argument, regT1-sizeof(Register) points to 'this'
1808
    loadPtr(Address(regT1, -(int32_t)sizeof(Register)), MIPSRegisters::a3);
1809
1810
    // Setup arg2:
1811
    emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, MIPSRegisters::a2);
1812
1813
    // Setup arg1:
1814
    move(callFrameRegister, MIPSRegisters::a1);
1815
1816
    // Setup arg4: ArgList is passed by reference.  At 16($sp), store ($sp + 24)
1817
    addPtr(Imm32(24), stackPointerRegister, regT2);
1818
    storePtr(regT2, Address(stackPointerRegister, 16));
1819
1820
    // Setup arg0 as 20($sp) to hold the returned structure.
1821
    ASSERT(sizeof(JSValue) == 4);
1822
    addPtr(Imm32(20), stackPointerRegister, MIPSRegisters::a0);
1823
1824
    // Call
1825
    call(Address(MIPSRegisters::a2, OBJECT_OFFSETOF(JSFunction, m_data)));
1826
1827
    // Get returned value from 0($v0) which is the same as 20($sp)
1828
    loadPtr(Address(returnValueRegister, 0), returnValueRegister);
1829
1830
    // Restore stack space
1831
    addPtr(Imm32(sizeof(ArgList) + 24), stackPointerRegister);
1832
1783
#elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
1833
#elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
1784
#error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform."
1834
#error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform."
1785
#else
1835
#else
- JavaScriptCore/jit/JITStubs.cpp +170 lines
Lines 642-647 SYMBOL_STRING(ctiOpThrowNotCaught) ":" " JavaScriptCore/jit/JITStubs.cpp_sec1
642
    "mov pc, lr" "\n"
642
    "mov pc, lr" "\n"
643
);
643
);
644
644
645
#elif CPU(MIPS)
646
647
#if USE(JIT_STUB_ARGUMENT_VA_LIST)
648
#error "JIT_STUB_ARGUMENT_VA_LIST not supported on MIPS."
649
#endif
650
651
asm volatile (
652
".text" "\n"
653
".align 2" "\n"
654
".set noreorder" "\n"
655
".set nomacro" "\n"
656
".set nomips16" "\n"
657
".globl " SYMBOL_STRING(ctiTrampoline) "\n"
658
".ent " SYMBOL_STRING(ctiTrampoline) "\n"
659
SYMBOL_STRING(ctiTrampoline) ":" "\n"
660
    "addiu $29,$29,-72" "\n"
661
    "sw    $31,44($29)" "\n"
662
    "sw    $18,40($29)" "\n"
663
    "sw    $17,36($29)" "\n"
664
    "sw    $16,32($29)" "\n"
665
#if WTF_MIPS_PIC
666
    "sw    $28,28($29)" "\n"
667
#endif
668
    "move  $16,$6       # set callFrameRegister" "\n"
669
    "li    $17,512      # set timeoutCheckRegister" "\n"
670
    "move  $25,$4       # move executableAddress to t9" "\n"
671
    "sw    $5,52($29)   # store registerFile to current stack" "\n"
672
    "sw    $6,56($29)   # store callFrame to curent stack" "\n"
673
    "sw    $7,60($29)   # store exception to current stack" "\n"
674
    "lw    $8,88($29)   # load enableProfilerReference from previous stack" "\n"
675
    "lw    $9,92($29)   # load globalData from previous stack" "\n"
676
    "sw    $8,64($29)   # store enableProfilerReference to current stack" "\n"
677
    "jalr  $25" "\n"
678
    "sw    $9,68($29)   # store globalData to current stack" "\n"
679
    "lw    $16,32($29)" "\n"
680
    "lw    $17,36($29)" "\n"
681
    "lw    $18,40($29)" "\n"
682
    "lw    $31,44($29)" "\n"
683
    "jr    $31" "\n"
684
    "addiu $29,$29,72" "\n"
685
".set reorder" "\n"
686
".set macro" "\n"
687
".end " SYMBOL_STRING(ctiTrampoline) "\n"
688
);
689
690
asm volatile (
691
".text" "\n"
692
".align 2" "\n"
693
".set noreorder" "\n"
694
".set nomacro" "\n"
695
".set nomips16" "\n"
696
".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
697
".ent " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
698
SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
699
#if WTF_MIPS_PIC
700
    "lw    $28,28($29)" "\n"
701
".set macro" "\n"
702
    "la    $25," SYMBOL_STRING(cti_vm_throw) "\n"
703
".set nomacro" "\n"
704
    "bal " SYMBOL_STRING(cti_vm_throw) "\n"
705
    "move  $4,$29" "\n"
706
#else
707
    "jal " SYMBOL_STRING(cti_vm_throw) "\n"
708
    "move  $4,$29" "\n"
709
#endif
710
    "lw    $16,32($29)" "\n"
711
    "lw    $17,36($29)" "\n"
712
    "lw    $18,40($29)" "\n"
713
    "lw    $31,44($29)" "\n"
714
    "jr    $31" "\n"
715
    "addiu $29,$29,72" "\n"
716
".set reorder" "\n"
717
".set macro" "\n"
718
".end " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
719
);
720
721
asm volatile (
722
".text" "\n"
723
".align 2" "\n"
724
".set noreorder" "\n"
725
".set nomacro" "\n"
726
".set nomips16" "\n"
727
".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
728
".ent " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
729
SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
730
    "lw    $16,32($29)" "\n"
731
    "lw    $17,36($29)" "\n"
732
    "lw    $18,40($29)" "\n"
733
    "lw    $31,44($29)" "\n"
734
    "jr    $31" "\n"
735
    "addiu $29,$29,72" "\n"
736
".set reorder" "\n"
737
".set macro" "\n"
738
".end " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
739
);
740
645
#elif COMPILER(RVCT) && CPU(ARM_TRADITIONAL)
741
#elif COMPILER(RVCT) && CPU(ARM_TRADITIONAL)
646
742
647
__asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, JSValue*, Profiler**, JSGlobalData*)
743
__asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, JSValue*, Profiler**, JSGlobalData*)
Lines 777-782 JITThunks::JITThunks(JSGlobalData* globa JavaScriptCore/jit/JITStubs.cpp_sec2
777
873
778
    ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == 0x1C);
874
    ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == 0x1C);
779
#endif
875
#endif
876
877
#if CPU(MIPS)
878
    ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedGP) == 28);
879
    ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS0) == 32);
880
    ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS1) == 36);
881
    ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS2) == 40);
882
    ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedReturnAddress) == 44);
883
    ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == 48);
884
    ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, registerFile) == 52);
885
    ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, callFrame) == 56);
886
    ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, exception) == 60);
887
    ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == 64);
888
    ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, globalData) == 68);
889
890
#endif
780
}
891
}
781
892
782
#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
893
#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
Lines 1034-1039 static NEVER_INLINE void throwStackOverf JavaScriptCore/jit/JITStubs.cpp_sec3
1034
        ); \
1145
        ); \
1035
    rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) \
1146
    rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) \
1036
1147
1148
#elif CPU(MIPS)
1149
#if WTF_MIPS_PIC
1150
#define DEFINE_STUB_FUNCTION(rtype, op) \
1151
    extern "C" { \
1152
        rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
1153
    }; \
1154
    asm volatile ( \
1155
        ".text" "\n" \
1156
        ".align 2" "\n" \
1157
        ".set noreorder" "\n" \
1158
        ".set nomacro" "\n" \
1159
        ".set nomips16" "\n" \
1160
        ".globl " SYMBOL_STRING(cti_##op) "\n" \
1161
        ".ent " SYMBOL_STRING(cti_##op) "\n" \
1162
        SYMBOL_STRING(cti_##op) ":" "\n" \
1163
        "lw    $28,28($29)" "\n" \
1164
        "sw    $31,48($29)" "\n" \
1165
        ".set macro" "\n" \
1166
        "la    $25," SYMBOL_STRING(JITStubThunked_##op) "\n" \
1167
        ".set nomacro" "\n" \
1168
        "bal " SYMBOL_STRING(JITStubThunked_##op) "\n" \
1169
        "nop" "\n" \
1170
        "lw    $31,48($29)" "\n" \
1171
        "jr    $31" "\n" \
1172
        "nop" "\n" \
1173
        ".set reorder" "\n" \
1174
        ".set macro" "\n" \
1175
        ".end " SYMBOL_STRING(cti_##op) "\n" \
1176
        ); \
1177
    rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
1178
1179
#else // WTF_MIPS_PIC
1180
#define DEFINE_STUB_FUNCTION(rtype, op) \
1181
    extern "C" { \
1182
        rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
1183
    }; \
1184
    asm volatile ( \
1185
        ".text" "\n" \
1186
        ".align 2" "\n" \
1187
        ".set noreorder" "\n" \
1188
        ".set nomacro" "\n" \
1189
        ".set nomips16" "\n" \
1190
        ".globl " SYMBOL_STRING(cti_##op) "\n" \
1191
        ".ent " SYMBOL_STRING(cti_##op) "\n" \
1192
        SYMBOL_STRING(cti_##op) ":" "\n" \
1193
        "sw    $31,48($29)" "\n" \
1194
        "jal " SYMBOL_STRING(JITStubThunked_##op) "\n" \
1195
        "nop" "\n" \
1196
        "lw    $31,48($29)" "\n" \
1197
        "jr    $31" "\n" \
1198
        "nop" "\n" \
1199
        ".set reorder" "\n" \
1200
        ".set macro" "\n" \
1201
        ".end " SYMBOL_STRING(cti_##op) "\n" \
1202
        ); \
1203
    rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
1204
1205
#endif
1206
1037
#elif CPU(ARM_TRADITIONAL) && COMPILER(GCC)
1207
#elif CPU(ARM_TRADITIONAL) && COMPILER(GCC)
1038
1208
1039
#if USE(JSVALUE32_64)
1209
#if USE(JSVALUE32_64)
- JavaScriptCore/jit/JITStubs.h +24 lines
Lines 191-196 namespace JSC { JavaScriptCore/jit/JITStubs.h_sec1
191
        // When JIT code makes a call, it pushes its return address just below the rest of the stack.
191
        // When JIT code makes a call, it pushes its return address just below the rest of the stack.
192
        ReturnAddressPtr* returnAddressSlot() { return &thunkReturnAddress; }
192
        ReturnAddressPtr* returnAddressSlot() { return &thunkReturnAddress; }
193
    };
193
    };
194
#elif CPU(MIPS)
195
    struct JITStackFrame {
196
        void* reserved; // Unused
197
        JITStubArg args[6];
198
199
        void* preservedGP; // store GP when using PIC code
200
        void* preservedS0;
201
        void* preservedS1;
202
        void* preservedS2;
203
        void* preservedReturnAddress;
204
205
        ReturnAddressPtr thunkReturnAddress;
206
207
        // These arguments passed in a1..a3 (a0 contained the entry code pointed, which is not preserved)
208
        RegisterFile* registerFile;
209
        CallFrame* callFrame;
210
        JSValue* exception;
211
212
        // These arguments passed on the stack.
213
        Profiler** enabledProfilerReference;
214
        JSGlobalData* globalData;
215
216
        ReturnAddressPtr* returnAddressSlot() { return &thunkReturnAddress; }
217
    };
194
#else
218
#else
195
#error "JITStackFrame not defined for this platform."
219
#error "JITStackFrame not defined for this platform."
196
#endif
220
#endif
- JavaScriptCore/wtf/Platform.h -2 / +22 lines
Lines 104-109 JavaScriptCore/wtf/Platform.h_sec1
104
#define WTF_CPU_IA64 1
104
#define WTF_CPU_IA64 1
105
#endif
105
#endif
106
106
107
/* CPU(MIPS) - MIPS 32-bit */
108
/* Note: Only O32 ABI is tested, so we enable it for O32 ABI for now.  */
109
#if   (defined(mips) || defined(__mips__)) && defined(_ABIO32)
110
#define WTF_CPU_MIPS 1
111
#if defined(__MIPSEB__)
112
#define WTF_CPU_BIG_ENDIAN 1
113
#endif
114
#define WTF_MIPS_PIC (defined __PIC__)
115
#define WTF_MIPS_ARCH __mips
116
#define WTF_MIPS_ISA(v) (defined WTF_MIPS_ARCH && WTF_MIPS_ARCH == v)
117
#define WTF_MIPS_ISA_AT_LEAST(v) (defined WTF_MIPS_ARCH && WTF_MIPS_ARCH >= v)
118
#define WTF_MIPS_ARCH_REV __mips_isa_rev
119
#define WTF_MIPS_ISA_REV(v) (defined WTF_MIPS_ARCH_REV && WTF_MIPS_ARCH_REV == v)
120
#define WTF_MIPS_DOUBLE_FLOAT (defined __mips_hard_float && !defined __mips_single_float)
121
#endif /* MIPS */
122
107
/* CPU(PPC) - PowerPC 32-bit */
123
/* CPU(PPC) - PowerPC 32-bit */
108
#if   defined(__ppc__)     \
124
#if   defined(__ppc__)     \
109
    || defined(__PPC__)     \
125
    || defined(__PPC__)     \
Lines 830-836 JavaScriptCore/wtf/Platform.h_sec2
830
#if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64)
846
#if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64)
831
#if (CPU(X86_64) && (OS(UNIX) || OS(WINDOWS))) || CPU(IA64) || CPU(ALPHA)
847
#if (CPU(X86_64) && (OS(UNIX) || OS(WINDOWS))) || CPU(IA64) || CPU(ALPHA)
832
#define WTF_USE_JSVALUE64 1
848
#define WTF_USE_JSVALUE64 1
833
#elif CPU(ARM) || CPU(PPC64)
849
#elif CPU(ARM) || CPU(PPC64) || CPU(MIPS)
834
#define WTF_USE_JSVALUE32 1
850
#define WTF_USE_JSVALUE32 1
835
#elif OS(WINDOWS) && COMPILER(MINGW)
851
#elif OS(WINDOWS) && COMPILER(MINGW)
836
/* Using JSVALUE32_64 causes padding/alignement issues for JITStubArg
852
/* Using JSVALUE32_64 causes padding/alignement issues for JITStubArg
Lines 883-888 on MinGW. See https://bugs.webkit.org/sh JavaScriptCore/wtf/Platform.h_sec3
883
    #define ENABLE_JIT 1
899
    #define ENABLE_JIT 1
884
#elif CPU(ARM_TRADITIONAL) && OS(LINUX)
900
#elif CPU(ARM_TRADITIONAL) && OS(LINUX)
885
    #define ENABLE_JIT 1
901
    #define ENABLE_JIT 1
902
#elif CPU(MIPS) && OS(LINUX)
903
    #define ENABLE_JIT 1
904
    #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 0
886
#endif
905
#endif
887
#endif /* PLATFORM(QT) */
906
#endif /* PLATFORM(QT) */
888
907
Lines 950-956 on MinGW. See https://bugs.webkit.org/sh JavaScriptCore/wtf/Platform.h_sec4
950
    || (CPU(X86) && OS(WINDOWS) && COMPILER(MSVC)) \
969
    || (CPU(X86) && OS(WINDOWS) && COMPILER(MSVC)) \
951
    || (CPU(X86) && OS(LINUX) && GCC_VERSION >= 40100) \
970
    || (CPU(X86) && OS(LINUX) && GCC_VERSION >= 40100) \
952
    || (CPU(X86_64) && OS(LINUX) && GCC_VERSION >= 40100) \
971
    || (CPU(X86_64) && OS(LINUX) && GCC_VERSION >= 40100) \
953
    || (CPU(ARM_TRADITIONAL) && OS(LINUX))
972
    || (CPU(ARM_TRADITIONAL) && OS(LINUX)) \
973
    || (CPU(MIPS) && OS(LINUX))
954
#define ENABLE_YARR 1
974
#define ENABLE_YARR 1
955
#define ENABLE_YARR_JIT 1
975
#define ENABLE_YARR_JIT 1
956
#endif
976
#endif
- JavaScriptCore/yarr/RegexJIT.cpp +14 lines
Lines 54-59 class RegexGenerator : private MacroAsse JavaScriptCore/yarr/RegexJIT.cpp_sec1
54
    static const RegisterID regT1 = ARMRegisters::r6;
54
    static const RegisterID regT1 = ARMRegisters::r6;
55
55
56
    static const RegisterID returnRegister = ARMRegisters::r0;
56
    static const RegisterID returnRegister = ARMRegisters::r0;
57
#elif CPU(MIPS)
58
    static const RegisterID input = MIPSRegisters::a0;
59
    static const RegisterID index = MIPSRegisters::a1;
60
    static const RegisterID length = MIPSRegisters::a2;
61
    static const RegisterID output = MIPSRegisters::a3;
62
63
    static const RegisterID regT0 = MIPSRegisters::t4;
64
    static const RegisterID regT1 = MIPSRegisters::t5;
65
66
    static const RegisterID returnRegister = MIPSRegisters::v0;
57
#elif CPU(X86)
67
#elif CPU(X86)
58
    static const RegisterID input = X86Registers::eax;
68
    static const RegisterID input = X86Registers::eax;
59
    static const RegisterID index = X86Registers::edx;
69
    static const RegisterID index = X86Registers::edx;
Lines 1313-1318 class RegexGenerator : private MacroAsse JavaScriptCore/yarr/RegexJIT.cpp_sec2
1313
        push(ARMRegisters::r5);
1323
        push(ARMRegisters::r5);
1314
        push(ARMRegisters::r6);
1324
        push(ARMRegisters::r6);
1315
        move(ARMRegisters::r3, output);
1325
        move(ARMRegisters::r3, output);
1326
#elif CPU(MIPS)
1327
        // Do nothing.
1316
#endif
1328
#endif
1317
    }
1329
    }
1318
1330
Lines 1330-1335 class RegexGenerator : private MacroAsse JavaScriptCore/yarr/RegexJIT.cpp_sec3
1330
        pop(ARMRegisters::r6);
1342
        pop(ARMRegisters::r6);
1331
        pop(ARMRegisters::r5);
1343
        pop(ARMRegisters::r5);
1332
        pop(ARMRegisters::r4);
1344
        pop(ARMRegisters::r4);
1345
#elif CPU(MIPS)
1346
        // Do nothing
1333
#endif
1347
#endif
1334
        ret();
1348
        ret();
1335
    }
1349
    }

Return to Bug 30144