source: webkit/trunk/JavaScriptCore/assembler/MacroAssembler.h@ 38975

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

2008-12-03 Sam Weinig <[email protected]>

Reviewed by Geoffrey Garen.

Remove shared AssemblerBuffer 1MB buffer and instead give AssemblerBuffer
an 256 byte inline capacity.

1% progression on Sunspider.

  • assembler/AssemblerBuffer.h: (JSC::AssemblerBuffer::AssemblerBuffer): (JSC::AssemblerBuffer::~AssemblerBuffer): (JSC::AssemblerBuffer::grow):
  • assembler/MacroAssembler.h: (JSC::MacroAssembler::MacroAssembler):
  • assembler/X86Assembler.h: (JSC::X86Assembler::X86Assembler):
  • interpreter/Interpreter.cpp: (JSC::Interpreter::Interpreter):
  • interpreter/Interpreter.h:
  • jit/JIT.cpp: (JSC::JIT::JIT):
  • parser/Nodes.cpp: (JSC::RegExpNode::emitBytecode):
  • runtime/RegExp.cpp: (JSC::RegExp::RegExp): (JSC::RegExp::create):
  • runtime/RegExp.h:
  • runtime/RegExpConstructor.cpp: (JSC::constructRegExp):
  • runtime/RegExpPrototype.cpp: (JSC::regExpProtoFuncCompile):
  • runtime/StringPrototype.cpp: (JSC::stringProtoFuncMatch): (JSC::stringProtoFuncSearch):
  • wrec/WREC.cpp: (JSC::WREC::Generator::compileRegExp):
  • wrec/WRECGenerator.h: (JSC::WREC::Generator::Generator):
  • wrec/WRECParser.h: (JSC::WREC::Parser::Parser):
File size: 16.9 KB
Line 
1/*
2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef MacroAssembler_h
27#define MacroAssembler_h
28
29#include <wtf/Platform.h>
30
31#if ENABLE(ASSEMBLER)
32
33#include "X86Assembler.h"
34
35namespace JSC {
36
37class MacroAssembler {
38protected:
39 X86Assembler m_assembler;
40
41public:
42 typedef X86::RegisterID RegisterID;
43
44 // Note: do not rely on values in this enum, these will change (to 0..3).
45 enum Scale {
46 TimesOne = 1,
47 TimesTwo = 2,
48 TimesFour = 4,
49 TimesEight = 8
50 };
51
52 MacroAssembler()
53 {
54 }
55
56 void* copyCode()
57 {
58 return m_assembler.executableCopy();
59 }
60
61 // Address:
62 //
63 // Describes a simple base-offset address.
64 struct Address {
65 explicit Address(RegisterID base, int32_t offset = 0)
66 : base(base)
67 , offset(offset)
68 {
69 }
70
71 RegisterID base;
72 int32_t offset;
73 };
74
75 // ImplicitAddress:
76 //
77 // This class is used for explicit 'load' and 'store' operations
78 // (as opposed to situations in which a memory operand is provided
79 // to a generic operation, such as an integer arithmetic instruction).
80 //
81 // In the case of a load (or store) operation we want to permit
82 // addresses to be implicitly constructed, e.g. the two calls:
83 //
84 // load32(Address(addrReg), destReg);
85 // load32(addrReg, destReg);
86 //
87 // Are equivalent, and the explicit wrapping of the Address in the former
88 // is unnecessary.
89 struct ImplicitAddress {
90 ImplicitAddress(RegisterID base)
91 : base(base)
92 , offset(0)
93 {
94 }
95
96 ImplicitAddress(Address address)
97 : base(address.base)
98 , offset(address.offset)
99 {
100 }
101
102 RegisterID base;
103 int32_t offset;
104 };
105
106 // BaseIndex:
107 //
108 // Describes a complex addressing mode.
109 struct BaseIndex {
110 BaseIndex(RegisterID base, RegisterID index, int32_t offset = 0)
111 : base(base)
112 , index(index)
113 , scale(TimesOne)
114 , offset(offset)
115 {
116 }
117
118 BaseIndex(RegisterID base, RegisterID index, Scale scale, int32_t offset = 0)
119 : base(base)
120 , index(index)
121 , scale(scale)
122 , offset(offset)
123 {
124 }
125
126 RegisterID base;
127 RegisterID index;
128 Scale scale;
129 int32_t offset;
130 };
131
132 class Jump;
133
134 // Label:
135 //
136 // A Label records a point in the generated instruction stream, typically such that
137 // it may be used as a destination for a jump.
138 class Label {
139 friend class Jump;
140 friend class MacroAssembler;
141
142 public:
143 Label(MacroAssembler* masm)
144 : m_label(masm->m_assembler.label())
145 {
146 }
147
148 private:
149 X86Assembler::JmpDst m_label;
150 };
151
152 // Jump:
153 //
154 // A jump object is a reference to a jump instruction that has been planted
155 // into the code buffer - it is typically used to link the jump, setting the
156 // relative offset such that when executed it will jump to the desired
157 // destination.
158 //
159 // Jump objects retain a pointer to the assembler for syntactic purposes -
160 // to allow the jump object to be able to link itself, e.g.:
161 //
162 // Jump forwardsBranch = jne32(Imm32(0), reg1);
163 // // ...
164 // forwardsBranch.link();
165 //
166 // Jumps may also be linked to a Label.
167 class Jump {
168 public:
169 Jump()
170 : m_assembler(0)
171 {
172 }
173
174 Jump(X86Assembler& assembler, X86Assembler::JmpSrc jmp)
175 : m_assembler(&assembler)
176 , m_jmp(jmp)
177 {
178 }
179
180 void link()
181 {
182 ASSERT(m_assembler);
183 m_assembler->link(m_jmp, m_assembler->label());
184 }
185
186 void linkTo(Label label)
187 {
188 ASSERT(m_assembler);
189 m_assembler->link(m_jmp, label.m_label);
190 }
191
192 private:
193 X86Assembler* m_assembler;
194 X86Assembler::JmpSrc m_jmp;
195 };
196
197 // JumpList:
198 //
199 // A JumpList is a set of Jump objects.
200 // All jumps in the set will be linked to the same destination.
201 class JumpList {
202 public:
203 void link()
204 {
205 size_t size = m_jumps.size();
206 for (size_t i = 0; i < size; ++i)
207 m_jumps[i].link();
208 m_jumps.clear();
209 }
210
211 void linkTo(Label label)
212 {
213 size_t size = m_jumps.size();
214 for (size_t i = 0; i < size; ++i)
215 m_jumps[i].linkTo(label);
216 m_jumps.clear();
217 }
218
219 void append(Jump jump)
220 {
221 m_jumps.append(jump);
222 }
223
224 void append(JumpList& other)
225 {
226 m_jumps.append(other.m_jumps.begin(), other.m_jumps.size());
227 }
228
229 private:
230 Vector<Jump> m_jumps;
231 };
232
233 // Imm32:
234 //
235 // A 32bit immediate operand to an instruction - this is wrapped in a
236 // class requiring explicit construction in order to prevent RegisterIDs
237 // (which are implemented as an enum) from accidentally being passed as
238 // immediate values.
239 struct Imm32 {
240 explicit Imm32(int32_t value)
241 : m_value(value)
242 {
243 }
244
245 int32_t m_value;
246 };
247
248
249 // Integer arithmetic operations:
250 //
251 // Operations are typically two operand - operation(source, srcDst)
252 // For many operations the source may be an Imm32, the srcDst operand
253 // may often be a memory location (explictly described using an Address
254 // object).
255
256 void addPtr(Imm32 imm, RegisterID dest)
257 {
258#if PLATFORM(X86_64)
259 if (CAN_SIGN_EXTEND_8_32(imm.m_value))
260 m_assembler.addq_i8r(imm.m_value, dest);
261 else
262 m_assembler.addq_i32r(imm.m_value, dest);
263#else
264 if (CAN_SIGN_EXTEND_8_32(imm.m_value))
265 m_assembler.addl_i8r(imm.m_value, dest);
266 else
267 m_assembler.addl_i32r(imm.m_value, dest);
268#endif
269 }
270
271 void add32(Imm32 imm, RegisterID dest)
272 {
273 if (CAN_SIGN_EXTEND_8_32(imm.m_value))
274 m_assembler.addl_i8r(imm.m_value, dest);
275 else
276 m_assembler.addl_i32r(imm.m_value, dest);
277 }
278
279 void add32(Address src, RegisterID dest)
280 {
281 m_assembler.addl_mr(src.offset, src.base, dest);
282 }
283
284 void or32(Imm32 imm, RegisterID dest)
285 {
286 if (CAN_SIGN_EXTEND_8_32(imm.m_value))
287 m_assembler.orl_i8r(imm.m_value, dest);
288 else
289 m_assembler.orl_i32r(imm.m_value, dest);
290 }
291
292 void sub32(Imm32 imm, RegisterID dest)
293 {
294 if (CAN_SIGN_EXTEND_8_32(imm.m_value))
295 m_assembler.subl_i8r(imm.m_value, dest);
296 else
297 m_assembler.subl_i32r(imm.m_value, dest);
298 }
299
300 void sub32(Address src, RegisterID dest)
301 {
302 m_assembler.subl_mr(src.offset, src.base, dest);
303 }
304
305
306 // Memory access operations:
307 //
308 // Loads are of the form load(address, destination) and stores of the form
309 // store(source, address). The source for a store may be an Imm32. Address
310 // operand objects to loads and store will be implicitly constructed if a
311 // register is passed.
312
313 void loadPtr(ImplicitAddress address, RegisterID dest)
314 {
315#if PLATFORM(X86_64)
316 if (address.offset)
317 m_assembler.movq_mr(address.offset, address.base, dest);
318 else
319 m_assembler.movq_mr(address.base, dest);
320#else
321 if (address.offset)
322 m_assembler.movl_mr(address.offset, address.base, dest);
323 else
324 m_assembler.movl_mr(address.base, dest);
325#endif
326 }
327
328 void load32(ImplicitAddress address, RegisterID dest)
329 {
330 if (address.offset)
331 m_assembler.movl_mr(address.offset, address.base, dest);
332 else
333 m_assembler.movl_mr(address.base, dest);
334 }
335
336 void load16(BaseIndex address, RegisterID dest)
337 {
338 if (address.offset)
339 m_assembler.movzwl_mr(address.offset, address.base, address.index, address.scale, dest);
340 else
341 m_assembler.movzwl_mr(address.base, address.index, address.scale, dest);
342 }
343
344 void storePtr(RegisterID src, ImplicitAddress address)
345 {
346#if PLATFORM(X86_64)
347 if (address.offset)
348 m_assembler.movq_rm(src, address.offset, address.base);
349 else
350 m_assembler.movq_rm(src, address.base);
351#else
352 if (address.offset)
353 m_assembler.movl_rm(src, address.offset, address.base);
354 else
355 m_assembler.movl_rm(src, address.base);
356#endif
357 }
358
359 void store32(RegisterID src, ImplicitAddress address)
360 {
361 if (address.offset)
362 m_assembler.movl_rm(src, address.offset, address.base);
363 else
364 m_assembler.movl_rm(src, address.base);
365 }
366
367 void store32(Imm32 imm, ImplicitAddress address)
368 {
369 // FIXME: add a version that doesn't take an offset
370 m_assembler.movl_i32m(imm.m_value, address.offset, address.base);
371 }
372
373
374 // Stack manipulation operations:
375 //
376 // The ABI is assumed to provide a stack abstraction to memory,
377 // containing machine word sized units of data. Push and pop
378 // operations add and remove a single register sized unit of data
379 // to or from the stack. Peek and poke operations read or write
380 // values on the stack, without moving the current stack position.
381
382 void pop(RegisterID dest)
383 {
384#if PLATFORM(X86_64)
385 m_assembler.popq_r(dest);
386#else
387 m_assembler.popl_r(dest);
388#endif
389 }
390
391 void push(RegisterID src)
392 {
393#if PLATFORM(X86_64)
394 m_assembler.pushq_r(src);
395#else
396 m_assembler.pushl_r(src);
397#endif
398 }
399
400 void pop()
401 {
402 addPtr(Imm32(sizeof(void*)), X86::esp);
403 }
404
405 void peek(RegisterID dest, int index = 0)
406 {
407 loadPtr(Address(X86::esp, (index * sizeof(void *))), dest);
408 }
409
410 void poke(RegisterID src, int index = 0)
411 {
412 storePtr(src, Address(X86::esp, (index * sizeof(void *))));
413 }
414
415
416 // Register move operations:
417 //
418 // Move values in registers.
419
420 void move(Imm32 imm, RegisterID dest)
421 {
422 // Note: on 64-bit the Imm32 value is zero extended into the register, it
423 // may be useful to have a separate version that sign extends the value?
424 if (!imm.m_value)
425 m_assembler.xorl_rr(dest, dest);
426 else
427 m_assembler.movl_i32r(imm.m_value, dest);
428 }
429
430 void move(RegisterID src, RegisterID dest)
431 {
432 // Note: on 64-bit this is is a full register move; perhaps it would be
433 // useful to have separate move32 & movePtr, with move32 zero extending?
434#if PLATFORM(X86_64)
435 m_assembler.movq_rr(src, dest);
436#else
437 m_assembler.movl_rr(src, dest);
438#endif
439 }
440
441
442 // Forwards / external control flow operations:
443 //
444 // This set of jump and conditional branch operations return a Jump
445 // object which may linked at a later point, allow forwards jump,
446 // or jumps that will require external linkage (after the code has been
447 // relocated).
448 //
449 // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
450 // respecitvely, for unsigned comparisons the names b, a, be, and ae are
451 // used (representing the names 'below' and 'above').
452 //
453 // Operands to the comparision are provided in the expected order, e.g.
454 // jle32(reg1, Imm32(5)) will branch if the value held in reg1, when
455 // treated as a signed 32bit value, is less than or equal to 5.
456
457private:
458 void compareImm32ForBranch(RegisterID left, int32_t right)
459 {
460 if (CAN_SIGN_EXTEND_8_32(right))
461 m_assembler.cmpl_i8r(right, left);
462 else
463 m_assembler.cmpl_i32r(right, left);
464 }
465
466 void compareImm32ForBranchEquality(RegisterID reg, int32_t imm)
467 {
468 if (!imm)
469 m_assembler.testl_rr(reg, reg);
470 else if (CAN_SIGN_EXTEND_8_32(imm))
471 m_assembler.cmpl_i8r(imm, reg);
472 else
473 m_assembler.cmpl_i32r(imm, reg);
474 }
475
476public:
477 Jump jae32(RegisterID left, Imm32 right)
478 {
479 compareImm32ForBranch(left, right.m_value);
480 return Jump(m_assembler, m_assembler.jae());
481 }
482
483 Jump je32(RegisterID op1, RegisterID op2)
484 {
485 m_assembler.cmpl_rr(op1, op2);
486 return Jump(m_assembler, m_assembler.je());
487 }
488
489 Jump je32(RegisterID op1, Address op2)
490 {
491 m_assembler.cmpl_rm(op1, op2.offset, op2.base);
492 return Jump(m_assembler, m_assembler.je());
493 }
494
495 Jump je32(Imm32 imm, RegisterID reg)
496 {
497 compareImm32ForBranchEquality(reg, imm.m_value);
498 return Jump(m_assembler, m_assembler.je());
499 }
500
501 Jump je16(RegisterID op1, BaseIndex op2)
502 {
503 if (op2.offset)
504 m_assembler.cmpw_rm(op1, op2.base, op2.index, op2.scale);
505 else
506 m_assembler.cmpw_rm(op1, op2.offset, op2.base, op2.index, op2.scale);
507
508 return Jump(m_assembler, m_assembler.je());
509 }
510
511 Jump jg32(RegisterID left, RegisterID right)
512 {
513 m_assembler.cmpl_rr(right, left);
514 return Jump(m_assembler, m_assembler.jg());
515 }
516
517 Jump jge32(RegisterID left, Imm32 right)
518 {
519 compareImm32ForBranch(left, right.m_value);
520 return Jump(m_assembler, m_assembler.jge());
521 }
522
523 Jump jl32(RegisterID left, Imm32 right)
524 {
525 compareImm32ForBranch(left, right.m_value);
526 return Jump(m_assembler, m_assembler.jl());
527 }
528
529 Jump jle32(RegisterID left, RegisterID right)
530 {
531 m_assembler.cmpl_rr(right, left);
532 return Jump(m_assembler, m_assembler.jle());
533 }
534
535 Jump jle32(RegisterID left, Imm32 right)
536 {
537 compareImm32ForBranch(left, right.m_value);
538 return Jump(m_assembler, m_assembler.jle());
539 }
540
541 Jump jne32(RegisterID op1, RegisterID op2)
542 {
543 m_assembler.cmpl_rr(op1, op2);
544 return Jump(m_assembler, m_assembler.jne());
545 }
546
547 Jump jne32(Imm32 imm, RegisterID reg)
548 {
549 compareImm32ForBranchEquality(reg, imm.m_value);
550 return Jump(m_assembler, m_assembler.jne());
551 }
552
553 Jump jump()
554 {
555 return Jump(m_assembler, m_assembler.jmp());
556 }
557
558
559 // Backwards, local control flow operations:
560 //
561 // These operations provide a shorter notation for local
562 // backwards branches, which may be both more convenient
563 // for the user, and for the programmer, and for the
564 // assembler (allowing shorter values to be used in
565 // relative offsets).
566 //
567 // The code sequence:
568 //
569 // Label topOfLoop(this);
570 // // ...
571 // jne32(reg1, reg2, topOfLoop);
572 //
573 // Is equivalent to the longer, potentially less efficient form:
574 //
575 // Label topOfLoop(this);
576 // // ...
577 // jne32(reg1, reg2).linkTo(topOfLoop);
578
579 void je32(Imm32 imm, RegisterID op2, Label target)
580 {
581 je32(imm, op2).linkTo(target);
582 }
583
584 void je16(RegisterID op1, BaseIndex op2, Label target)
585 {
586 je16(op1, op2).linkTo(target);
587 }
588
589 void jl32(RegisterID left, Imm32 right, Label target)
590 {
591 jl32(left, right).linkTo(target);
592 }
593
594 void jle32(RegisterID left, RegisterID right, Label target)
595 {
596 jle32(left, right).linkTo(target);
597 }
598
599 void jne32(RegisterID op1, RegisterID op2, Label target)
600 {
601 jne32(op1, op2).linkTo(target);
602 }
603
604 void jne32(Imm32 imm, RegisterID op2, Label target)
605 {
606 jne32(imm, op2).linkTo(target);
607 }
608
609 void jump(Label target)
610 {
611 m_assembler.link(m_assembler.jmp(), target.m_label);
612 }
613
614
615 // Miscellaneous operations:
616
617 void breakpoint()
618 {
619 m_assembler.int3();
620 }
621
622 void ret()
623 {
624 m_assembler.ret();
625 }
626};
627
628} // namespace JSC
629
630#endif // ENABLE(ASSEMBLER)
631
632#endif // MacroAssembler_h
Note: See TracBrowser for help on using the repository browser.