source: webkit/trunk/JavaScriptCore/assembler/MIPSAssembler.h@ 64608

Last change on this file since 64608 was 64608, checked in by [email protected], 15 years ago

Bug 43390 - Do not CRASH if we run out of room for jit code.

Reviewed by Oliver Hunt.

Change the ExecutableAllocator implementations not to crash, and to return 0 if memory cannot be allocated.
The assemblers should pass this through without trying to use it in executableCopy.
Change the LinkBuffer to handle this, and to provide an allocationSuccessful() method to test for this.

Change the JIT to throw an exception if allocation fails.
Make JIT optimizations fail gracefully if memory cannot be allocated (use non-optimized path).
Change YARR JIT to fallback to PCRE

  • assembler/ARMAssembler.cpp:

(JSC::ARMAssembler::executableCopy):

  • assembler/ARMv7Assembler.h:

(JSC::ARMv7Assembler::executableCopy):

  • assembler/LinkBuffer.h:

(JSC::LinkBuffer::allocationSuccessful):

  • assembler/MIPSAssembler.h:

(JSC::MIPSAssembler::executableCopy):

  • assembler/X86Assembler.h:

(JSC::X86Assembler::executableCopy):

  • bytecode/StructureStubInfo.h:

(JSC::StructureStubInfo::initGetByIdProto):
(JSC::StructureStubInfo::initGetByIdChain):
(JSC::StructureStubInfo::initGetByIdSelfList):
(JSC::StructureStubInfo::initGetByIdProtoList):
(JSC::StructureStubInfo::initPutByIdTransition):

  • jit/ExecutableAllocator.cpp:

(JSC::ExecutablePool::systemAlloc):

  • jit/ExecutableAllocatorFixedVMPool.cpp:

(JSC::FixedVMPoolAllocator::allocInternal):

  • jit/JIT.cpp:

(JSC::JIT::privateCompile):

  • jit/JIT.h:

(JSC::JIT::compileGetByIdProto):
(JSC::JIT::compileGetByIdSelfList):
(JSC::JIT::compileGetByIdProtoList):
(JSC::JIT::compileGetByIdChainList):
(JSC::JIT::compileGetByIdChain):
(JSC::JIT::compilePutByIdTransition):
(JSC::JIT::compilePatchGetArrayLength):

  • jit/JITOpcodes.cpp:

(JSC::JIT::privateCompileCTIMachineTrampolines):

  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::privateCompileCTIMachineTrampolines):
(JSC::JIT::privateCompileCTINativeCall):

  • jit/JITPropertyAccess.cpp:

(JSC::JIT::stringGetByValStubGenerator):
(JSC::JIT::privateCompilePutByIdTransition):
(JSC::JIT::privateCompilePatchGetArrayLength):
(JSC::JIT::privateCompileGetByIdProto):
(JSC::JIT::privateCompileGetByIdSelfList):
(JSC::JIT::privateCompileGetByIdProtoList):
(JSC::JIT::privateCompileGetByIdChainList):
(JSC::JIT::privateCompileGetByIdChain):

  • jit/JITPropertyAccess32_64.cpp:

(JSC::JIT::stringGetByValStubGenerator):
(JSC::JIT::privateCompilePutByIdTransition):
(JSC::JIT::privateCompilePatchGetArrayLength):
(JSC::JIT::privateCompileGetByIdProto):
(JSC::JIT::privateCompileGetByIdSelfList):
(JSC::JIT::privateCompileGetByIdProtoList):
(JSC::JIT::privateCompileGetByIdChainList):
(JSC::JIT::privateCompileGetByIdChain):

  • jit/JITStubs.cpp:

(JSC::JITThunks::tryCachePutByID):
(JSC::JITThunks::tryCacheGetByID):
(JSC::DEFINE_STUB_FUNCTION):
(JSC::setupPolymorphicProtoList):

  • jit/JITStubs.h:
  • jit/SpecializedThunkJIT.h:

(JSC::SpecializedThunkJIT::finalize):

  • runtime/ExceptionHelpers.cpp:

(JSC::createOutOfMemoryError):

  • runtime/ExceptionHelpers.h:
  • runtime/Executable.cpp:

(JSC::EvalExecutable::compileInternal):
(JSC::ProgramExecutable::compileInternal):
(JSC::FunctionExecutable::compileForCallInternal):
(JSC::FunctionExecutable::compileForConstructInternal):
(JSC::FunctionExecutable::reparseExceptionInfo):
(JSC::EvalExecutable::reparseExceptionInfo):

  • yarr/RegexJIT.cpp:

(JSC::Yarr::RegexGenerator::compile):

File size: 26.2 KB
Line 
1/*
2 * Copyright (C) 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2009 University of Szeged
4 * All rights reserved.
5 * Copyright (C) 2010 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#if ENABLE(ASSEMBLER) && CPU(MIPS)
33
34#include "AssemblerBuffer.h"
35#include <wtf/Assertions.h>
36#include <wtf/SegmentedVector.h>
37
38namespace JSC {
39
40typedef uint32_t MIPSWord;
41
42namespace MIPSRegisters {
43typedef enum {
44 r0 = 0,
45 r1,
46 r2,
47 r3,
48 r4,
49 r5,
50 r6,
51 r7,
52 r8,
53 r9,
54 r10,
55 r11,
56 r12,
57 r13,
58 r14,
59 r15,
60 r16,
61 r17,
62 r18,
63 r19,
64 r20,
65 r21,
66 r22,
67 r23,
68 r24,
69 r25,
70 r26,
71 r27,
72 r28,
73 r29,
74 r30,
75 r31,
76 zero = r0,
77 at = r1,
78 v0 = r2,
79 v1 = r3,
80 a0 = r4,
81 a1 = r5,
82 a2 = r6,
83 a3 = r7,
84 t0 = r8,
85 t1 = r9,
86 t2 = r10,
87 t3 = r11,
88 t4 = r12,
89 t5 = r13,
90 t6 = r14,
91 t7 = r15,
92 s0 = r16,
93 s1 = r17,
94 s2 = r18,
95 s3 = r19,
96 s4 = r20,
97 s5 = r21,
98 s6 = r22,
99 s7 = r23,
100 t8 = r24,
101 t9 = r25,
102 k0 = r26,
103 k1 = r27,
104 gp = r28,
105 sp = r29,
106 fp = r30,
107 ra = r31
108} RegisterID;
109
110typedef enum {
111 f0,
112 f1,
113 f2,
114 f3,
115 f4,
116 f5,
117 f6,
118 f7,
119 f8,
120 f9,
121 f10,
122 f11,
123 f12,
124 f13,
125 f14,
126 f15,
127 f16,
128 f17,
129 f18,
130 f19,
131 f20,
132 f21,
133 f22,
134 f23,
135 f24,
136 f25,
137 f26,
138 f27,
139 f28,
140 f29,
141 f30,
142 f31
143} FPRegisterID;
144
145} // namespace MIPSRegisters
146
147class MIPSAssembler {
148public:
149 typedef MIPSRegisters::RegisterID RegisterID;
150 typedef MIPSRegisters::FPRegisterID FPRegisterID;
151 typedef SegmentedVector<int, 64> Jumps;
152
153 MIPSAssembler()
154 {
155 }
156
157 // MIPS instruction opcode field position
158 enum {
159 OP_SH_RD = 11,
160 OP_SH_RT = 16,
161 OP_SH_RS = 21,
162 OP_SH_SHAMT = 6,
163 OP_SH_CODE = 16,
164 OP_SH_FD = 6,
165 OP_SH_FS = 11,
166 OP_SH_FT = 16
167 };
168
169 class JmpSrc {
170 friend class MIPSAssembler;
171 public:
172 JmpSrc()
173 : m_offset(-1)
174 {
175 }
176
177 private:
178 JmpSrc(int offset)
179 : m_offset(offset)
180 {
181 }
182
183 int m_offset;
184 };
185
186 class JmpDst {
187 friend class MIPSAssembler;
188 public:
189 JmpDst()
190 : m_offset(-1)
191 , m_used(false)
192 {
193 }
194
195 bool isUsed() const { return m_used; }
196 void used() { m_used = true; }
197 private:
198 JmpDst(int offset)
199 : m_offset(offset)
200 , m_used(false)
201 {
202 ASSERT(m_offset == offset);
203 }
204
205 int m_offset : 31;
206 int m_used : 1;
207 };
208
209 void emitInst(MIPSWord op)
210 {
211 void* oldBase = m_buffer.data();
212
213 m_buffer.putInt(op);
214
215 void* newBase = m_buffer.data();
216 if (oldBase != newBase)
217 relocateJumps(oldBase, newBase);
218 }
219
220 void nop()
221 {
222 emitInst(0x00000000);
223 }
224
225 /* Need to insert one load data delay nop for mips1. */
226 void loadDelayNop()
227 {
228#if WTF_MIPS_ISA(1)
229 nop();
230#endif
231 }
232
233 /* Need to insert one coprocessor access delay nop for mips1. */
234 void copDelayNop()
235 {
236#if WTF_MIPS_ISA(1)
237 nop();
238#endif
239 }
240
241 void move(RegisterID rd, RegisterID rs)
242 {
243 /* addu */
244 emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS));
245 }
246
247 /* Set an immediate value to a register. This may generate 1 or 2
248 instructions. */
249 void li(RegisterID dest, int imm)
250 {
251 if (imm >= -32768 && imm <= 32767)
252 addiu(dest, MIPSRegisters::zero, imm);
253 else if (imm >= 0 && imm < 65536)
254 ori(dest, MIPSRegisters::zero, imm);
255 else {
256 lui(dest, imm >> 16);
257 if (imm & 0xffff)
258 ori(dest, dest, imm);
259 }
260 }
261
262 void lui(RegisterID rt, int imm)
263 {
264 emitInst(0x3c000000 | (rt << OP_SH_RT) | (imm & 0xffff));
265 }
266
267 void addiu(RegisterID rt, RegisterID rs, int imm)
268 {
269 emitInst(0x24000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
270 | (imm & 0xffff));
271 }
272
273 void addu(RegisterID rd, RegisterID rs, RegisterID rt)
274 {
275 emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
276 | (rt << OP_SH_RT));
277 }
278
279 void subu(RegisterID rd, RegisterID rs, RegisterID rt)
280 {
281 emitInst(0x00000023 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
282 | (rt << OP_SH_RT));
283 }
284
285 void mult(RegisterID rs, RegisterID rt)
286 {
287 emitInst(0x00000018 | (rs << OP_SH_RS) | (rt << OP_SH_RT));
288 }
289
290 void mfhi(RegisterID rd)
291 {
292 emitInst(0x00000010 | (rd << OP_SH_RD));
293 }
294
295 void mflo(RegisterID rd)
296 {
297 emitInst(0x00000012 | (rd << OP_SH_RD));
298 }
299
300 void mul(RegisterID rd, RegisterID rs, RegisterID rt)
301 {
302#if WTF_MIPS_ISA_AT_LEAST(32)
303 emitInst(0x70000002 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
304 | (rt << OP_SH_RT));
305#else
306 mult(rs, rt);
307 mflo(rd);
308#endif
309 }
310
311 void andInsn(RegisterID rd, RegisterID rs, RegisterID rt)
312 {
313 emitInst(0x00000024 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
314 | (rt << OP_SH_RT));
315 }
316
317 void andi(RegisterID rt, RegisterID rs, int imm)
318 {
319 emitInst(0x30000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
320 | (imm & 0xffff));
321 }
322
323 void nor(RegisterID rd, RegisterID rs, RegisterID rt)
324 {
325 emitInst(0x00000027 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
326 | (rt << OP_SH_RT));
327 }
328
329 void orInsn(RegisterID rd, RegisterID rs, RegisterID rt)
330 {
331 emitInst(0x00000025 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
332 | (rt << OP_SH_RT));
333 }
334
335 void ori(RegisterID rt, RegisterID rs, int imm)
336 {
337 emitInst(0x34000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
338 | (imm & 0xffff));
339 }
340
341 void xorInsn(RegisterID rd, RegisterID rs, RegisterID rt)
342 {
343 emitInst(0x00000026 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
344 | (rt << OP_SH_RT));
345 }
346
347 void xori(RegisterID rt, RegisterID rs, int imm)
348 {
349 emitInst(0x38000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
350 | (imm & 0xffff));
351 }
352
353 void slt(RegisterID rd, RegisterID rs, RegisterID rt)
354 {
355 emitInst(0x0000002a | (rd << OP_SH_RD) | (rs << OP_SH_RS)
356 | (rt << OP_SH_RT));
357 }
358
359 void sltu(RegisterID rd, RegisterID rs, RegisterID rt)
360 {
361 emitInst(0x0000002b | (rd << OP_SH_RD) | (rs << OP_SH_RS)
362 | (rt << OP_SH_RT));
363 }
364
365 void sltiu(RegisterID rt, RegisterID rs, int imm)
366 {
367 emitInst(0x2c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
368 | (imm & 0xffff));
369 }
370
371 void sll(RegisterID rd, RegisterID rt, int shamt)
372 {
373 emitInst(0x00000000 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
374 | ((shamt & 0x1f) << OP_SH_SHAMT));
375 }
376
377 void sllv(RegisterID rd, RegisterID rt, int rs)
378 {
379 emitInst(0x00000004 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
380 | (rs << OP_SH_RS));
381 }
382
383 void sra(RegisterID rd, RegisterID rt, int shamt)
384 {
385 emitInst(0x00000003 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
386 | ((shamt & 0x1f) << OP_SH_SHAMT));
387 }
388
389 void srav(RegisterID rd, RegisterID rt, RegisterID rs)
390 {
391 emitInst(0x00000007 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
392 | (rs << OP_SH_RS));
393 }
394
395 void srl(RegisterID rd, RegisterID rt, int shamt)
396 {
397 emitInst(0x00000002 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
398 | ((shamt & 0x1f) << OP_SH_SHAMT));
399 }
400
401 void srlv(RegisterID rd, RegisterID rt, RegisterID rs)
402 {
403 emitInst(0x00000006 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
404 | (rs << OP_SH_RS));
405 }
406
407 void lbu(RegisterID rt, RegisterID rs, int offset)
408 {
409 emitInst(0x90000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
410 | (offset & 0xffff));
411 loadDelayNop();
412 }
413
414 void lw(RegisterID rt, RegisterID rs, int offset)
415 {
416 emitInst(0x8c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
417 | (offset & 0xffff));
418 loadDelayNop();
419 }
420
421 void lwl(RegisterID rt, RegisterID rs, int offset)
422 {
423 emitInst(0x88000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
424 | (offset & 0xffff));
425 loadDelayNop();
426 }
427
428 void lwr(RegisterID rt, RegisterID rs, int offset)
429 {
430 emitInst(0x98000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
431 | (offset & 0xffff));
432 loadDelayNop();
433 }
434
435 void lhu(RegisterID rt, RegisterID rs, int offset)
436 {
437 emitInst(0x94000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
438 | (offset & 0xffff));
439 loadDelayNop();
440 }
441
442 void sw(RegisterID rt, RegisterID rs, int offset)
443 {
444 emitInst(0xac000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
445 | (offset & 0xffff));
446 }
447
448 void jr(RegisterID rs)
449 {
450 emitInst(0x00000008 | (rs << OP_SH_RS));
451 }
452
453 void jalr(RegisterID rs)
454 {
455 emitInst(0x0000f809 | (rs << OP_SH_RS));
456 }
457
458 void jal()
459 {
460 emitInst(0x0c000000);
461 }
462
463 void bkpt()
464 {
465 int value = 512; /* BRK_BUG */
466 emitInst(0x0000000d | ((value & 0x3ff) << OP_SH_CODE));
467 }
468
469 void bgez(RegisterID rs, int imm)
470 {
471 emitInst(0x04010000 | (rs << OP_SH_RS) | (imm & 0xffff));
472 }
473
474 void bltz(RegisterID rs, int imm)
475 {
476 emitInst(0x04000000 | (rs << OP_SH_RS) | (imm & 0xffff));
477 }
478
479 void beq(RegisterID rs, RegisterID rt, int imm)
480 {
481 emitInst(0x10000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff));
482 }
483
484 void bne(RegisterID rs, RegisterID rt, int imm)
485 {
486 emitInst(0x14000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff));
487 }
488
489 void bc1t()
490 {
491 emitInst(0x45010000);
492 }
493
494 void bc1f()
495 {
496 emitInst(0x45000000);
497 }
498
499 JmpSrc newJmpSrc()
500 {
501 return JmpSrc(m_buffer.size());
502 }
503
504 void appendJump()
505 {
506 m_jumps.append(m_buffer.size());
507 }
508
509 void addd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
510 {
511 emitInst(0x46200000 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
512 | (ft << OP_SH_FT));
513 }
514
515 void subd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
516 {
517 emitInst(0x46200001 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
518 | (ft << OP_SH_FT));
519 }
520
521 void muld(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
522 {
523 emitInst(0x46200002 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
524 | (ft << OP_SH_FT));
525 }
526
527 void lwc1(FPRegisterID ft, RegisterID rs, int offset)
528 {
529 emitInst(0xc4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
530 | (offset & 0xffff));
531 copDelayNop();
532 }
533
534 void ldc1(FPRegisterID ft, RegisterID rs, int offset)
535 {
536 emitInst(0xd4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
537 | (offset & 0xffff));
538 }
539
540 void swc1(FPRegisterID ft, RegisterID rs, int offset)
541 {
542 emitInst(0xe4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
543 | (offset & 0xffff));
544 }
545
546 void sdc1(FPRegisterID ft, RegisterID rs, int offset)
547 {
548 emitInst(0xf4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
549 | (offset & 0xffff));
550 }
551
552 void mtc1(RegisterID rt, FPRegisterID fs)
553 {
554 emitInst(0x44800000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
555 copDelayNop();
556 }
557
558 void mfc1(RegisterID rt, FPRegisterID fs)
559 {
560 emitInst(0x44000000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
561 copDelayNop();
562 }
563
564 void sqrtd(FPRegisterID fd, FPRegisterID fs)
565 {
566 emitInst(0x46200004 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
567 }
568
569 void truncwd(FPRegisterID fd, FPRegisterID fs)
570 {
571 emitInst(0x4620000d | (fd << OP_SH_FD) | (fs << OP_SH_FS));
572 }
573
574 void cvtdw(FPRegisterID fd, FPRegisterID fs)
575 {
576 emitInst(0x46800021 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
577 }
578
579 void ceqd(FPRegisterID fs, FPRegisterID ft)
580 {
581 emitInst(0x46200032 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
582 copDelayNop();
583 }
584
585 void cngtd(FPRegisterID fs, FPRegisterID ft)
586 {
587 emitInst(0x4620003f | (fs << OP_SH_FS) | (ft << OP_SH_FT));
588 copDelayNop();
589 }
590
591 void cnged(FPRegisterID fs, FPRegisterID ft)
592 {
593 emitInst(0x4620003d | (fs << OP_SH_FS) | (ft << OP_SH_FT));
594 copDelayNop();
595 }
596
597 void cltd(FPRegisterID fs, FPRegisterID ft)
598 {
599 emitInst(0x4620003c | (fs << OP_SH_FS) | (ft << OP_SH_FT));
600 copDelayNop();
601 }
602
603 void cled(FPRegisterID fs, FPRegisterID ft)
604 {
605 emitInst(0x4620003e | (fs << OP_SH_FS) | (ft << OP_SH_FT));
606 copDelayNop();
607 }
608
609 void cueqd(FPRegisterID fs, FPRegisterID ft)
610 {
611 emitInst(0x46200033 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
612 copDelayNop();
613 }
614
615 void coled(FPRegisterID fs, FPRegisterID ft)
616 {
617 emitInst(0x46200036 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
618 copDelayNop();
619 }
620
621 void coltd(FPRegisterID fs, FPRegisterID ft)
622 {
623 emitInst(0x46200034 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
624 copDelayNop();
625 }
626
627 void culed(FPRegisterID fs, FPRegisterID ft)
628 {
629 emitInst(0x46200037 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
630 copDelayNop();
631 }
632
633 void cultd(FPRegisterID fs, FPRegisterID ft)
634 {
635 emitInst(0x46200035 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
636 copDelayNop();
637 }
638
639 // General helpers
640
641 JmpDst label()
642 {
643 return JmpDst(m_buffer.size());
644 }
645
646 JmpDst align(int alignment)
647 {
648 while (!m_buffer.isAligned(alignment))
649 bkpt();
650
651 return label();
652 }
653
654 static void* getRelocatedAddress(void* code, JmpSrc jump)
655 {
656 ASSERT(jump.m_offset != -1);
657 void* b = reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code)) + jump.m_offset);
658 return b;
659 }
660
661 static void* getRelocatedAddress(void* code, JmpDst label)
662 {
663 void* b = reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code)) + label.m_offset);
664 return b;
665 }
666
667 static int getDifferenceBetweenLabels(JmpDst from, JmpDst to)
668 {
669 return to.m_offset - from.m_offset;
670 }
671
672 static int getDifferenceBetweenLabels(JmpDst from, JmpSrc to)
673 {
674 return to.m_offset - from.m_offset;
675 }
676
677 static int getDifferenceBetweenLabels(JmpSrc from, JmpDst to)
678 {
679 return to.m_offset - from.m_offset;
680 }
681
682 // Assembler admin methods:
683
684 size_t size() const
685 {
686 return m_buffer.size();
687 }
688
689 void* executableCopy(ExecutablePool* allocator)
690 {
691 void *result = m_buffer.executableCopy(allocator);
692 if (result)
693 relocateJumps(m_buffer.data(), result);
694 return result;
695 }
696
697 static unsigned getCallReturnOffset(JmpSrc call)
698 {
699 // The return address is after a call and a delay slot instruction
700 return call.m_offset;
701 }
702
703 // Linking & patching:
704 //
705 // 'link' and 'patch' methods are for use on unprotected code - such as the code
706 // within the AssemblerBuffer, and code being patched by the patch buffer. Once
707 // code has been finalized it is (platform support permitting) within a non-
708 // writable region of memory; to modify the code in an execute-only execuable
709 // pool the 'repatch' and 'relink' methods should be used.
710
711 void linkJump(JmpSrc from, JmpDst to)
712 {
713 ASSERT(to.m_offset != -1);
714 ASSERT(from.m_offset != -1);
715 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + from.m_offset);
716 MIPSWord* toPos = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + to.m_offset);
717
718 ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
719 insn = insn - 6;
720 linkWithOffset(insn, toPos);
721 }
722
723 static void linkJump(void* code, JmpSrc from, void* to)
724 {
725 ASSERT(from.m_offset != -1);
726 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
727
728 ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
729 insn = insn - 6;
730 linkWithOffset(insn, to);
731 }
732
733 static void linkCall(void* code, JmpSrc from, void* to)
734 {
735 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
736 linkCallInternal(insn, to);
737 }
738
739 static void linkPointer(void* code, JmpDst from, void* to)
740 {
741 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
742 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
743 *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
744 insn++;
745 ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
746 *insn = (*insn & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
747 }
748
749 static void relinkJump(void* from, void* to)
750 {
751 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
752
753 ASSERT(!(*(insn - 1)) && !(*(insn - 5)));
754 insn = insn - 6;
755 int flushSize = linkWithOffset(insn, to);
756
757 ExecutableAllocator::cacheFlush(insn, flushSize);
758 }
759
760 static void relinkCall(void* from, void* to)
761 {
762 void* start;
763 int size = linkCallInternal(from, to);
764 if (size == sizeof(MIPSWord))
765 start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 2 * sizeof(MIPSWord));
766 else
767 start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 4 * sizeof(MIPSWord));
768
769 ExecutableAllocator::cacheFlush(start, size);
770 }
771
772 static void repatchInt32(void* from, int32_t to)
773 {
774 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
775 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
776 *insn = (*insn & 0xffff0000) | ((to >> 16) & 0xffff);
777 insn++;
778 ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
779 *insn = (*insn & 0xffff0000) | (to & 0xffff);
780 insn--;
781 ExecutableAllocator::cacheFlush(insn, 2 * sizeof(MIPSWord));
782 }
783
784 static void repatchPointer(void* from, void* to)
785 {
786 repatchInt32(from, reinterpret_cast<int32_t>(to));
787 }
788
789 static void repatchLoadPtrToLEA(void* from)
790 {
791 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
792 insn = insn + 3;
793 ASSERT((*insn & 0xfc000000) == 0x8c000000); // lw
794 /* lw -> addiu */
795 *insn = 0x24000000 | (*insn & 0x03ffffff);
796
797 ExecutableAllocator::cacheFlush(insn, sizeof(MIPSWord));
798 }
799
800private:
801
802 /* Update each jump in the buffer of newBase. */
803 void relocateJumps(void* oldBase, void* newBase)
804 {
805 // Check each jump
806 for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
807 int pos = *iter;
808 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(newBase) + pos);
809 insn = insn + 2;
810 // Need to make sure we have 5 valid instructions after pos
811 if ((unsigned int)pos >= m_buffer.size() - 5 * sizeof(MIPSWord))
812 continue;
813
814 if ((*insn & 0xfc000000) == 0x08000000) { // j
815 int offset = *insn & 0x03ffffff;
816 int oldInsnAddress = (int)insn - (int)newBase + (int)oldBase;
817 int topFourBits = (oldInsnAddress + 4) >> 28;
818 int oldTargetAddress = (topFourBits << 28) | (offset << 2);
819 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
820 int newInsnAddress = (int)insn;
821 if (((newInsnAddress + 4) >> 28) == (newTargetAddress >> 28))
822 *insn = 0x08000000 | ((newTargetAddress >> 2) & 0x3ffffff);
823 else {
824 /* lui */
825 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
826 /* ori */
827 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
828 /* jr */
829 *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
830 }
831 } else if ((*insn & 0xffe00000) == 0x3c000000) { // lui
832 int high = (*insn & 0xffff) << 16;
833 int low = *(insn + 1) & 0xffff;
834 int oldTargetAddress = high | low;
835 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
836 /* lui */
837 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
838 /* ori */
839 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
840 }
841 }
842 }
843
844 static int linkWithOffset(MIPSWord* insn, void* to)
845 {
846 ASSERT((*insn & 0xfc000000) == 0x10000000 // beq
847 || (*insn & 0xfc000000) == 0x14000000 // bne
848 || (*insn & 0xffff0000) == 0x45010000 // bc1t
849 || (*insn & 0xffff0000) == 0x45000000); // bc1f
850 intptr_t diff = (reinterpret_cast<intptr_t>(to)
851 - reinterpret_cast<intptr_t>(insn) - 4) >> 2;
852
853 if (diff < -32768 || diff > 32767 || *(insn + 2) != 0x10000003) {
854 /*
855 Convert the sequence:
856 beq $2, $3, target
857 nop
858 b 1f
859 nop
860 nop
861 nop
862 1:
863
864 to the new sequence if possible:
865 bne $2, $3, 1f
866 nop
867 j target
868 nop
869 nop
870 nop
871 1:
872
873 OR to the new sequence:
874 bne $2, $3, 1f
875 nop
876 lui $25, target >> 16
877 ori $25, $25, target & 0xffff
878 jr $25
879 nop
880 1:
881
882 Note: beq/bne/bc1t/bc1f are converted to bne/beq/bc1f/bc1t.
883 */
884
885 if (*(insn + 2) == 0x10000003) {
886 if ((*insn & 0xfc000000) == 0x10000000) // beq
887 *insn = (*insn & 0x03ff0000) | 0x14000005; // bne
888 else if ((*insn & 0xfc000000) == 0x14000000) // bne
889 *insn = (*insn & 0x03ff0000) | 0x10000005; // beq
890 else if ((*insn & 0xffff0000) == 0x45010000) // bc1t
891 *insn = 0x45000005; // bc1f
892 else if ((*insn & 0xffff0000) == 0x45000000) // bc1f
893 *insn = 0x45010005; // bc1t
894 else
895 ASSERT(0);
896 }
897
898 insn = insn + 2;
899 if ((reinterpret_cast<intptr_t>(insn) + 4) >> 28
900 == reinterpret_cast<intptr_t>(to) >> 28) {
901 *insn = 0x08000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
902 *(insn + 1) = 0;
903 return 4 * sizeof(MIPSWord);
904 }
905
906 intptr_t newTargetAddress = reinterpret_cast<intptr_t>(to);
907 /* lui */
908 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
909 /* ori */
910 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
911 /* jr */
912 *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
913 return 5 * sizeof(MIPSWord);
914 }
915
916 *insn = (*insn & 0xffff0000) | (diff & 0xffff);
917 return sizeof(MIPSWord);
918 }
919
920 static int linkCallInternal(void* from, void* to)
921 {
922 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
923 insn = insn - 4;
924
925 if ((*(insn + 2) & 0xfc000000) == 0x0c000000) { // jal
926 if ((reinterpret_cast<intptr_t>(from) - 4) >> 28
927 == reinterpret_cast<intptr_t>(to) >> 28) {
928 *(insn + 2) = 0x0c000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
929 return sizeof(MIPSWord);
930 }
931
932 /* lui $25, (to >> 16) & 0xffff */
933 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
934 /* ori $25, $25, to & 0xffff */
935 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (reinterpret_cast<intptr_t>(to) & 0xffff);
936 /* jalr $25 */
937 *(insn + 2) = 0x0000f809 | (MIPSRegisters::t9 << OP_SH_RS);
938 return 3 * sizeof(MIPSWord);
939 }
940
941 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
942 ASSERT((*(insn + 1) & 0xfc000000) == 0x34000000); // ori
943
944 /* lui */
945 *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
946 /* ori */
947 *(insn + 1) = (*(insn + 1) & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
948 return 2 * sizeof(MIPSWord);
949 }
950
951 AssemblerBuffer m_buffer;
952 Jumps m_jumps;
953};
954
955} // namespace JSC
956
957#endif // ENABLE(ASSEMBLER) && CPU(MIPS)
958
959#endif // MIPSAssembler_h
Note: See TracBrowser for help on using the repository browser.