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

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

2008-11-29 Gavin Barraclough <[email protected]>

Reviewed by Camron Zwarich.

Add the class MacroAssembler to provide some abstraction of code generation,
and change WREC to make use of this class, rather than directly accessing
the X86Assembler.

This patch also allows WREC to be compiled without the rest of the JIT enabled.

  • JavaScriptCore.xcodeproj/project.pbxproj:
  • assembler/MacroAssembler.h: Added. (JSC::MacroAssembler::): (JSC::MacroAssembler::MacroAssembler): (JSC::MacroAssembler::copyCode): (JSC::MacroAssembler::Address::Address): (JSC::MacroAssembler::ImplicitAddress::ImplicitAddress): (JSC::MacroAssembler::BaseIndex::BaseIndex): (JSC::MacroAssembler::Label::Label): (JSC::MacroAssembler::Jump::Jump): (JSC::MacroAssembler::Jump::link): (JSC::MacroAssembler::Jump::linkTo): (JSC::MacroAssembler::JumpList::link): (JSC::MacroAssembler::JumpList::linkTo): (JSC::MacroAssembler::JumpList::append): (JSC::MacroAssembler::Imm32::Imm32): (JSC::MacroAssembler::add32): (JSC::MacroAssembler::or32): (JSC::MacroAssembler::sub32): (JSC::MacroAssembler::loadPtr): (JSC::MacroAssembler::load32): (JSC::MacroAssembler::load16): (JSC::MacroAssembler::storePtr): (JSC::MacroAssembler::store32): (JSC::MacroAssembler::pop): (JSC::MacroAssembler::push): (JSC::MacroAssembler::peek): (JSC::MacroAssembler::poke): (JSC::MacroAssembler::move): (JSC::MacroAssembler::compareImm32ForBranch): (JSC::MacroAssembler::compareImm32ForBranchEquality): (JSC::MacroAssembler::jae32): (JSC::MacroAssembler::je32): (JSC::MacroAssembler::je16): (JSC::MacroAssembler::jg32): (JSC::MacroAssembler::jge32): (JSC::MacroAssembler::jl32): (JSC::MacroAssembler::jle32): (JSC::MacroAssembler::jne32): (JSC::MacroAssembler::jump): (JSC::MacroAssembler::breakpoint): (JSC::MacroAssembler::ret):
  • assembler/X86Assembler.h: (JSC::X86Assembler::cmpw_rm):
  • interpreter/Interpreter.cpp: (JSC::Interpreter::Interpreter):
  • interpreter/Interpreter.h: (JSC::Interpreter::assemblerBuffer):
  • runtime/RegExp.cpp: (JSC::RegExp::RegExp):
  • wrec/WREC.cpp: (JSC::WREC::Generator::compileRegExp):
  • wrec/WREC.h:
  • wrec/WRECFunctors.cpp: (JSC::WREC::GeneratePatternCharacterFunctor::generateAtom): (JSC::WREC::GenerateCharacterClassFunctor::generateAtom): (JSC::WREC::GenerateBackreferenceFunctor::generateAtom): (JSC::WREC::GenerateParenthesesNonGreedyFunctor::generateAtom):
  • wrec/WRECFunctors.h: (JSC::WREC::GenerateParenthesesNonGreedyFunctor::GenerateParenthesesNonGreedyFunctor):
  • wrec/WRECGenerator.cpp: (JSC::WREC::Generator::generateEnter): (JSC::WREC::Generator::generateReturnSuccess): (JSC::WREC::Generator::generateSaveIndex): (JSC::WREC::Generator::generateIncrementIndex): (JSC::WREC::Generator::generateLoadCharacter): (JSC::WREC::Generator::generateJumpIfEndOfInput): (JSC::WREC::Generator::generateJumpIfNotEndOfInput): (JSC::WREC::Generator::generateReturnFailure): (JSC::WREC::Generator::generateBacktrack1): (JSC::WREC::Generator::generateBacktrackBackreference): (JSC::WREC::Generator::generateBackreferenceQuantifier): (JSC::WREC::Generator::generateNonGreedyQuantifier): (JSC::WREC::Generator::generateGreedyQuantifier): (JSC::WREC::Generator::generatePatternCharacter): (JSC::WREC::Generator::generateCharacterClassInvertedRange): (JSC::WREC::Generator::generateCharacterClassInverted): (JSC::WREC::Generator::generateCharacterClass): (JSC::WREC::Generator::generateParentheses): (JSC::WREC::Generator::generateParenthesesNonGreedy): (JSC::WREC::Generator::generateParenthesesResetTrampoline): (JSC::WREC::Generator::generateAssertionBOL): (JSC::WREC::Generator::generateAssertionEOL): (JSC::WREC::Generator::generateAssertionWordBoundary): (JSC::WREC::Generator::generateBackreference): (JSC::WREC::Generator::terminateAlternative): (JSC::WREC::Generator::terminateDisjunction):
  • wrec/WRECGenerator.h: (JSC::WREC::Generator::Generator):
  • wrec/WRECParser.cpp: (JSC::WREC::Parser::parsePatternCharacterQualifier): (JSC::WREC::Parser::parseCharacterClassQuantifier): (JSC::WREC::Parser::parseBackreferenceQuantifier): (JSC::WREC::Parser::parseParentheses): (JSC::WREC::Parser::parseCharacterClass): (JSC::WREC::Parser::parseOctalEscape): (JSC::WREC::Parser::parseEscape): (JSC::WREC::Parser::parseTerm): (JSC::WREC::Parser::parseDisjunction):
  • wrec/WRECParser.h: (JSC::WREC::Parser::Parser): (JSC::WREC::Parser::parsePattern): (JSC::WREC::Parser::parseAlternative):
  • wtf/Platform.h:
File size: 15.4 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(AssemblerBuffer* assemblerBuffer)
53 : m_assembler(assemblerBuffer)
54 {
55 }
56
57 void* copyCode()
58 {
59 return m_assembler.executableCopy();
60 }
61
62 // Address:
63 //
64 // Describes a simple base-offset address.
65 struct Address {
66 explicit Address(RegisterID base, int32_t offset = 0)
67 : base(base)
68 , offset(offset)
69 {
70 }
71
72 RegisterID base;
73 int32_t offset;
74 };
75
76 // ImplicitAddress:
77 //
78 // This class is used for explicit 'load' and 'store' operations
79 // (as opposed to situations in which a memory operand is provided
80 // to a generic operation, such as an integer arithmetic instruction).
81 //
82 // In the case of a load (or store) operation we want to permit
83 // addresses to be implicitly constructed, e.g. the two calls:
84 //
85 // load32(Address(addrReg), destReg);
86 // load32(addrReg, destReg);
87 //
88 // Are equivalent, and the explicit wrapping of the Address in the former
89 // is unnecessary.
90 struct ImplicitAddress {
91 ImplicitAddress(RegisterID base)
92 : base(base)
93 , offset(0)
94 {
95 }
96
97 ImplicitAddress(Address address)
98 : base(address.base)
99 , offset(address.offset)
100 {
101 }
102
103 RegisterID base;
104 int32_t offset;
105 };
106
107 // BaseIndex:
108 //
109 // Describes a complex addressing mode.
110 struct BaseIndex {
111 BaseIndex(RegisterID base, RegisterID index, int32_t offset = 0)
112 : base(base)
113 , index(index)
114 , scale(TimesOne)
115 , offset(offset)
116 {
117 }
118
119 BaseIndex(RegisterID base, RegisterID index, Scale scale, int32_t offset = 0)
120 : base(base)
121 , index(index)
122 , scale(scale)
123 , offset(offset)
124 {
125 }
126
127 RegisterID base;
128 RegisterID index;
129 Scale scale;
130 int32_t offset;
131 };
132
133 // Label:
134 //
135 // A Label records a point in the generated instruction stream, typically such that
136 // it may be used as a destination for a jump.
137 class Label {
138 friend class MacroAssembler;
139
140 public:
141 Label(MacroAssembler* masm)
142 : m_label(masm->m_assembler.label())
143 {
144 }
145
146 private:
147 X86Assembler::JmpDst m_label;
148 };
149
150 // Jump:
151 //
152 // A jump object is a reference to a jump instruction that has been planted
153 // into the code buffer - it is typically used to link the jump, setting the
154 // relative offset such that when executed it will jump to the desired
155 // destination.
156 //
157 // Jump objects retain a pointer to the assembler for syntactic purposes -
158 // to allow the jump object to be able to link itself, e.g.:
159 //
160 // Jump forwardsBranch = jne32(Imm32(0), reg1);
161 // // ...
162 // forwardsBranch.link();
163 //
164 // Jumps may also be linked to a Label.
165 class Jump {
166 public:
167 Jump()
168 : m_assembler(0)
169 {
170 }
171
172 Jump(X86Assembler& assembler, X86Assembler::JmpSrc jmp)
173 : m_assembler(&assembler)
174 , m_jmp(jmp)
175 {
176 }
177
178 void link()
179 {
180 ASSERT(m_assembler);
181 m_assembler->link(m_jmp, m_assembler->label());
182 }
183
184 void linkTo(Label label)
185 {
186 ASSERT(m_assembler);
187 m_assembler->link(m_jmp, label.m_label);
188 }
189
190 private:
191 X86Assembler* m_assembler;
192 X86Assembler::JmpSrc m_jmp;
193 };
194
195 // JumpList:
196 //
197 // A JumpList is a set of Jump objects.
198 // All jumps in the set will be linked to the same destination.
199 class JumpList {
200 public:
201 void link()
202 {
203 size_t size = jumps.size();
204 for (size_t i = 0; i < size; ++i)
205 jumps[i].link();
206 jumps.clear();
207 }
208
209 void linkTo(Label label)
210 {
211 size_t size = jumps.size();
212 for (size_t i = 0; i < size; ++i)
213 jumps[i].linkTo(label);
214 jumps.clear();
215 }
216
217 void append(Jump jump)
218 {
219 jumps.append(jump);
220 }
221
222 void append(JumpList& other)
223 {
224 jumps.append(other.jumps.begin(), other.jumps.size());
225 }
226
227 private:
228 Vector<Jump> jumps;
229 };
230
231 // Imm32:
232 //
233 // A 32bit immediate operand to an instruction - this is wrapped in a
234 // class requiring explicit construction in order to prevent RegisterIDs
235 // (which are implemented as an enum) from accidentally being passed as
236 // immediate values.
237 struct Imm32 {
238 explicit Imm32(int32_t value)
239 : m_value(value)
240 {
241 }
242
243 int32_t m_value;
244 };
245
246
247 // Integer arithmetic operations:
248 //
249 // Operations are typically two operand - operation(source, srcDst)
250 // For many operations the source may be an Imm32, the srcDst operand
251 // may often be a memory location (explictly described using an Address
252 // object).
253
254 void add32(Imm32 imm, RegisterID dest)
255 {
256 if (CAN_SIGN_EXTEND_8_32(imm.m_value))
257 m_assembler.addl_i8r(imm.m_value, dest);
258 else
259 m_assembler.addl_i32r(imm.m_value, dest);
260 }
261
262 void add32(Address src, RegisterID dest)
263 {
264 m_assembler.addl_mr(src.offset, src.base, dest);
265 }
266
267 void or32(Imm32 imm, RegisterID dest)
268 {
269 m_assembler.orl_i32r(imm.m_value, dest);
270 }
271
272 void sub32(Imm32 imm, RegisterID dest)
273 {
274 if (CAN_SIGN_EXTEND_8_32(imm.m_value))
275 m_assembler.subl_i8r(imm.m_value, dest);
276 else
277 m_assembler.subl_i32r(imm.m_value, dest);
278 }
279
280 void sub32(Address src, RegisterID dest)
281 {
282 m_assembler.subl_mr(src.offset, src.base, dest);
283 }
284
285
286 // Memory access operations:
287 //
288 // Loads are of the form load(address, destination) and stores of the form
289 // store(source, address). The source for a store may be an Imm32. Address
290 // operand objects to loads and store will be implicitly constructed if a
291 // register is passed.
292
293 void loadPtr(ImplicitAddress address, RegisterID dest)
294 {
295 if (address.offset)
296 m_assembler.movl_mr(address.offset, address.base, dest);
297 else
298 m_assembler.movl_mr(address.base, dest);
299 }
300
301 void load32(ImplicitAddress address, RegisterID dest)
302 {
303 if (address.offset)
304 m_assembler.movl_mr(address.offset, address.base, dest);
305 else
306 m_assembler.movl_mr(address.base, dest);
307 }
308
309 void load16(BaseIndex address, RegisterID dest)
310 {
311 if (address.offset)
312 m_assembler.movzwl_mr(address.offset, address.base, address.index, address.scale, dest);
313 else
314 m_assembler.movzwl_mr(address.base, address.index, address.scale, dest);
315 }
316
317 void storePtr(RegisterID src, ImplicitAddress address)
318 {
319 if (address.offset)
320 m_assembler.movl_rm(src, address.offset, address.base);
321 else
322 m_assembler.movl_rm(src, address.base);
323 }
324
325 void store32(RegisterID src, ImplicitAddress address)
326 {
327 if (address.offset)
328 m_assembler.movl_rm(src, address.offset, address.base);
329 else
330 m_assembler.movl_rm(src, address.base);
331 }
332
333 void store32(Imm32 imm, ImplicitAddress address)
334 {
335 // FIXME: add a version that doesn't take an offset
336 m_assembler.movl_i32m(imm.m_value, address.offset, address.base);
337 }
338
339
340 // Stack manipulation operations:
341 //
342 // The ABI is assumed to provide a stack abstraction to memory,
343 // containing machine word sized units of data. Push and pop
344 // operations add and remove a single register sized unit of data
345 // to or from the stack. Peek and poke operations read or write
346 // values on the stack, without moving the current stack position.
347
348 void pop(RegisterID dest)
349 {
350 m_assembler.popl_r(dest);
351 }
352
353 void push(RegisterID src)
354 {
355 m_assembler.pushl_r(src);
356 }
357
358 void pop()
359 {
360 m_assembler.addl_i8r(sizeof(void*), X86::esp);
361 }
362
363 void peek(RegisterID dest, int index = 0)
364 {
365 loadPtr(Address(X86::esp, (index * sizeof(void *))), dest);
366 }
367
368 void poke(RegisterID src, int index = 0)
369 {
370 storePtr(src, Address(X86::esp, (index * sizeof(void *))));
371 }
372
373
374 // Register move operations:
375 //
376 // Move values in registers.
377
378 void move(Imm32 imm, RegisterID dest)
379 {
380 if (!imm.m_value)
381 m_assembler.xorl_rr(dest, dest);
382 else
383 m_assembler.movl_i32r(imm.m_value, dest);
384 }
385
386
387 // Forwards / external control flow operations:
388 //
389 // This set of jump and conditional branch operations return a Jump
390 // object which may linked at a later point, allow forwards jump,
391 // or jumps that will require external linkage (after the code has been
392 // relocated).
393 //
394 // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
395 // respecitvely, for unsigned comparisons the names b, a, be, and ae are
396 // used (representing the names 'below' and 'above').
397 //
398 // Operands to the comparision are provided in the expected order, e.g.
399 // jle32(reg1, Imm32(5)) will branch if the value held in reg1, when
400 // treated as a signed 32bit value, is less than or equal to 5.
401
402private:
403 void compareImm32ForBranch(RegisterID left, int32_t right)
404 {
405 if (CAN_SIGN_EXTEND_8_32(right))
406 m_assembler.cmpl_i8r(right, left);
407 else
408 m_assembler.cmpl_i32r(right, left);
409 }
410
411 void compareImm32ForBranchEquality(RegisterID reg, int32_t imm)
412 {
413 if (!imm)
414 m_assembler.testl_rr(reg, reg);
415 else if (CAN_SIGN_EXTEND_8_32(imm))
416 m_assembler.cmpl_i8r(imm, reg);
417 else
418 m_assembler.cmpl_i32r(imm, reg);
419 }
420
421public:
422 Jump jae32(RegisterID left, Imm32 right)
423 {
424 compareImm32ForBranch(left, right.m_value);
425 return Jump(m_assembler, m_assembler.jae());
426 }
427
428 Jump je32(RegisterID op1, RegisterID op2)
429 {
430 m_assembler.cmpl_rr(op1, op2);
431 return Jump(m_assembler, m_assembler.je());
432 }
433
434 Jump je32(RegisterID op1, Address op2)
435 {
436 m_assembler.cmpl_rm(op1, op2.offset, op2.base);
437 return Jump(m_assembler, m_assembler.je());
438 }
439
440 Jump je32(Imm32 imm, RegisterID reg)
441 {
442 compareImm32ForBranchEquality(reg, imm.m_value);
443 return Jump(m_assembler, m_assembler.je());
444 }
445
446 Jump je16(RegisterID op1, BaseIndex op2)
447 {
448 if (op2.offset)
449 m_assembler.cmpw_rm(op1, op2.base, op2.index, op2.scale);
450 else
451 m_assembler.cmpw_rm(op1, op2.offset, op2.base, op2.index, op2.scale);
452
453 return Jump(m_assembler, m_assembler.je());
454 }
455
456 Jump jg32(RegisterID left, RegisterID right)
457 {
458 m_assembler.cmpl_rr(right, left);
459 return Jump(m_assembler, m_assembler.jg());
460 }
461
462 Jump jge32(RegisterID left, Imm32 right)
463 {
464 compareImm32ForBranch(left, right.m_value);
465 return Jump(m_assembler, m_assembler.jge());
466 }
467
468 Jump jl32(RegisterID left, Imm32 right)
469 {
470 compareImm32ForBranch(left, right.m_value);
471 return Jump(m_assembler, m_assembler.jl());
472 }
473
474 Jump jle32(RegisterID left, RegisterID right)
475 {
476 m_assembler.cmpl_rr(right, left);
477 return Jump(m_assembler, m_assembler.jle());
478 }
479
480 Jump jle32(RegisterID left, Imm32 right)
481 {
482 compareImm32ForBranch(left, right.m_value);
483 return Jump(m_assembler, m_assembler.jle());
484 }
485
486 Jump jne32(RegisterID op1, RegisterID op2)
487 {
488 m_assembler.cmpl_rr(op1, op2);
489 return Jump(m_assembler, m_assembler.jne());
490 }
491
492 Jump jne32(Imm32 imm, RegisterID reg)
493 {
494 compareImm32ForBranchEquality(reg, imm.m_value);
495 return Jump(m_assembler, m_assembler.jne());
496 }
497
498 Jump jump()
499 {
500 return Jump(m_assembler, m_assembler.jmp());
501 }
502
503
504 // Backwards, local control flow operations:
505 //
506 // These operations provide a shorter notation for local
507 // backwards branches, which may be both more convenient
508 // for the user, and for the programmer, and for the
509 // assembler (allowing shorter values to be used in
510 // relative offsets).
511 //
512 // The code sequence:
513 //
514 // Label topOfLoop(this);
515 // // ...
516 // jne32(reg1, reg2, topOfLoop);
517 //
518 // Is equivalent to the longer, potentially less efficient form:
519 //
520 // Label topOfLoop(this);
521 // // ...
522 // jne32(reg1, reg2).linkTo(topOfLoop);
523
524 void je32(Imm32 imm, RegisterID op2, Label target)
525 {
526 je32(imm, op2).linkTo(target);
527 }
528
529 void je16(RegisterID op1, BaseIndex op2, Label target)
530 {
531 je16(op1, op2).linkTo(target);
532 }
533
534 void jl32(RegisterID left, Imm32 right, Label target)
535 {
536 jl32(left, right).linkTo(target);
537 }
538
539 void jle32(RegisterID left, RegisterID right, Label target)
540 {
541 jle32(left, right).linkTo(target);
542 }
543
544 void jne32(RegisterID op1, RegisterID op2, Label target)
545 {
546 jne32(op1, op2).linkTo(target);
547 }
548
549 void jne32(Imm32 imm, RegisterID op2, Label target)
550 {
551 jne32(imm, op2).linkTo(target);
552 }
553
554 void jump(Label target)
555 {
556 m_assembler.link(m_assembler.jmp(), target.m_label);
557 }
558
559
560 // Miscellaneous operations:
561
562 void breakpoint()
563 {
564 m_assembler.int3();
565 }
566
567 void ret()
568 {
569 m_assembler.ret();
570 }
571};
572
573} // namespace JSC
574
575#endif // ENABLE(ASSEMBLER)
576
577#endif // MacroAssembler_h
Note: See TracBrowser for help on using the repository browser.