OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2008 the V8 project authors. All rights reserved. | |
2 // Redistribution and use in source and binary forms, with or without | |
3 // modification, are permitted provided that the following conditions are | |
4 // met: | |
5 // | |
6 // * Redistributions of source code must retain the above copyright | |
7 // notice, this list of conditions and the following disclaimer. | |
8 // * Redistributions in binary form must reproduce the above | |
9 // copyright notice, this list of conditions and the following | |
10 // disclaimer in the documentation and/or other materials provided | |
11 // with the distribution. | |
12 // * Neither the name of Google Inc. nor the names of its | |
13 // contributors may be used to endorse or promote products derived | |
14 // from this software without specific prior written permission. | |
15 // | |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
24 // THEORY 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 #include <string.h> | |
29 #include "v8.h" | |
30 #include "log.h" | |
31 #include "ast.h" | |
32 #include "macro-assembler.h" | |
33 #include "regexp-macro-assembler-ia32.h" | |
34 | |
35 namespace v8 { namespace internal { | |
36 /* | |
37 * This assembler uses the following register assignment convention | |
38 * - edx : current character, or kEndOfInput if current position is not | |
39 * inside string. The kEndOfInput value is greater than 0xffff, | |
40 * so any tests that don't check whether the current position | |
41 * is inside the correct range should retain bits above the | |
42 * 15th in their computations, and fail if the value is too | |
43 * great. | |
44 * - edi : current position in input, as negative offset from end of string. | |
45 * - esi : end of input (points to byte after last character in input). | |
46 * - ebp : points to the location above the registers on the stack, | |
47 * as if by the "enter <register_count>" opcode. | |
48 * - esp : points to tip of backtracking stack. | |
49 * | |
50 * The registers eax, ebx and ecx are free to use for computations. | |
51 * | |
52 * Each call to a public method should retain this convention. | |
53 * The stack will have the following structure: | |
54 * - int* capture_array (int[num_saved_registers_], for output). | |
55 * - end of input (index of end of string, relative to *string_base) | |
56 * - start of input (index of first character in string, relative | |
57 * to *string_base) | |
58 * - void** string_base (location of a handle containing the string) | |
59 * - return address | |
60 * - backup of esi | |
61 * - backup of edi | |
62 * ebp-> - old ebp | |
63 * - register 0 ebp[-4] | |
64 * - register 1 ebp[-8] | |
65 * - ... | |
66 * | |
67 * The data before ebp must be placed there by the calling code, e.g., | |
68 * by calling the code as cast to: | |
69 * bool (*match)(String** string_base, | |
70 * int start_offset, | |
71 * int end_offset, | |
72 * int* capture_output_array) | |
73 */ | |
74 | |
75 #define __ masm_-> | |
76 | |
77 RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32( | |
78 Mode mode, | |
79 int registers_to_save, | |
80 bool ignore_case) | |
81 : masm_(new MacroAssembler(NULL, kRegExpCodeSize)), | |
Mads Ager (chromium)
2008/11/25 21:09:41
Guess what? :-)
| |
82 constants_(kRegExpConstantsSize), | |
83 mode_(mode), | |
84 num_registers_(registers_to_save), | |
85 num_saved_registers_(registers_to_save), | |
86 ignore_case_(ignore_case), | |
87 entry_label_(), | |
88 start_label_(), | |
89 success_label_(), | |
90 exit_label_(), | |
91 self_(Heap::undefined_value()) { | |
92 __ jmp(&entry_label_); // We'll write the entry code later. | |
93 __ bind(&start_label_); // And then continue from here. | |
94 } | |
95 | |
96 | |
97 RegExpMacroAssemblerIA32::~RegExpMacroAssemblerIA32() { | |
98 delete masm_; | |
99 // Unuse labels in case we throw away the assembler without calling GetCode. | |
100 entry_label_.Unuse(); | |
101 start_label_.Unuse(); | |
102 success_label_.Unuse(); | |
103 exit_label_.Unuse(); | |
104 } | |
105 | |
106 | |
107 void RegExpMacroAssemblerIA32::AdvanceCurrentPosition(int by) { | |
108 ASSERT(by > 0); | |
109 Label inside_string; | |
110 __ add(Operand(edi), Immediate(by * char_size())); | |
111 __ j(below, &inside_string); | |
112 Backtrack(); | |
113 | |
114 __ bind(&inside_string); | |
115 } | |
116 | |
117 | |
118 void RegExpMacroAssemblerIA32::AdvanceRegister(int reg, int by) { | |
119 ASSERT(reg >= 0); | |
120 ASSERT(reg < num_registers_); | |
121 __ add(register_location(reg), Immediate(by)); | |
122 } | |
123 | |
124 | |
125 void RegExpMacroAssemblerIA32::Backtrack() { | |
126 __ pop(ecx); | |
127 __ add(Operand(ecx), Immediate(self_)); | |
128 __ jmp(Operand(ecx)); | |
129 } | |
130 | |
131 | |
132 void RegExpMacroAssemblerIA32::Bind(Label* label) { | |
133 __ bind(label); | |
134 } | |
135 | |
136 void RegExpMacroAssemblerIA32::CheckBitmap(uc16 start, | |
137 Label* bitmap, | |
138 Label* on_zero) { | |
139 ReadCurrentChar(eax); | |
140 __ sub(Operand(eax), Immediate(start)); | |
141 __ cmp(eax, 64); // FIXME: 64 = length_of_bitmap_in_bits. | |
142 BranchOrBacktrack(greater_equal, on_zero); | |
143 __ mov(ebx, eax); | |
144 __ shr(ebx, 3); | |
145 // TODO(lrn): Where is the bitmap stored? Pass the bitmap as argument instead. | |
146 // __ mov(ecx, position_of_bitmap); | |
147 __ movzx_b(ebx, Operand(ecx, ebx, times_1, 0)); | |
148 __ and_(eax, (1<<3)-1); | |
149 __ bt(Operand(ebx), eax); | |
150 __ j(carry, on_zero); | |
151 } | |
152 | |
153 | |
154 void RegExpMacroAssemblerIA32::CheckCharacter(uc16 c, Label* on_equal) { | |
155 __ cmp(edx, c); | |
156 BranchOrBacktrack(equal, on_equal); | |
157 } | |
158 | |
159 | |
160 void RegExpMacroAssemblerIA32::CheckCharacterGT(uc16 limit, Label* on_greater) { | |
161 __ cmp(edx, limit); | |
162 BranchOrBacktrack(greater, on_greater); | |
163 } | |
164 | |
165 | |
166 void RegExpMacroAssemblerIA32::CheckCharacterLT(uc16 limit, Label* on_less) { | |
167 __ cmp(edx, limit); | |
168 BranchOrBacktrack(less, on_less); | |
169 } | |
170 | |
171 | |
172 void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str, | |
173 int cp_offset, | |
174 Label* on_failure) { | |
175 int byte_length = str.length() * char_size(); | |
176 int start_offset = cp_offset * char_size(); | |
177 __ mov(ebx, edi); | |
178 __ add(Operand(ebx), Immediate(start_offset + byte_length)); | |
179 BranchOrBacktrack(greater_equal, on_failure); | |
180 | |
181 ArraySlice constant_buffer = constants_.GetBuffer(str.length(), char_size()); | |
182 for (int i = 0; i < str.length(); i++) { | |
183 if (mode_ == ASCII) { | |
184 constant_buffer.at<char>(i) = static_cast<char>(str[i]); | |
185 } else { | |
186 memcpy(constant_buffer.location<void>(), | |
187 str.start(), | |
188 str.length() * sizeof(uc16)); | |
189 } | |
190 } | |
191 | |
192 __ mov(eax, edi); | |
193 __ mov(ebx, esi); | |
194 __ lea(edi, Operand(esi, edi, times_1, start_offset)); | |
195 LoadConstantBufferAddress(esi, &constant_buffer); | |
196 __ mov(ecx, str.length()); | |
197 if (mode_ == ASCII) { | |
198 __ rep_cmpsb(); | |
199 } else { | |
200 ASSERT(mode_ == UC16); | |
201 __ rep_cmpsw(); | |
202 } | |
203 __ mov(esi, ebx); | |
204 __ mov(edi, eax); | |
205 BranchOrBacktrack(not_equal, on_failure); | |
206 } | |
207 | |
208 | |
209 void RegExpMacroAssemblerIA32::CheckCurrentPosition(int register_index, | |
210 Label* on_equal) { | |
211 __ cmp(edi, register_location(register_index)); | |
212 BranchOrBacktrack(equal, on_equal); | |
213 } | |
214 | |
215 | |
216 void RegExpMacroAssemblerIA32::CheckNotBackReference( | |
217 int start_reg, Label* on_no_match) { | |
218 if (ignore_case_) { | |
219 UNIMPLEMENTED(); | |
220 } | |
221 Label fallthrough; | |
222 __ mov(eax, register_location(start_reg)); | |
223 __ mov(ecx, register_location(start_reg + 1)); | |
224 __ sub(ecx, Operand(eax)); // Length to check. | |
225 __ j(equal, &fallthrough); // Covers the case where it's not bound (-1,-1). | |
226 __ mov(ebx, Operand(edi)); | |
227 __ push(esi); | |
228 __ add(edi, Operand(esi)); | |
229 __ add(esi, Operand(eax)); | |
230 if (mode_ == ASCII) { | |
231 __ rep_cmpsb(); | |
232 } else { | |
233 __ rep_cmpsw(); | |
234 } | |
235 __ pop(esi); | |
236 __ mov(edi, Operand(ebx)); | |
237 BranchOrBacktrack(not_equal, on_no_match); | |
238 __ bind(&fallthrough); | |
239 } | |
240 | |
241 | |
242 void RegExpMacroAssemblerIA32::CheckNotCharacter(uc16 c, Label* on_not_equal) { | |
243 __ cmp(edx, c); | |
244 BranchOrBacktrack(not_equal, on_not_equal); | |
245 } | |
246 | |
247 | |
248 void RegExpMacroAssemblerIA32::CheckNotCharacterAfterOr(uc16 c, | |
249 uc16 mask, | |
250 Label* on_not_equal) { | |
251 __ mov(eax, Operand(edx)); | |
252 __ or_(eax, mask); | |
253 __ cmp(eax, c); | |
254 BranchOrBacktrack(not_equal, on_not_equal); | |
255 } | |
256 | |
257 | |
258 void RegExpMacroAssemblerIA32::CheckNotCharacterAfterMinusOr( | |
259 uc16 c, | |
260 uc16 mask, | |
261 Label* on_not_equal) { | |
262 __ lea(eax, Operand(edx, -mask)); | |
263 __ or_(eax, mask); | |
264 __ cmp(eax, c); | |
265 BranchOrBacktrack(not_equal, on_not_equal); | |
266 } | |
267 | |
268 | |
269 void RegExpMacroAssemblerIA32::DispatchHalfNibbleMap( | |
270 uc16 start, | |
271 Label* half_nibble_map, | |
272 const Vector<Label*>& destinations) { | |
273 ReadCurrentChar(eax); | |
274 __ sub(Operand(eax), Immediate(start)); | |
275 | |
276 __ mov(ecx, eax); | |
277 __ shr(eax, 2); | |
278 // FIXME: ecx must hold address of map | |
279 __ movzx_b(eax, Operand(ecx, eax, times_1, 0)); | |
280 __ and_(ecx, 0x03); | |
281 __ add(ecx, Operand(ecx)); | |
282 __ shr(eax); // Shift right cl times | |
283 | |
284 Label second_bit_set, case_3, case_1; | |
285 __ test(eax, Immediate(0x02)); | |
286 __ j(not_zero, &second_bit_set); | |
287 __ test(eax, Immediate(0x01)); | |
288 __ j(not_zero, &case_1); | |
289 // Case 0: | |
290 __ jmp(destinations[0]); | |
291 __ bind(&case_1); | |
292 // Case 1: | |
293 __ jmp(destinations[1]); | |
294 __ bind(&second_bit_set); | |
295 __ test(eax, Immediate(0x01)); | |
296 __ j(not_zero, &case_3); | |
297 // Case 2 | |
298 __ jmp(destinations[2]); | |
299 __ bind(&case_3); | |
300 // Case 3: | |
301 __ jmp(destinations[3]); | |
302 } | |
303 | |
304 | |
305 void RegExpMacroAssemblerIA32::DispatchByteMap( | |
306 uc16 start, | |
307 Label* byte_map, | |
308 const Vector<Label*>& destinations) { | |
309 Label fallthrough; | |
310 ReadCurrentChar(eax); | |
311 __ sub(Operand(eax), Immediate(start)); | |
312 __ cmp(eax, 64); // FIXME: 64 = size of map. Found somehow?? | |
313 __ j(greater_equal, &fallthrough); | |
314 // FIXME: ecx must hold address of map | |
315 __ movzx_b(eax, Operand(ecx, eax, times_1, 0)); | |
316 // jump table: jump to destinations[eax]; | |
317 | |
318 __ bind(&fallthrough); | |
319 } | |
320 | |
321 | |
322 | |
323 void RegExpMacroAssemblerIA32::DispatchHighByteMap( | |
324 byte start, | |
325 Label* byte_map, | |
326 const Vector<Label*>& destinations) { | |
327 Label fallthrough; | |
328 ReadCurrentChar(eax); | |
329 __ shr(eax, 8); | |
330 __ sub(Operand(eax), Immediate(start)); | |
331 __ cmp(eax, destinations.length() - start); | |
332 __ j(greater_equal, &fallthrough); | |
333 | |
334 // TODO(lrn) jumptable: jump to destinations[eax] | |
335 __ bind(&fallthrough); | |
336 } | |
337 | |
338 | |
339 void RegExpMacroAssemblerIA32::EmitOrLink(Label* label) { | |
340 UNREACHABLE(); // Has no use. | |
341 } | |
342 | |
343 | |
344 void RegExpMacroAssemblerIA32::Fail() { | |
345 __ mov(eax, 0); | |
346 __ jmp(&exit_label_); | |
347 } | |
348 | |
349 | |
350 Handle<Object> RegExpMacroAssemblerIA32::GetCode() { | |
351 // Finalize code - write the entry point code now we know how many | |
352 // registers we need. | |
353 | |
354 // Entry code: | |
355 __ bind(&entry_label_); | |
356 __ push(esi); | |
357 __ push(edi); | |
358 __ enter(Immediate(num_registers_ * sizeof(uint32_t))); | |
359 __ mov(esi, Operand(ebp, kInputEndOffset)); | |
360 __ mov(edi, Operand(ebp, kInputStartOffset)); | |
361 __ sub(edi, Operand(esi)); | |
362 __ mov(edx, Operand(ebp, kInputBuffer)); | |
363 __ mov(edx, Operand(edx, 0)); | |
364 __ add(esi, Operand(edx)); | |
365 __ jmp(&start_label_); | |
366 | |
367 // Exit code: | |
368 __ bind(&success_label_); | |
369 __ mov(ebx, Operand(ebp, kRegisterOutput)); | |
370 __ mov(ecx, Operand(ebp, kInputEndOffset)); | |
371 __ sub(ecx, Operand(ebp, kInputStartOffset)); | |
372 for (int i = 0; i < num_saved_registers_; i++) { | |
373 __ mov(eax, register_location(i)); | |
374 __ sub(eax, Operand(ecx)); // Convert to index from start, not end. | |
375 __ mov(Operand(ebx, i * sizeof(int32_t)), eax); | |
376 } | |
377 // copy captures to output | |
378 __ mov(eax, Immediate(1)); | |
379 | |
380 __ bind(&exit_label_); | |
381 __ leave(); | |
382 __ pop(edi); | |
383 __ pop(esi); | |
384 __ ret(0); | |
385 | |
386 CodeDesc code_desc; | |
387 masm_->GetCode(&code_desc); | |
388 Handle<Code> code = Factory::NewCode(code_desc, | |
389 NULL, | |
390 Code::ComputeFlags(Code::REGEXP), | |
391 self_); | |
392 LOG(CodeCreateEvent("RegExp", *code, "(Compiled RegExp)")); | |
393 return Handle<Object>::cast(code); | |
394 } | |
395 | |
396 | |
397 void RegExpMacroAssemblerIA32::GoTo(Label* to) { | |
398 __ jmp(to); | |
399 } | |
400 | |
401 | |
402 | |
403 void RegExpMacroAssemblerIA32::IfRegisterGE(int reg, | |
404 int comparand, | |
405 Label* if_ge) { | |
406 __ cmp(register_location(reg), Immediate(comparand)); | |
407 BranchOrBacktrack(greater_equal, if_ge); | |
408 } | |
409 | |
410 | |
411 | |
412 void RegExpMacroAssemblerIA32::IfRegisterLT(int reg, | |
413 int comparand, | |
414 Label* if_lt) { | |
415 __ cmp(register_location(reg), Immediate(comparand)); | |
416 BranchOrBacktrack(less, if_lt); | |
417 } | |
418 | |
419 | |
420 | |
421 RegExpMacroAssembler::IrregexpImplementation | |
422 RegExpMacroAssemblerIA32::Implementation() { | |
423 return kIA32Implementation; | |
424 } | |
425 | |
426 | |
427 | |
428 void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset, | |
429 Label* on_end_of_input) { | |
430 ASSERT(cp_offset >= 0); | |
431 ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works) | |
432 __ cmp(edi, -cp_offset); | |
433 BranchOrBacktrack(less_equal, on_end_of_input); | |
434 ReadChar(edx, cp_offset); | |
435 } | |
436 | |
437 | |
438 void RegExpMacroAssemblerIA32::PopCurrentPosition() { | |
439 __ pop(edi); | |
440 } | |
441 | |
442 | |
443 void RegExpMacroAssemblerIA32::PopRegister(int register_index) { | |
444 RecordRegister(register_index); | |
445 __ pop(register_location(register_index)); | |
446 } | |
447 | |
448 | |
449 void RegExpMacroAssemblerIA32::PushBacktrack(Label* label) { | |
450 // Check for preemption first. | |
451 Label no_preempt; | |
452 Label retry_preempt; | |
453 // Check for preemption. | |
454 ExternalReference stack_limit = | |
455 ExternalReference::address_of_stack_guard_limit(); | |
456 __ cmp(esp, Operand::StaticVariable(stack_limit)); | |
457 __ j(above, &no_preempt); | |
458 | |
459 __ push(edi); // Current position. | |
460 __ push(edx); // Current character. | |
461 // Restore original edi, esi. | |
462 __ mov(edi, Operand(ebp, kBackup_edi)); | |
463 __ mov(esi, Operand(ebp, kBackup_esi)); | |
464 | |
465 __ bind(&retry_preempt); | |
466 // simulate stack for Runtime call. | |
467 __ push(Immediate(0)); // Dummy receiver | |
468 __ CallRuntime(Runtime::kStackGuard, 0); | |
469 __ cmp(esp, Operand::StaticVariable(stack_limit)); | |
470 __ j(below_equal, &retry_preempt); | |
471 | |
472 __ pop(edx); | |
473 __ pop(edi); | |
474 __ mov(esi, Operand(ebp, kInputBuffer)); | |
475 __ mov(esi, Operand(esi, 0)); | |
476 __ add(esi, Operand(ebp, kInputEndOffset)); | |
477 | |
478 __ bind(&no_preempt); | |
479 | |
480 Label cont; | |
481 __ push(label, RelocInfo::NONE); | |
482 } | |
483 | |
484 | |
485 void RegExpMacroAssemblerIA32::PushCurrentPosition() { | |
486 __ push(edi); | |
487 } | |
488 | |
489 | |
490 void RegExpMacroAssemblerIA32::PushRegister(int register_index) { | |
491 __ push(register_location(register_index)); | |
492 } | |
493 | |
494 | |
495 void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) { | |
496 __ mov(edi, register_location(reg)); | |
497 } | |
498 | |
499 | |
500 void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) { | |
501 __ mov(esp, register_location(reg)); | |
502 } | |
503 | |
504 | |
505 void RegExpMacroAssemblerIA32::SetRegister(int register_index, int to) { | |
506 RecordRegister(register_index); | |
507 __ mov(register_location(register_index), Immediate(to)); | |
508 } | |
509 | |
510 | |
511 void RegExpMacroAssemblerIA32::Succeed() { | |
512 __ jmp(&success_label_); | |
513 } | |
514 | |
515 | |
516 void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister( | |
517 int register_index) { | |
518 __ mov(register_location(register_index), edi); | |
519 } | |
520 | |
521 void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) { | |
522 __ mov(register_location(reg), esp); | |
523 } | |
524 | |
525 | |
526 // Private methods: | |
527 | |
528 Operand RegExpMacroAssemblerIA32::register_location( | |
529 int register_index) { | |
530 ASSERT(register_index < (1<<30)); | |
531 return Operand(ebp, -((register_index + 1) * sizeof(uint32_t))); | |
532 } | |
533 | |
534 | |
535 size_t RegExpMacroAssemblerIA32::char_size() { | |
536 return static_cast<size_t>(mode_); | |
537 } | |
538 | |
539 | |
540 void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition, | |
541 Label* to) { | |
542 if (condition < 0) { // No condition | |
543 if (to == NULL) { | |
544 Backtrack(); | |
545 return; | |
546 } | |
547 __ jmp(to); | |
548 return; | |
549 } else if (to == NULL) { | |
550 Label skip; | |
551 __ j(NegateCondition(condition), &skip); | |
552 Backtrack(); | |
553 __ bind(&skip); | |
554 return; | |
555 } | |
556 __ j(condition, to); | |
557 } | |
558 | |
559 | |
560 void RegExpMacroAssemblerIA32::Canonicalize(Register reg) { | |
561 if (mode_ == ASCII) { | |
562 Label end; | |
563 __ cmp(Operand(reg), Immediate('a')); | |
564 __ j(below, &end); | |
565 __ cmp(Operand(reg), Immediate('z')); | |
566 __ j(above, &end); | |
567 __ sub(Operand(reg), Immediate('a' - 'A')); | |
568 __ bind(&end); | |
569 return; | |
570 } | |
571 ASSERT(mode_ == UC16); | |
572 // TODO(lrn): Use some tables. | |
573 } | |
574 | |
575 | |
576 void RegExpMacroAssemblerIA32::RecordRegister(int register_index) { | |
577 if (register_index >= num_registers_) { | |
578 num_registers_ = register_index + 1; | |
579 } | |
580 } | |
581 | |
582 | |
583 void RegExpMacroAssemblerIA32::ReadChar(Register destination, int offset) { | |
584 if (mode_ == ASCII) { | |
585 __ movzx_b(destination, Operand(esi, edi, times_1, offset)); | |
586 return; | |
587 } | |
588 ASSERT(mode_ == UC16); | |
589 __ movzx_w(destination, Operand(esi, edi, times_1, offset * 2)); | |
590 } | |
591 | |
592 | |
593 void RegExpMacroAssemblerIA32::ReadCurrentChar(Register destination) { | |
594 __ mov(destination, edx); | |
595 } | |
596 | |
597 | |
598 void RegExpMacroAssemblerIA32::LoadConstantBufferAddress(Register reg, | |
599 ArraySlice* buffer) { | |
600 __ mov(reg, buffer->array()); | |
601 __ add(Operand(reg), Immediate(buffer->base_offset())); | |
602 } | |
603 | |
604 #undef __ | |
605 }} | |
OLD | NEW |