blob: 76b4bcff5dd27a6e369c3e623d5710ce74371fd0 [file] [log] [blame]
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001// 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.h"
34#include "macro-assembler-ia32.h"
35#include "regexp-macro-assembler-ia32.h"
36
37namespace v8 { namespace internal {
38
39/*
40 * This assembler uses the following register assignment convention
41 * - edx : current character. Must be loaded using LoadCurrentCharacter
42 * before using any of the dispatch methods.
43 * - edi : current position in input, as negative offset from end of string.
44 * Please notice that this is the byte offset, not the character offset!
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 * - at_start (if 1, start at start of string, if 0, don't)
55 * - int* capture_array (int[num_saved_registers_], for output).
56 * - end of input (index of end of string, relative to *string_base)
57 * - start of input (index of first character in string, relative
58 * to *string_base)
59 * - void** string_base (location of a handle containing the string)
60 * - return address
61 * - backup of esi
62 * - backup of edi
63 * - backup of ebx
64 * ebp-> - old ebp
65 * - register 0 ebp[-4] (Only positions must be stored in the first
66 * - register 1 ebp[-8] num_saved_registers_ registers)
67 * - ...
68 *
69 * The first num_saved_registers_ registers are initialized to point to
70 * "character -1" in the string (i.e., char_size() bytes before the first
71 * character of the string). The remaining registers starts out as garbage.
72 *
73 * The data up to the return address must be placed there by the calling
74 * code, e.g., by calling the code as cast to:
75 * bool (*match)(String** string_base,
76 * int start_offset,
77 * int end_offset,
78 * int* capture_output_array,
79 * bool at_start)
80 */
81
82#define __ masm_->
83
84RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(
85 Mode mode,
86 int registers_to_save)
87 : masm_(new MacroAssembler(NULL, kRegExpCodeSize)),
88 constants_(kRegExpConstantsSize),
89 mode_(mode),
90 num_registers_(registers_to_save),
91 num_saved_registers_(registers_to_save),
92 entry_label_(),
93 start_label_(),
94 success_label_(),
95 exit_label_(),
96 self_(Heap::undefined_value()) {
97 __ jmp(&entry_label_); // We'll write the entry code later.
98 __ bind(&start_label_); // And then continue from here.
99}
100
101
102RegExpMacroAssemblerIA32::~RegExpMacroAssemblerIA32() {
103 delete masm_;
104 // Unuse labels in case we throw away the assembler without calling GetCode.
105 entry_label_.Unuse();
106 start_label_.Unuse();
107 success_label_.Unuse();
108 exit_label_.Unuse();
109}
110
111
112void RegExpMacroAssemblerIA32::AdvanceCurrentPosition(int by) {
113 ASSERT(by > 0);
114 Label inside_string;
115 __ add(Operand(edi), Immediate(by * char_size()));
116}
117
118
119void RegExpMacroAssemblerIA32::AdvanceRegister(int reg, int by) {
120 ASSERT(reg >= 0);
121 ASSERT(reg < num_registers_);
122 __ add(register_location(reg), Immediate(by));
123}
124
125
126void RegExpMacroAssemblerIA32::Backtrack() {
127 __ pop(ecx);
128 __ add(Operand(ecx), Immediate(self_));
129 __ jmp(Operand(ecx));
130}
131
132
133void RegExpMacroAssemblerIA32::Bind(Label* label) {
134 __ bind(label);
135}
136
137void RegExpMacroAssemblerIA32::CheckBitmap(uc16 start,
138 Label* bitmap,
139 Label* on_zero) {
140 UNREACHABLE();
141 __ mov(eax, current_character());
142 __ sub(Operand(eax), Immediate(start));
143 __ cmp(eax, 64); // FIXME: 64 = length_of_bitmap_in_bits.
144 BranchOrBacktrack(greater_equal, on_zero);
145 __ mov(ebx, eax);
146 __ shr(ebx, 3);
147 // TODO(lrn): Where is the bitmap stored? Pass the bitmap as argument instead.
148 // __ mov(ecx, position_of_bitmap);
149 __ movzx_b(ebx, Operand(ecx, ebx, times_1, 0));
150 __ and_(eax, (1<<3)-1);
151 __ bt(Operand(ebx), eax);
152 __ j(carry, on_zero);
153}
154
155
156void RegExpMacroAssemblerIA32::CheckCharacter(uc16 c, Label* on_equal) {
157 __ cmp(current_character(), c);
158 BranchOrBacktrack(equal, on_equal);
159}
160
161
162void RegExpMacroAssemblerIA32::CheckCharacterGT(uc16 limit, Label* on_greater) {
163 __ cmp(current_character(), limit);
164 BranchOrBacktrack(greater, on_greater);
165}
166
167
168void RegExpMacroAssemblerIA32::CheckNotAtStart(Label* on_not_at_start) {
169 __ cmp(Operand(ebp, kAtStart), Immediate(0));
170 BranchOrBacktrack(equal, on_not_at_start);
171 __ mov(eax, Operand(ebp, kInputEndOffset));
172 __ add(eax, Operand(edi));
173 __ cmp(eax, Operand(ebp, kInputStartOffset));
174 BranchOrBacktrack(not_equal, on_not_at_start);
175}
176
177
178void RegExpMacroAssemblerIA32::CheckCharacterLT(uc16 limit, Label* on_less) {
179 __ cmp(current_character(), limit);
180 BranchOrBacktrack(less, on_less);
181}
182
183
184void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str,
185 int cp_offset,
186 Label* on_failure) {
187 int byte_length = str.length() * char_size();
188 int byte_offset = cp_offset * char_size();
189 __ cmp(Operand(edi), Immediate(-(byte_offset + byte_length)));
190 BranchOrBacktrack(greater, on_failure);
191
192 if (str.length() <= kMaxInlineStringTests) {
193 for (int i = 0; i < str.length(); i++) {
194 if (mode_ == ASCII) {
195 __ cmpb(Operand(esi, edi, times_1, byte_offset + i),
196 static_cast<int8_t>(str[i]));
197 } else {
198 ASSERT(mode_ == UC16);
199 __ cmpw(Operand(esi, edi, times_1, byte_offset + i * sizeof(uc16)),
200 Immediate(str[i]));
201 }
202 __ j(not_equal, on_failure);
203 }
204 return;
205 }
206
207 ArraySlice constant_buffer = constants_.GetBuffer(str.length(), char_size());
208 if (mode_ == ASCII) {
209 for (int i = 0; i < str.length(); i++) {
210 constant_buffer.at<char>(i) = static_cast<char>(str[i]);
211 }
212 } else {
213 memcpy(constant_buffer.location(),
214 str.start(),
215 str.length() * sizeof(uc16));
216 }
217
218 __ mov(eax, edi);
219 __ mov(ebx, esi);
220 __ lea(edi, Operand(esi, edi, times_1, byte_offset));
221 LoadConstantBufferAddress(esi, &constant_buffer);
222 __ mov(ecx, str.length());
223 if (char_size() == 1) {
224 __ rep_cmpsb();
225 } else {
226 ASSERT(char_size() == 2);
227 __ rep_cmpsw();
228 }
229 __ mov(esi, ebx);
230 __ mov(edi, eax);
231 BranchOrBacktrack(not_equal, on_failure);
232}
233
234
235void RegExpMacroAssemblerIA32::CheckCurrentPosition(int register_index,
236 Label* on_equal) {
237 __ cmp(edi, register_location(register_index));
238 BranchOrBacktrack(equal, on_equal);
239}
240
241
242void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
243 int start_reg, Label* on_no_match) {
244 Label fallthrough;
245 __ mov(eax, register_location(start_reg));
246 __ mov(ecx, register_location(start_reg + 1));
247 __ sub(ecx, Operand(eax)); // Length to check.
248 __ j(less, on_no_match);
249 __ j(equal, &fallthrough);
250
251 UNIMPLEMENTED(); // TODO(lrn): Call runtime function to do test.
252
253 __ bind(&fallthrough);
254}
255
256
257void RegExpMacroAssemblerIA32::CheckNotBackReference(
258 int start_reg, Label* on_no_match) {
259 Label fallthrough;
260 __ mov(eax, register_location(start_reg));
261 __ mov(ecx, register_location(start_reg + 1));
262 __ sub(ecx, Operand(eax)); // Length to check.
263 BranchOrBacktrack(less, on_no_match);
264 __ j(equal, &fallthrough);
265 // Check that there are sufficient characters left in the input.
266 __ mov(ebx, edi);
267 __ add(ebx, Operand(ecx));
268 BranchOrBacktrack(greater, on_no_match);
269
270 __ mov(ebx, edi);
271 __ mov(edx, esi);
272 __ add(edi, Operand(esi));
273 __ add(esi, Operand(eax));
274 __ rep_cmpsb();
275 __ mov(esi, edx);
276 Label success;
277 __ j(equal, &success);
278 __ mov(edi, ebx);
279 BranchOrBacktrack(no_condition, on_no_match);
280
281 __ bind(&success);
282 __ sub(edi, Operand(esi));
283
284 __ bind(&fallthrough);
285}
286
287
288void RegExpMacroAssemblerIA32::CheckNotRegistersEqual(int reg1,
289 int reg2,
290 Label* on_not_equal) {
291 __ mov(eax, register_location(reg1));
292 __ cmp(eax, register_location(reg2));
293 BranchOrBacktrack(not_equal, on_not_equal);
294}
295
296
297void RegExpMacroAssemblerIA32::CheckNotCharacter(uc16 c, Label* on_not_equal) {
298 __ cmp(current_character(), c);
299 BranchOrBacktrack(not_equal, on_not_equal);
300}
301
302
303void RegExpMacroAssemblerIA32::CheckNotCharacterAfterOr(uc16 c,
304 uc16 mask,
305 Label* on_not_equal) {
306 __ mov(eax, current_character());
307 __ or_(eax, mask);
308 __ cmp(eax, c);
309 BranchOrBacktrack(not_equal, on_not_equal);
310}
311
312
313void RegExpMacroAssemblerIA32::CheckNotCharacterAfterMinusOr(
314 uc16 c,
315 uc16 mask,
316 Label* on_not_equal) {
317 __ lea(eax, Operand(current_character(), -mask));
318 __ or_(eax, mask);
319 __ cmp(eax, c);
320 BranchOrBacktrack(not_equal, on_not_equal);
321}
322
323
324void RegExpMacroAssemblerIA32::DispatchHalfNibbleMap(
325 uc16 start,
326 Label* half_nibble_map,
327 const Vector<Label*>& destinations) {
328 UNIMPLEMENTED();
329 __ mov(eax, current_character());
330 __ sub(Operand(eax), Immediate(start));
331
332 __ mov(ecx, eax);
333 __ shr(eax, 2);
334 // FIXME: ecx must hold address of map
335 __ movzx_b(eax, Operand(ecx, eax, times_1, 0));
336 __ and_(ecx, 0x03);
337 __ add(ecx, Operand(ecx));
338 __ shr(eax); // Shift right cl times
339
340 Label second_bit_set, case_3, case_1;
341 __ test(eax, Immediate(0x02));
342 __ j(not_zero, &second_bit_set);
343 __ test(eax, Immediate(0x01));
344 __ j(not_zero, &case_1);
345 // Case 0:
346 __ jmp(destinations[0]);
347 __ bind(&case_1);
348 // Case 1:
349 __ jmp(destinations[1]);
350 __ bind(&second_bit_set);
351 __ test(eax, Immediate(0x01));
352 __ j(not_zero, &case_3);
353 // Case 2
354 __ jmp(destinations[2]);
355 __ bind(&case_3);
356 // Case 3:
357 __ jmp(destinations[3]);
358}
359
360
361void RegExpMacroAssemblerIA32::DispatchByteMap(
362 uc16 start,
363 Label* byte_map,
364 const Vector<Label*>& destinations) {
365 UNIMPLEMENTED();
366
367 Label fallthrough;
368 __ mov(eax, current_character());
369 __ sub(Operand(eax), Immediate(start));
370 __ cmp(eax, 64); // FIXME: 64 = size of map. Found somehow??
371 __ j(greater_equal, &fallthrough);
372 // TODO(lrn): ecx must hold address of map
373 __ movzx_b(eax, Operand(ecx, eax, times_1, 0));
374 // jump table: jump to destinations[eax];
375
376 __ bind(&fallthrough);
377}
378
379
380void RegExpMacroAssemblerIA32::DispatchHighByteMap(
381 byte start,
382 Label* byte_map,
383 const Vector<Label*>& destinations) {
384 UNIMPLEMENTED();
385
386 Label fallthrough;
387 __ mov(eax, current_character());
388 __ shr(eax, 8);
389 __ sub(Operand(eax), Immediate(start));
390 __ cmp(eax, destinations.length() - start);
391 __ j(greater_equal, &fallthrough);
392
393 // TODO(lrn) jumptable: jump to destinations[eax]
394 __ bind(&fallthrough);
395}
396
397
398void RegExpMacroAssemblerIA32::EmitOrLink(Label* label) {
399 UNIMPLEMENTED(); // Has no use.
400}
401
402
403void RegExpMacroAssemblerIA32::Fail() {
404 __ xor_(eax, Operand(eax)); // zero eax.
405 __ jmp(&exit_label_);
406}
407
408
409Handle<Object> RegExpMacroAssemblerIA32::GetCode() {
410 // Finalize code - write the entry point code now we know how many
411 // registers we need.
412
413 // Entry code:
414 __ bind(&entry_label_);
415 // Save callee-save registers. Order here should correspond to order of
416 // kBackup_ebx etc.
417 __ push(esi);
418 __ push(edi);
419 __ push(ebx); // Callee-save on MacOS.
420 __ enter(Immediate(num_registers_ * kPointerSize));
421 // Load string length.
422 __ mov(esi, Operand(ebp, kInputEndOffset));
423 // Load input position.
424 __ mov(edi, Operand(ebp, kInputStartOffset));
425 // Set up edi to be negative offset from string end.
426 __ sub(edi, Operand(esi));
427 // Set up esi to be end of string. First get location.
428 __ mov(edx, Operand(ebp, kInputBuffer));
429 // Dereference location to get string start.
430 __ mov(edx, Operand(edx, 0));
431 // Add start to length to complete esi setup.
432 __ add(esi, Operand(edx));
433 if (num_saved_registers_ > 0) {
434 // Fill saved registers with initial value = start offset - 1
435 __ mov(ecx, -num_saved_registers_);
436 __ mov(eax, Operand(edi));
437 __ sub(Operand(eax), Immediate(char_size()));
438 Label init_loop;
439 __ bind(&init_loop);
440 __ mov(Operand(ebp, ecx, times_4, +0), eax);
441 __ inc(ecx);
442 __ j(not_equal, &init_loop);
443 }
444 // Load previous char as initial value of current-character.
445 Label at_start;
446 __ cmp(Operand(ebp, kAtStart), Immediate(0));
447 __ j(not_equal, &at_start);
448 LoadCurrentCharToRegister(-1); // Load previous char.
449 __ jmp(&start_label_);
450 __ bind(&at_start);
451 __ mov(current_character(), '\n');
452 __ jmp(&start_label_);
453
454
455 // Exit code:
456 // Success
457 __ bind(&success_label_);
458 if (num_saved_registers_ > 0) {
459 // copy captures to output
460 __ mov(ebx, Operand(ebp, kRegisterOutput));
461 __ mov(ecx, Operand(ebp, kInputEndOffset));
462 __ sub(ecx, Operand(ebp, kInputStartOffset));
463 for (int i = 0; i < num_saved_registers_; i++) {
464 __ mov(eax, register_location(i));
465 __ add(eax, Operand(ecx)); // Convert to index from start, not end.
466 if (char_size() > 1) {
467 ASSERT(char_size() == 2);
468 __ sar(eax, 1); // Convert to character index, not byte.
469 }
470 __ mov(Operand(ebx, i * kPointerSize), eax);
471 }
472 }
473 __ mov(eax, Immediate(1));
474
475 // Exit and return eax
476 __ bind(&exit_label_);
477 __ leave();
478 __ pop(ebx);
479 __ pop(edi);
480 __ pop(esi);
481 __ ret(0);
482
483 CodeDesc code_desc;
484 masm_->GetCode(&code_desc);
485 Handle<Code> code = Factory::NewCode(code_desc,
486 NULL,
487 Code::ComputeFlags(Code::REGEXP),
488 self_);
489 LOG(CodeCreateEvent("RegExp", *code, "(Compiled RegExp)"));
490 return Handle<Object>::cast(code);
491}
492
493
494void RegExpMacroAssemblerIA32::GoTo(Label* to) {
495 __ jmp(to);
496}
497
498
499void RegExpMacroAssemblerIA32::IfRegisterGE(int reg,
500 int comparand,
501 Label* if_ge) {
502 __ cmp(register_location(reg), Immediate(comparand));
503 BranchOrBacktrack(greater_equal, if_ge);
504}
505
506
507void RegExpMacroAssemblerIA32::IfRegisterLT(int reg,
508 int comparand,
509 Label* if_lt) {
510 __ cmp(register_location(reg), Immediate(comparand));
511 BranchOrBacktrack(less, if_lt);
512}
513
514
515RegExpMacroAssembler::IrregexpImplementation
516 RegExpMacroAssemblerIA32::Implementation() {
517 return kIA32Implementation;
518}
519
520
521void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset,
522 Label* on_end_of_input) {
523 ASSERT(cp_offset >= 0);
524 ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works)
525 __ cmp(edi, -cp_offset * char_size());
526 BranchOrBacktrack(greater_equal, on_end_of_input);
527 LoadCurrentCharToRegister(cp_offset);
528}
529
530
531void RegExpMacroAssemblerIA32::PopCurrentPosition() {
532 __ pop(edi);
533}
534
535
536void RegExpMacroAssemblerIA32::PopRegister(int register_index) {
537 __ pop(register_location(register_index));
538}
539
540
541void RegExpMacroAssemblerIA32::PushBacktrack(Label* label) {
542 // CheckStackLimit(); // Not ready yet.
543 __ push(label, RelocInfo::NONE);
544}
545
546
547void RegExpMacroAssemblerIA32::PushCurrentPosition() {
548 __ push(edi);
549}
550
551
552void RegExpMacroAssemblerIA32::PushRegister(int register_index) {
553 __ push(register_location(register_index));
554}
555
556
557void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) {
558 __ mov(edi, register_location(reg));
559}
560
561
562void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) {
563 __ mov(esp, register_location(reg));
564}
565
566
567void RegExpMacroAssemblerIA32::SetRegister(int register_index, int to) {
568 ASSERT(register_index >= num_saved_registers_); // Reserved for positions!
569 __ mov(register_location(register_index), Immediate(to));
570}
571
572
573void RegExpMacroAssemblerIA32::Succeed() {
574 __ jmp(&success_label_);
575}
576
577
578void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(int reg) {
579 __ mov(register_location(reg), edi);
580}
581
582void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
583 __ mov(register_location(reg), esp);
584}
585
586
587// Private methods:
588
589Operand RegExpMacroAssemblerIA32::register_location(int register_index) {
590 ASSERT(register_index < (1<<30));
591 if (num_registers_ <= register_index) {
592 num_registers_ = register_index + 1;
593 }
594 return Operand(ebp, -(register_index + 1) * kPointerSize);
595}
596
597
598Register RegExpMacroAssemblerIA32::current_character() {
599 return edx;
600}
601
602
603size_t RegExpMacroAssemblerIA32::char_size() {
604 return static_cast<size_t>(mode_);
605}
606
607
608void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition,
609 Label* to) {
610 if (condition < 0) { // No condition
611 if (to == NULL) {
612 Backtrack();
613 return;
614 }
615 __ jmp(to);
616 return;
617 }
618 if (to == NULL) {
619 Label skip;
620 __ j(NegateCondition(condition), &skip);
621 Backtrack();
622 __ bind(&skip);
623 return;
624 }
625 __ j(condition, to);
626}
627
628
629void RegExpMacroAssemblerIA32::CheckStackLimit() {
630 if (FLAG_check_stack) {
631 // Check for preemption first.
632 Label no_preempt;
633 Label retry_preempt;
634 // Check for preemption.
635 ExternalReference stack_guard_limit =
636 ExternalReference::address_of_stack_guard_limit();
637 __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
638 __ j(above, &no_preempt, taken);
639 __ push(edi); // Current position.
640 __ push(edx); // Current character.
641 // Restore original edi, esi.
642 __ mov(edi, Operand(ebp, kBackup_edi));
643 __ mov(esi, Operand(ebp, kBackup_esi));
644
645 __ bind(&retry_preempt);
646 // simulate stack for Runtime call.
647 __ push(eax);
648 __ push(Immediate(Smi::FromInt(0))); // Dummy receiver
649 __ CallRuntime(Runtime::kStackGuard, 1);
650 __ pop(eax);
651
652 __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
653 __ j(below_equal, &retry_preempt);
654
655 __ pop(edx);
656 __ pop(edi);
657 __ mov(esi, Operand(ebp, kInputBuffer));
658 __ mov(esi, Operand(esi, 0));
659 __ add(esi, Operand(ebp, kInputEndOffset));
660
661 __ bind(&no_preempt);
662 }
663}
664
665
666void RegExpMacroAssemblerIA32::LoadCurrentCharToRegister(int cp_offset) {
667 if (mode_ == ASCII) {
668 __ movzx_b(current_character(), Operand(esi, edi, times_1, cp_offset));
669 return;
670 }
671 ASSERT(mode_ == UC16);
672 __ movzx_w(current_character(),
673 Operand(esi, edi, times_1, cp_offset * sizeof(uc16)));
674}
675
676
677void RegExpMacroAssemblerIA32::LoadConstantBufferAddress(Register reg,
678 ArraySlice* buffer) {
679 __ mov(reg, buffer->array());
680 __ add(Operand(reg), Immediate(buffer->base_offset()));
681}
682
683#undef __
684}} // namespace v8::internal