blob: d9dddd68973c4e41970ddf74feb7bbe7c4280c36 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2008-2009 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 "v8.h"
29#include "unicode.h"
30#include "log.h"
31#include "ast.h"
32#include "regexp-stack.h"
33#include "macro-assembler.h"
34#include "regexp-macro-assembler.h"
35#include "ia32/macro-assembler-ia32.h"
36#include "ia32/regexp-macro-assembler-ia32.h"
37
38namespace v8 {
39namespace internal {
40
Steve Block6ded16b2010-05-10 14:33:55 +010041#ifndef V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +000042/*
43 * This assembler uses the following register assignment convention
44 * - edx : current character. Must be loaded using LoadCurrentCharacter
45 * before using any of the dispatch methods.
46 * - edi : current position in input, as negative offset from end of string.
47 * Please notice that this is the byte offset, not the character offset!
48 * - esi : end of input (points to byte after last character in input).
49 * - ebp : frame pointer. Used to access arguments, local variables and
50 * RegExp registers.
51 * - esp : points to tip of C stack.
52 * - ecx : points to tip of backtrack stack
53 *
Kristian Monsen25f61362010-05-21 11:50:48 +010054 * The registers eax and ebx are free to use for computations.
Steve Blocka7e24c12009-10-30 11:49:00 +000055 *
56 * Each call to a public method should retain this convention.
57 * The stack will have the following structure:
Leon Clarkee46be812010-01-19 14:06:41 +000058 * - direct_call (if 1, direct call from JavaScript code, if 0
59 * call through the runtime system)
60 * - stack_area_base (High end of the memory area to use as
61 * backtracking stack)
Leon Clarkee46be812010-01-19 14:06:41 +000062 * - int* capture_array (int[num_saved_registers_], for output).
63 * - end of input (Address of end of string)
64 * - start of input (Address of first character in string)
65 * - start index (character index of start)
66 * - String* input_string (location of a handle containing the string)
Steve Blocka7e24c12009-10-30 11:49:00 +000067 * --- frame alignment (if applicable) ---
68 * - return address
69 * ebp-> - old ebp
70 * - backup of caller esi
71 * - backup of caller edi
72 * - backup of caller ebx
73 * - Offset of location before start of input (effectively character
74 * position -1). Used to initialize capture registers to a non-position.
75 * - register 0 ebp[-4] (Only positions must be stored in the first
76 * - register 1 ebp[-8] num_saved_registers_ registers)
77 * - ...
78 *
79 * The first num_saved_registers_ registers are initialized to point to
80 * "character -1" in the string (i.e., char_size() bytes before the first
81 * character of the string). The remaining registers starts out as garbage.
82 *
83 * The data up to the return address must be placed there by the calling
84 * code, by calling the code entry as cast to a function with the signature:
85 * int (*match)(String* input_string,
Leon Clarkee46be812010-01-19 14:06:41 +000086 * int start_index,
Steve Blocka7e24c12009-10-30 11:49:00 +000087 * Address start,
88 * Address end,
89 * int* capture_output_array,
90 * bool at_start,
Leon Clarkee46be812010-01-19 14:06:41 +000091 * byte* stack_area_base,
92 * bool direct_call)
Steve Blocka7e24c12009-10-30 11:49:00 +000093 */
94
95#define __ ACCESS_MASM(masm_)
96
97RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(
98 Mode mode,
99 int registers_to_save)
100 : masm_(new MacroAssembler(NULL, kRegExpCodeSize)),
101 mode_(mode),
102 num_registers_(registers_to_save),
103 num_saved_registers_(registers_to_save),
104 entry_label_(),
105 start_label_(),
106 success_label_(),
107 backtrack_label_(),
108 exit_label_() {
109 ASSERT_EQ(0, registers_to_save % 2);
110 __ jmp(&entry_label_); // We'll write the entry code later.
111 __ bind(&start_label_); // And then continue from here.
112}
113
114
115RegExpMacroAssemblerIA32::~RegExpMacroAssemblerIA32() {
116 delete masm_;
117 // Unuse labels in case we throw away the assembler without calling GetCode.
118 entry_label_.Unuse();
119 start_label_.Unuse();
120 success_label_.Unuse();
121 backtrack_label_.Unuse();
122 exit_label_.Unuse();
123 check_preempt_label_.Unuse();
124 stack_overflow_label_.Unuse();
125}
126
127
128int RegExpMacroAssemblerIA32::stack_limit_slack() {
129 return RegExpStack::kStackLimitSlack;
130}
131
132
133void RegExpMacroAssemblerIA32::AdvanceCurrentPosition(int by) {
134 if (by != 0) {
135 Label inside_string;
136 __ add(Operand(edi), Immediate(by * char_size()));
137 }
138}
139
140
141void RegExpMacroAssemblerIA32::AdvanceRegister(int reg, int by) {
142 ASSERT(reg >= 0);
143 ASSERT(reg < num_registers_);
144 if (by != 0) {
145 __ add(register_location(reg), Immediate(by));
146 }
147}
148
149
150void RegExpMacroAssemblerIA32::Backtrack() {
151 CheckPreemption();
152 // Pop Code* offset from backtrack stack, add Code* and jump to location.
153 Pop(ebx);
154 __ add(Operand(ebx), Immediate(masm_->CodeObject()));
155 __ jmp(Operand(ebx));
156}
157
158
159void RegExpMacroAssemblerIA32::Bind(Label* label) {
160 __ bind(label);
161}
162
163
164void RegExpMacroAssemblerIA32::CheckCharacter(uint32_t c, Label* on_equal) {
165 __ cmp(current_character(), c);
166 BranchOrBacktrack(equal, on_equal);
167}
168
169
170void RegExpMacroAssemblerIA32::CheckCharacterGT(uc16 limit, Label* on_greater) {
171 __ cmp(current_character(), limit);
172 BranchOrBacktrack(greater, on_greater);
173}
174
175
176void RegExpMacroAssemblerIA32::CheckAtStart(Label* on_at_start) {
177 Label not_at_start;
178 // Did we start the match at the start of the string at all?
Kristian Monsen25f61362010-05-21 11:50:48 +0100179 __ cmp(Operand(ebp, kStartIndex), Immediate(0));
180 BranchOrBacktrack(not_equal, &not_at_start);
Steve Blocka7e24c12009-10-30 11:49:00 +0000181 // If we did, are we still at the start of the input?
182 __ lea(eax, Operand(esi, edi, times_1, 0));
183 __ cmp(eax, Operand(ebp, kInputStart));
184 BranchOrBacktrack(equal, on_at_start);
185 __ bind(&not_at_start);
186}
187
188
189void RegExpMacroAssemblerIA32::CheckNotAtStart(Label* on_not_at_start) {
190 // Did we start the match at the start of the string at all?
Kristian Monsen25f61362010-05-21 11:50:48 +0100191 __ cmp(Operand(ebp, kStartIndex), Immediate(0));
192 BranchOrBacktrack(not_equal, on_not_at_start);
Steve Blocka7e24c12009-10-30 11:49:00 +0000193 // If we did, are we still at the start of the input?
194 __ lea(eax, Operand(esi, edi, times_1, 0));
195 __ cmp(eax, Operand(ebp, kInputStart));
196 BranchOrBacktrack(not_equal, on_not_at_start);
197}
198
199
200void RegExpMacroAssemblerIA32::CheckCharacterLT(uc16 limit, Label* on_less) {
201 __ cmp(current_character(), limit);
202 BranchOrBacktrack(less, on_less);
203}
204
205
206void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str,
207 int cp_offset,
208 Label* on_failure,
209 bool check_end_of_string) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100210#ifdef DEBUG
211 // If input is ASCII, don't even bother calling here if the string to
212 // match contains a non-ascii character.
213 if (mode_ == ASCII) {
214 for (int i = 0; i < str.length(); i++) {
215 ASSERT(str[i] <= String::kMaxAsciiCharCodeU);
216 }
217 }
218#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000219 int byte_length = str.length() * char_size();
220 int byte_offset = cp_offset * char_size();
221 if (check_end_of_string) {
222 // Check that there are at least str.length() characters left in the input.
223 __ cmp(Operand(edi), Immediate(-(byte_offset + byte_length)));
224 BranchOrBacktrack(greater, on_failure);
225 }
226
227 if (on_failure == NULL) {
228 // Instead of inlining a backtrack, (re)use the global backtrack target.
229 on_failure = &backtrack_label_;
230 }
231
Kristian Monsen25f61362010-05-21 11:50:48 +0100232 // Do one character test first to minimize loading for the case that
233 // we don't match at all (loading more than one character introduces that
234 // chance of reading unaligned and reading across cache boundaries).
235 // If the first character matches, expect a larger chance of matching the
236 // string, and start loading more characters at a time.
237 if (mode_ == ASCII) {
238 __ cmpb(Operand(esi, edi, times_1, byte_offset),
239 static_cast<int8_t>(str[0]));
240 } else {
241 // Don't use 16-bit immediate. The size changing prefix throws off
242 // pre-decoding.
243 __ movzx_w(eax,
244 Operand(esi, edi, times_1, byte_offset));
245 __ cmp(eax, static_cast<int32_t>(str[0]));
246 }
247 BranchOrBacktrack(not_equal, on_failure);
248
249 __ lea(ebx, Operand(esi, edi, times_1, 0));
250 for (int i = 1, n = str.length(); i < n;) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000251 if (mode_ == ASCII) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100252 if (i <= n - 4) {
253 int combined_chars =
254 (static_cast<uint32_t>(str[i + 0]) << 0) |
255 (static_cast<uint32_t>(str[i + 1]) << 8) |
256 (static_cast<uint32_t>(str[i + 2]) << 16) |
257 (static_cast<uint32_t>(str[i + 3]) << 24);
258 __ cmp(Operand(ebx, byte_offset + i), Immediate(combined_chars));
259 i += 4;
260 } else {
261 __ cmpb(Operand(ebx, byte_offset + i),
262 static_cast<int8_t>(str[i]));
263 i += 1;
264 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000265 } else {
266 ASSERT(mode_ == UC16);
Kristian Monsen25f61362010-05-21 11:50:48 +0100267 if (i <= n - 2) {
268 __ cmp(Operand(ebx, byte_offset + i * sizeof(uc16)),
269 Immediate(*reinterpret_cast<const int*>(&str[i])));
270 i += 2;
271 } else {
272 // Avoid a 16-bit immediate operation. It uses the length-changing
273 // 0x66 prefix which causes pre-decoder misprediction and pipeline
274 // stalls. See
275 // "Intel(R) 64 and IA-32 Architectures Optimization Reference Manual"
276 // (248966.pdf) section 3.4.2.3 "Length-Changing Prefixes (LCP)"
277 __ movzx_w(eax,
278 Operand(ebx, byte_offset + i * sizeof(uc16)));
279 __ cmp(eax, static_cast<int32_t>(str[i]));
280 i += 1;
281 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000282 }
283 BranchOrBacktrack(not_equal, on_failure);
284 }
285}
286
287
288void RegExpMacroAssemblerIA32::CheckGreedyLoop(Label* on_equal) {
289 Label fallthrough;
290 __ cmp(edi, Operand(backtrack_stackpointer(), 0));
291 __ j(not_equal, &fallthrough);
292 __ add(Operand(backtrack_stackpointer()), Immediate(kPointerSize)); // Pop.
293 BranchOrBacktrack(no_condition, on_equal);
294 __ bind(&fallthrough);
295}
296
297
298void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
299 int start_reg,
300 Label* on_no_match) {
301 Label fallthrough;
302 __ mov(edx, register_location(start_reg)); // Index of start of capture
303 __ mov(ebx, register_location(start_reg + 1)); // Index of end of capture
304 __ sub(ebx, Operand(edx)); // Length of capture.
305
306 // The length of a capture should not be negative. This can only happen
307 // if the end of the capture is unrecorded, or at a point earlier than
308 // the start of the capture.
309 BranchOrBacktrack(less, on_no_match, not_taken);
310
311 // If length is zero, either the capture is empty or it is completely
312 // uncaptured. In either case succeed immediately.
313 __ j(equal, &fallthrough);
314
315 if (mode_ == ASCII) {
316 Label success;
317 Label fail;
318 Label loop_increment;
319 // Save register contents to make the registers available below.
320 __ push(edi);
321 __ push(backtrack_stackpointer());
322 // After this, the eax, ecx, and edi registers are available.
323
324 __ add(edx, Operand(esi)); // Start of capture
325 __ add(edi, Operand(esi)); // Start of text to match against capture.
326 __ add(ebx, Operand(edi)); // End of text to match against capture.
327
328 Label loop;
329 __ bind(&loop);
330 __ movzx_b(eax, Operand(edi, 0));
331 __ cmpb_al(Operand(edx, 0));
332 __ j(equal, &loop_increment);
333
334 // Mismatch, try case-insensitive match (converting letters to lower-case).
335 __ or_(eax, 0x20); // Convert match character to lower-case.
336 __ lea(ecx, Operand(eax, -'a'));
337 __ cmp(ecx, static_cast<int32_t>('z' - 'a')); // Is eax a lowercase letter?
338 __ j(above, &fail);
339 // Also convert capture character.
340 __ movzx_b(ecx, Operand(edx, 0));
341 __ or_(ecx, 0x20);
342
343 __ cmp(eax, Operand(ecx));
344 __ j(not_equal, &fail);
345
346 __ bind(&loop_increment);
347 // Increment pointers into match and capture strings.
348 __ add(Operand(edx), Immediate(1));
349 __ add(Operand(edi), Immediate(1));
350 // Compare to end of match, and loop if not done.
351 __ cmp(edi, Operand(ebx));
352 __ j(below, &loop, taken);
353 __ jmp(&success);
354
355 __ bind(&fail);
356 // Restore original values before failing.
357 __ pop(backtrack_stackpointer());
358 __ pop(edi);
359 BranchOrBacktrack(no_condition, on_no_match);
360
361 __ bind(&success);
362 // Restore original value before continuing.
363 __ pop(backtrack_stackpointer());
364 // Drop original value of character position.
365 __ add(Operand(esp), Immediate(kPointerSize));
366 // Compute new value of character position after the matched part.
367 __ sub(edi, Operand(esi));
368 } else {
369 ASSERT(mode_ == UC16);
370 // Save registers before calling C function.
371 __ push(esi);
372 __ push(edi);
373 __ push(backtrack_stackpointer());
374 __ push(ebx);
375
Steve Block6ded16b2010-05-10 14:33:55 +0100376 static const int argument_count = 3;
377 __ PrepareCallCFunction(argument_count, ecx);
Steve Blocka7e24c12009-10-30 11:49:00 +0000378 // Put arguments into allocated stack area, last argument highest on stack.
379 // Parameters are
380 // Address byte_offset1 - Address captured substring's start.
381 // Address byte_offset2 - Address of current character position.
382 // size_t byte_length - length of capture in bytes(!)
383
384 // Set byte_length.
385 __ mov(Operand(esp, 2 * kPointerSize), ebx);
386 // Set byte_offset2.
387 // Found by adding negative string-end offset of current position (edi)
388 // to end of string.
389 __ add(edi, Operand(esi));
390 __ mov(Operand(esp, 1 * kPointerSize), edi);
391 // Set byte_offset1.
392 // Start of capture, where edx already holds string-end negative offset.
393 __ add(edx, Operand(esi));
394 __ mov(Operand(esp, 0 * kPointerSize), edx);
395
396 ExternalReference compare =
397 ExternalReference::re_case_insensitive_compare_uc16();
Steve Block6ded16b2010-05-10 14:33:55 +0100398 __ CallCFunction(compare, argument_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000399 // Pop original values before reacting on result value.
400 __ pop(ebx);
401 __ pop(backtrack_stackpointer());
402 __ pop(edi);
403 __ pop(esi);
404
405 // Check if function returned non-zero for success or zero for failure.
406 __ or_(eax, Operand(eax));
407 BranchOrBacktrack(zero, on_no_match);
408 // On success, increment position by length of capture.
409 __ add(edi, Operand(ebx));
410 }
411 __ bind(&fallthrough);
412}
413
414
415void RegExpMacroAssemblerIA32::CheckNotBackReference(
416 int start_reg,
417 Label* on_no_match) {
418 Label fallthrough;
419 Label success;
420 Label fail;
421
422 // Find length of back-referenced capture.
423 __ mov(edx, register_location(start_reg));
424 __ mov(eax, register_location(start_reg + 1));
425 __ sub(eax, Operand(edx)); // Length to check.
426 // Fail on partial or illegal capture (start of capture after end of capture).
427 BranchOrBacktrack(less, on_no_match);
428 // Succeed on empty capture (including no capture)
429 __ j(equal, &fallthrough);
430
431 // Check that there are sufficient characters left in the input.
432 __ mov(ebx, edi);
433 __ add(ebx, Operand(eax));
434 BranchOrBacktrack(greater, on_no_match);
435
436 // Save register to make it available below.
437 __ push(backtrack_stackpointer());
438
439 // Compute pointers to match string and capture string
440 __ lea(ebx, Operand(esi, edi, times_1, 0)); // Start of match.
441 __ add(edx, Operand(esi)); // Start of capture.
442 __ lea(ecx, Operand(eax, ebx, times_1, 0)); // End of match
443
444 Label loop;
445 __ bind(&loop);
446 if (mode_ == ASCII) {
447 __ movzx_b(eax, Operand(edx, 0));
448 __ cmpb_al(Operand(ebx, 0));
449 } else {
450 ASSERT(mode_ == UC16);
451 __ movzx_w(eax, Operand(edx, 0));
452 __ cmpw_ax(Operand(ebx, 0));
453 }
454 __ j(not_equal, &fail);
455 // Increment pointers into capture and match string.
456 __ add(Operand(edx), Immediate(char_size()));
457 __ add(Operand(ebx), Immediate(char_size()));
458 // Check if we have reached end of match area.
459 __ cmp(ebx, Operand(ecx));
460 __ j(below, &loop);
461 __ jmp(&success);
462
463 __ bind(&fail);
464 // Restore backtrack stackpointer.
465 __ pop(backtrack_stackpointer());
466 BranchOrBacktrack(no_condition, on_no_match);
467
468 __ bind(&success);
469 // Move current character position to position after match.
470 __ mov(edi, ecx);
471 __ sub(Operand(edi), esi);
472 // Restore backtrack stackpointer.
473 __ pop(backtrack_stackpointer());
474
475 __ bind(&fallthrough);
476}
477
478
479void RegExpMacroAssemblerIA32::CheckNotRegistersEqual(int reg1,
480 int reg2,
481 Label* on_not_equal) {
482 __ mov(eax, register_location(reg1));
483 __ cmp(eax, register_location(reg2));
484 BranchOrBacktrack(not_equal, on_not_equal);
485}
486
487
488void RegExpMacroAssemblerIA32::CheckNotCharacter(uint32_t c,
489 Label* on_not_equal) {
490 __ cmp(current_character(), c);
491 BranchOrBacktrack(not_equal, on_not_equal);
492}
493
494
495void RegExpMacroAssemblerIA32::CheckCharacterAfterAnd(uint32_t c,
496 uint32_t mask,
497 Label* on_equal) {
498 __ mov(eax, current_character());
499 __ and_(eax, mask);
500 __ cmp(eax, c);
501 BranchOrBacktrack(equal, on_equal);
502}
503
504
505void RegExpMacroAssemblerIA32::CheckNotCharacterAfterAnd(uint32_t c,
506 uint32_t mask,
507 Label* on_not_equal) {
508 __ mov(eax, current_character());
509 __ and_(eax, mask);
510 __ cmp(eax, c);
511 BranchOrBacktrack(not_equal, on_not_equal);
512}
513
514
515void RegExpMacroAssemblerIA32::CheckNotCharacterAfterMinusAnd(
516 uc16 c,
517 uc16 minus,
518 uc16 mask,
519 Label* on_not_equal) {
520 ASSERT(minus < String::kMaxUC16CharCode);
521 __ lea(eax, Operand(current_character(), -minus));
522 __ and_(eax, mask);
523 __ cmp(eax, c);
524 BranchOrBacktrack(not_equal, on_not_equal);
525}
526
527
528bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type,
Steve Blocka7e24c12009-10-30 11:49:00 +0000529 Label* on_no_match) {
530 // Range checks (c in min..max) are generally implemented by an unsigned
531 // (c - min) <= (max - min) check
532 switch (type) {
533 case 's':
534 // Match space-characters
535 if (mode_ == ASCII) {
536 // ASCII space characters are '\t'..'\r' and ' '.
Steve Blocka7e24c12009-10-30 11:49:00 +0000537 Label success;
538 __ cmp(current_character(), ' ');
539 __ j(equal, &success);
540 // Check range 0x09..0x0d
Leon Clarkee46be812010-01-19 14:06:41 +0000541 __ lea(eax, Operand(current_character(), -'\t'));
542 __ cmp(eax, '\r' - '\t');
Steve Blocka7e24c12009-10-30 11:49:00 +0000543 BranchOrBacktrack(above, on_no_match);
544 __ bind(&success);
545 return true;
546 }
547 return false;
548 case 'S':
549 // Match non-space characters.
Steve Blocka7e24c12009-10-30 11:49:00 +0000550 if (mode_ == ASCII) {
551 // ASCII space characters are '\t'..'\r' and ' '.
552 __ cmp(current_character(), ' ');
553 BranchOrBacktrack(equal, on_no_match);
Leon Clarkee46be812010-01-19 14:06:41 +0000554 __ lea(eax, Operand(current_character(), -'\t'));
555 __ cmp(eax, '\r' - '\t');
Steve Blocka7e24c12009-10-30 11:49:00 +0000556 BranchOrBacktrack(below_equal, on_no_match);
557 return true;
558 }
559 return false;
560 case 'd':
561 // Match ASCII digits ('0'..'9')
Leon Clarkee46be812010-01-19 14:06:41 +0000562 __ lea(eax, Operand(current_character(), -'0'));
563 __ cmp(eax, '9' - '0');
Steve Blocka7e24c12009-10-30 11:49:00 +0000564 BranchOrBacktrack(above, on_no_match);
565 return true;
566 case 'D':
567 // Match non ASCII-digits
Leon Clarkee46be812010-01-19 14:06:41 +0000568 __ lea(eax, Operand(current_character(), -'0'));
569 __ cmp(eax, '9' - '0');
Steve Blocka7e24c12009-10-30 11:49:00 +0000570 BranchOrBacktrack(below_equal, on_no_match);
571 return true;
572 case '.': {
573 // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
Leon Clarkee46be812010-01-19 14:06:41 +0000574 __ mov(Operand(eax), current_character());
575 __ xor_(Operand(eax), Immediate(0x01));
Steve Blocka7e24c12009-10-30 11:49:00 +0000576 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
Leon Clarkee46be812010-01-19 14:06:41 +0000577 __ sub(Operand(eax), Immediate(0x0b));
578 __ cmp(eax, 0x0c - 0x0b);
Steve Blocka7e24c12009-10-30 11:49:00 +0000579 BranchOrBacktrack(below_equal, on_no_match);
580 if (mode_ == UC16) {
581 // Compare original value to 0x2028 and 0x2029, using the already
582 // computed (current_char ^ 0x01 - 0x0b). I.e., check for
583 // 0x201d (0x2028 - 0x0b) or 0x201e.
Leon Clarkee46be812010-01-19 14:06:41 +0000584 __ sub(Operand(eax), Immediate(0x2028 - 0x0b));
585 __ cmp(eax, 0x2029 - 0x2028);
Steve Blocka7e24c12009-10-30 11:49:00 +0000586 BranchOrBacktrack(below_equal, on_no_match);
587 }
588 return true;
589 }
Leon Clarkee46be812010-01-19 14:06:41 +0000590 case 'w': {
591 if (mode_ != ASCII) {
592 // Table is 128 entries, so all ASCII characters can be tested.
593 __ cmp(Operand(current_character()), Immediate('z'));
594 BranchOrBacktrack(above, on_no_match);
595 }
596 ASSERT_EQ(0, word_character_map[0]); // Character '\0' is not a word char.
597 ExternalReference word_map = ExternalReference::re_word_character_map();
598 __ test_b(current_character(),
599 Operand::StaticArray(current_character(), times_1, word_map));
600 BranchOrBacktrack(zero, on_no_match);
601 return true;
602 }
603 case 'W': {
604 Label done;
605 if (mode_ != ASCII) {
606 // Table is 128 entries, so all ASCII characters can be tested.
607 __ cmp(Operand(current_character()), Immediate('z'));
608 __ j(above, &done);
609 }
610 ASSERT_EQ(0, word_character_map[0]); // Character '\0' is not a word char.
611 ExternalReference word_map = ExternalReference::re_word_character_map();
612 __ test_b(current_character(),
613 Operand::StaticArray(current_character(), times_1, word_map));
614 BranchOrBacktrack(not_zero, on_no_match);
615 if (mode_ != ASCII) {
616 __ bind(&done);
Steve Blocka7e24c12009-10-30 11:49:00 +0000617 }
618 return true;
Leon Clarkee46be812010-01-19 14:06:41 +0000619 }
620 // Non-standard classes (with no syntactic shorthand) used internally.
621 case '*':
622 // Match any character.
623 return true;
624 case 'n': {
625 // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 or 0x2029).
626 // The opposite of '.'.
627 __ mov(Operand(eax), current_character());
628 __ xor_(Operand(eax), Immediate(0x01));
629 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
630 __ sub(Operand(eax), Immediate(0x0b));
631 __ cmp(eax, 0x0c - 0x0b);
632 if (mode_ == ASCII) {
633 BranchOrBacktrack(above, on_no_match);
634 } else {
635 Label done;
636 BranchOrBacktrack(below_equal, &done);
637 ASSERT_EQ(UC16, mode_);
638 // Compare original value to 0x2028 and 0x2029, using the already
639 // computed (current_char ^ 0x01 - 0x0b). I.e., check for
640 // 0x201d (0x2028 - 0x0b) or 0x201e.
641 __ sub(Operand(eax), Immediate(0x2028 - 0x0b));
642 __ cmp(eax, 1);
643 BranchOrBacktrack(above, on_no_match);
644 __ bind(&done);
645 }
646 return true;
647 }
648 // No custom implementation (yet): s(UC16), S(UC16).
Steve Blocka7e24c12009-10-30 11:49:00 +0000649 default:
650 return false;
651 }
652}
653
654
655void RegExpMacroAssemblerIA32::Fail() {
656 ASSERT(FAILURE == 0); // Return value for failure is zero.
657 __ xor_(eax, Operand(eax)); // zero eax.
658 __ jmp(&exit_label_);
659}
660
661
662Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
663 // Finalize code - write the entry point code now we know how many
664 // registers we need.
665
666 // Entry code:
667 __ bind(&entry_label_);
668 // Start new stack frame.
669 __ push(ebp);
670 __ mov(ebp, esp);
671 // Save callee-save registers. Order here should correspond to order of
672 // kBackup_ebx etc.
673 __ push(esi);
674 __ push(edi);
675 __ push(ebx); // Callee-save on MacOS.
676 __ push(Immediate(0)); // Make room for "input start - 1" constant.
677
678 // Check if we have space on the stack for registers.
679 Label stack_limit_hit;
680 Label stack_ok;
681
Steve Blockd0582a62009-12-15 09:54:21 +0000682 ExternalReference stack_limit =
683 ExternalReference::address_of_stack_limit();
Steve Blocka7e24c12009-10-30 11:49:00 +0000684 __ mov(ecx, esp);
Steve Blockd0582a62009-12-15 09:54:21 +0000685 __ sub(ecx, Operand::StaticVariable(stack_limit));
Steve Blocka7e24c12009-10-30 11:49:00 +0000686 // Handle it if the stack pointer is already below the stack limit.
687 __ j(below_equal, &stack_limit_hit, not_taken);
688 // Check if there is room for the variable number of registers above
689 // the stack limit.
690 __ cmp(ecx, num_registers_ * kPointerSize);
691 __ j(above_equal, &stack_ok, taken);
692 // Exit with OutOfMemory exception. There is not enough space on the stack
693 // for our working registers.
694 __ mov(eax, EXCEPTION);
695 __ jmp(&exit_label_);
696
697 __ bind(&stack_limit_hit);
698 CallCheckStackGuardState(ebx);
699 __ or_(eax, Operand(eax));
700 // If returned value is non-zero, we exit with the returned value as result.
701 __ j(not_zero, &exit_label_);
702
703 __ bind(&stack_ok);
Steve Block6ded16b2010-05-10 14:33:55 +0100704 // Load start index for later use.
705 __ mov(ebx, Operand(ebp, kStartIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +0000706
707 // Allocate space on stack for registers.
708 __ sub(Operand(esp), Immediate(num_registers_ * kPointerSize));
709 // Load string length.
710 __ mov(esi, Operand(ebp, kInputEnd));
711 // Load input position.
712 __ mov(edi, Operand(ebp, kInputStart));
713 // Set up edi to be negative offset from string end.
714 __ sub(edi, Operand(esi));
Steve Block6ded16b2010-05-10 14:33:55 +0100715
716 // Set eax to address of char before start of the string.
Steve Blocka7e24c12009-10-30 11:49:00 +0000717 // (effectively string position -1).
Steve Block6ded16b2010-05-10 14:33:55 +0100718 __ neg(ebx);
719 if (mode_ == UC16) {
720 __ lea(eax, Operand(edi, ebx, times_2, -char_size()));
721 } else {
722 __ lea(eax, Operand(edi, ebx, times_1, -char_size()));
723 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000724 // Store this value in a local variable, for use when clearing
725 // position registers.
726 __ mov(Operand(ebp, kInputStartMinusOne), eax);
Leon Clarked91b9f72010-01-27 17:25:45 +0000727
Steve Blocka7e24c12009-10-30 11:49:00 +0000728 if (num_saved_registers_ > 0) { // Always is, if generated from a regexp.
729 // Fill saved registers with initial value = start offset - 1
730 // Fill in stack push order, to avoid accessing across an unwritten
731 // page (a problem on Windows).
732 __ mov(ecx, kRegisterZero);
733 Label init_loop;
734 __ bind(&init_loop);
735 __ mov(Operand(ebp, ecx, times_1, +0), eax);
736 __ sub(Operand(ecx), Immediate(kPointerSize));
737 __ cmp(ecx, kRegisterZero - num_saved_registers_ * kPointerSize);
738 __ j(greater, &init_loop);
739 }
740 // Ensure that we have written to each stack page, in order. Skipping a page
741 // on Windows can cause segmentation faults. Assuming page size is 4k.
742 const int kPageSize = 4096;
743 const int kRegistersPerPage = kPageSize / kPointerSize;
744 for (int i = num_saved_registers_ + kRegistersPerPage - 1;
745 i < num_registers_;
746 i += kRegistersPerPage) {
747 __ mov(register_location(i), eax); // One write every page.
748 }
749
750
751 // Initialize backtrack stack pointer.
752 __ mov(backtrack_stackpointer(), Operand(ebp, kStackHighEnd));
753 // Load previous char as initial value of current-character.
754 Label at_start;
Kristian Monsen25f61362010-05-21 11:50:48 +0100755 __ cmp(Operand(ebp, kStartIndex), Immediate(0));
756 __ j(equal, &at_start);
Steve Blocka7e24c12009-10-30 11:49:00 +0000757 LoadCurrentCharacterUnchecked(-1, 1); // Load previous char.
758 __ jmp(&start_label_);
759 __ bind(&at_start);
760 __ mov(current_character(), '\n');
761 __ jmp(&start_label_);
762
763
764 // Exit code:
765 if (success_label_.is_linked()) {
766 // Save captures when successful.
767 __ bind(&success_label_);
768 if (num_saved_registers_ > 0) {
769 // copy captures to output
770 __ mov(ebx, Operand(ebp, kRegisterOutput));
771 __ mov(ecx, Operand(ebp, kInputEnd));
Steve Block6ded16b2010-05-10 14:33:55 +0100772 __ mov(edx, Operand(ebp, kStartIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +0000773 __ sub(ecx, Operand(ebp, kInputStart));
Steve Block6ded16b2010-05-10 14:33:55 +0100774 if (mode_ == UC16) {
775 __ lea(ecx, Operand(ecx, edx, times_2, 0));
776 } else {
777 __ add(ecx, Operand(edx));
778 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000779 for (int i = 0; i < num_saved_registers_; i++) {
780 __ mov(eax, register_location(i));
Steve Block6ded16b2010-05-10 14:33:55 +0100781 // Convert to index from start of string, not end.
782 __ add(eax, Operand(ecx));
Steve Blocka7e24c12009-10-30 11:49:00 +0000783 if (mode_ == UC16) {
784 __ sar(eax, 1); // Convert byte index to character index.
785 }
786 __ mov(Operand(ebx, i * kPointerSize), eax);
787 }
788 }
789 __ mov(eax, Immediate(SUCCESS));
790 }
791 // Exit and return eax
792 __ bind(&exit_label_);
793 // Skip esp past regexp registers.
794 __ lea(esp, Operand(ebp, kBackup_ebx));
795 // Restore callee-save registers.
796 __ pop(ebx);
797 __ pop(edi);
798 __ pop(esi);
799 // Exit function frame, restore previous one.
800 __ pop(ebp);
801 __ ret(0);
802
803 // Backtrack code (branch target for conditional backtracks).
804 if (backtrack_label_.is_linked()) {
805 __ bind(&backtrack_label_);
806 Backtrack();
807 }
808
809 Label exit_with_exception;
810
811 // Preempt-code
812 if (check_preempt_label_.is_linked()) {
813 SafeCallTarget(&check_preempt_label_);
814
815 __ push(backtrack_stackpointer());
816 __ push(edi);
817
818 CallCheckStackGuardState(ebx);
819 __ or_(eax, Operand(eax));
820 // If returning non-zero, we should end execution with the given
821 // result as return value.
822 __ j(not_zero, &exit_label_);
823
824 __ pop(edi);
825 __ pop(backtrack_stackpointer());
826 // String might have moved: Reload esi from frame.
827 __ mov(esi, Operand(ebp, kInputEnd));
828 SafeReturn();
829 }
830
831 // Backtrack stack overflow code.
832 if (stack_overflow_label_.is_linked()) {
833 SafeCallTarget(&stack_overflow_label_);
834 // Reached if the backtrack-stack limit has been hit.
835
836 Label grow_failed;
837 // Save registers before calling C function
838 __ push(esi);
839 __ push(edi);
840
841 // Call GrowStack(backtrack_stackpointer())
Steve Block6ded16b2010-05-10 14:33:55 +0100842 static const int num_arguments = 2;
843 __ PrepareCallCFunction(num_arguments, ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +0000844 __ lea(eax, Operand(ebp, kStackHighEnd));
845 __ mov(Operand(esp, 1 * kPointerSize), eax);
846 __ mov(Operand(esp, 0 * kPointerSize), backtrack_stackpointer());
847 ExternalReference grow_stack = ExternalReference::re_grow_stack();
Steve Block6ded16b2010-05-10 14:33:55 +0100848 __ CallCFunction(grow_stack, num_arguments);
Steve Blocka7e24c12009-10-30 11:49:00 +0000849 // If return NULL, we have failed to grow the stack, and
850 // must exit with a stack-overflow exception.
851 __ or_(eax, Operand(eax));
852 __ j(equal, &exit_with_exception);
853 // Otherwise use return value as new stack pointer.
854 __ mov(backtrack_stackpointer(), eax);
855 // Restore saved registers and continue.
856 __ pop(edi);
857 __ pop(esi);
858 SafeReturn();
859 }
860
861 if (exit_with_exception.is_linked()) {
862 // If any of the code above needed to exit with an exception.
863 __ bind(&exit_with_exception);
864 // Exit with Result EXCEPTION(-1) to signal thrown exception.
865 __ mov(eax, EXCEPTION);
866 __ jmp(&exit_label_);
867 }
868
869 CodeDesc code_desc;
870 masm_->GetCode(&code_desc);
871 Handle<Code> code = Factory::NewCode(code_desc,
872 NULL,
873 Code::ComputeFlags(Code::REGEXP),
874 masm_->CodeObject());
Steve Block6ded16b2010-05-10 14:33:55 +0100875 PROFILE(RegExpCodeCreateEvent(*code, *source));
Steve Blocka7e24c12009-10-30 11:49:00 +0000876 return Handle<Object>::cast(code);
877}
878
879
880void RegExpMacroAssemblerIA32::GoTo(Label* to) {
881 BranchOrBacktrack(no_condition, to);
882}
883
884
885void RegExpMacroAssemblerIA32::IfRegisterGE(int reg,
886 int comparand,
887 Label* if_ge) {
888 __ cmp(register_location(reg), Immediate(comparand));
889 BranchOrBacktrack(greater_equal, if_ge);
890}
891
892
893void RegExpMacroAssemblerIA32::IfRegisterLT(int reg,
894 int comparand,
895 Label* if_lt) {
896 __ cmp(register_location(reg), Immediate(comparand));
897 BranchOrBacktrack(less, if_lt);
898}
899
900
901void RegExpMacroAssemblerIA32::IfRegisterEqPos(int reg,
902 Label* if_eq) {
903 __ cmp(edi, register_location(reg));
904 BranchOrBacktrack(equal, if_eq);
905}
906
907
908RegExpMacroAssembler::IrregexpImplementation
909 RegExpMacroAssemblerIA32::Implementation() {
910 return kIA32Implementation;
911}
912
913
914void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset,
915 Label* on_end_of_input,
916 bool check_bounds,
917 int characters) {
918 ASSERT(cp_offset >= -1); // ^ and \b can look behind one character.
919 ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works)
920 if (check_bounds) {
921 CheckPosition(cp_offset + characters - 1, on_end_of_input);
922 }
923 LoadCurrentCharacterUnchecked(cp_offset, characters);
924}
925
926
927void RegExpMacroAssemblerIA32::PopCurrentPosition() {
928 Pop(edi);
929}
930
931
932void RegExpMacroAssemblerIA32::PopRegister(int register_index) {
933 Pop(eax);
934 __ mov(register_location(register_index), eax);
935}
936
937
938void RegExpMacroAssemblerIA32::PushBacktrack(Label* label) {
939 Push(Immediate::CodeRelativeOffset(label));
940 CheckStackLimit();
941}
942
943
944void RegExpMacroAssemblerIA32::PushCurrentPosition() {
945 Push(edi);
946}
947
948
949void RegExpMacroAssemblerIA32::PushRegister(int register_index,
950 StackCheckFlag check_stack_limit) {
951 __ mov(eax, register_location(register_index));
952 Push(eax);
953 if (check_stack_limit) CheckStackLimit();
954}
955
956
957void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) {
958 __ mov(edi, register_location(reg));
959}
960
961
962void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) {
963 __ mov(backtrack_stackpointer(), register_location(reg));
964 __ add(backtrack_stackpointer(), Operand(ebp, kStackHighEnd));
965}
966
967
968void RegExpMacroAssemblerIA32::SetRegister(int register_index, int to) {
969 ASSERT(register_index >= num_saved_registers_); // Reserved for positions!
970 __ mov(register_location(register_index), Immediate(to));
971}
972
973
974void RegExpMacroAssemblerIA32::Succeed() {
975 __ jmp(&success_label_);
976}
977
978
979void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(int reg,
980 int cp_offset) {
981 if (cp_offset == 0) {
982 __ mov(register_location(reg), edi);
983 } else {
984 __ lea(eax, Operand(edi, cp_offset * char_size()));
985 __ mov(register_location(reg), eax);
986 }
987}
988
989
990void RegExpMacroAssemblerIA32::ClearRegisters(int reg_from, int reg_to) {
991 ASSERT(reg_from <= reg_to);
992 __ mov(eax, Operand(ebp, kInputStartMinusOne));
993 for (int reg = reg_from; reg <= reg_to; reg++) {
994 __ mov(register_location(reg), eax);
995 }
996}
997
998
999void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
1000 __ mov(eax, backtrack_stackpointer());
1001 __ sub(eax, Operand(ebp, kStackHighEnd));
1002 __ mov(register_location(reg), eax);
1003}
1004
1005
1006// Private methods:
1007
1008void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) {
Steve Block6ded16b2010-05-10 14:33:55 +01001009 static const int num_arguments = 3;
1010 __ PrepareCallCFunction(num_arguments, scratch);
Steve Blocka7e24c12009-10-30 11:49:00 +00001011 // RegExp code frame pointer.
1012 __ mov(Operand(esp, 2 * kPointerSize), ebp);
1013 // Code* of self.
1014 __ mov(Operand(esp, 1 * kPointerSize), Immediate(masm_->CodeObject()));
1015 // Next address on the stack (will be address of return address).
1016 __ lea(eax, Operand(esp, -kPointerSize));
1017 __ mov(Operand(esp, 0 * kPointerSize), eax);
1018 ExternalReference check_stack_guard =
1019 ExternalReference::re_check_stack_guard_state();
Steve Block6ded16b2010-05-10 14:33:55 +01001020 __ CallCFunction(check_stack_guard, num_arguments);
Steve Blocka7e24c12009-10-30 11:49:00 +00001021}
1022
1023
1024// Helper function for reading a value out of a stack frame.
1025template <typename T>
1026static T& frame_entry(Address re_frame, int frame_offset) {
1027 return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset));
1028}
1029
1030
1031int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
1032 Code* re_code,
1033 Address re_frame) {
1034 if (StackGuard::IsStackOverflow()) {
1035 Top::StackOverflow();
1036 return EXCEPTION;
1037 }
1038
1039 // If not real stack overflow the stack guard was used to interrupt
1040 // execution for another purpose.
1041
Leon Clarkee46be812010-01-19 14:06:41 +00001042 // If this is a direct call from JavaScript retry the RegExp forcing the call
1043 // through the runtime system. Currently the direct call cannot handle a GC.
1044 if (frame_entry<int>(re_frame, kDirectCall) == 1) {
1045 return RETRY;
1046 }
1047
Steve Blocka7e24c12009-10-30 11:49:00 +00001048 // Prepare for possible GC.
1049 HandleScope handles;
1050 Handle<Code> code_handle(re_code);
1051
1052 Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
1053 // Current string.
1054 bool is_ascii = subject->IsAsciiRepresentation();
1055
1056 ASSERT(re_code->instruction_start() <= *return_address);
1057 ASSERT(*return_address <=
1058 re_code->instruction_start() + re_code->instruction_size());
1059
1060 Object* result = Execution::HandleStackGuardInterrupt();
1061
1062 if (*code_handle != re_code) { // Return address no longer valid
1063 int delta = *code_handle - re_code;
1064 // Overwrite the return address on the stack.
1065 *return_address += delta;
1066 }
1067
1068 if (result->IsException()) {
1069 return EXCEPTION;
1070 }
1071
1072 // String might have changed.
1073 if (subject->IsAsciiRepresentation() != is_ascii) {
1074 // If we changed between an ASCII and an UC16 string, the specialized
1075 // code cannot be used, and we need to restart regexp matching from
1076 // scratch (including, potentially, compiling a new version of the code).
1077 return RETRY;
1078 }
1079
1080 // Otherwise, the content of the string might have moved. It must still
1081 // be a sequential or external string with the same content.
1082 // Update the start and end pointers in the stack frame to the current
1083 // location (whether it has actually moved or not).
1084 ASSERT(StringShape(*subject).IsSequential() ||
1085 StringShape(*subject).IsExternal());
1086
1087 // The original start address of the characters to match.
1088 const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
1089
1090 // Find the current start address of the same character at the current string
1091 // position.
1092 int start_index = frame_entry<int>(re_frame, kStartIndex);
1093 const byte* new_address = StringCharacterPosition(*subject, start_index);
1094
1095 if (start_address != new_address) {
1096 // If there is a difference, update the object pointer and start and end
1097 // addresses in the RegExp stack frame to match the new value.
1098 const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
1099 int byte_length = end_address - start_address;
1100 frame_entry<const String*>(re_frame, kInputString) = *subject;
1101 frame_entry<const byte*>(re_frame, kInputStart) = new_address;
1102 frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
1103 }
1104
1105 return 0;
1106}
1107
1108
1109Operand RegExpMacroAssemblerIA32::register_location(int register_index) {
1110 ASSERT(register_index < (1<<30));
1111 if (num_registers_ <= register_index) {
1112 num_registers_ = register_index + 1;
1113 }
1114 return Operand(ebp, kRegisterZero - register_index * kPointerSize);
1115}
1116
1117
1118void RegExpMacroAssemblerIA32::CheckPosition(int cp_offset,
1119 Label* on_outside_input) {
1120 __ cmp(edi, -cp_offset * char_size());
1121 BranchOrBacktrack(greater_equal, on_outside_input);
1122}
1123
1124
1125void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition,
1126 Label* to,
1127 Hint hint) {
1128 if (condition < 0) { // No condition
1129 if (to == NULL) {
1130 Backtrack();
1131 return;
1132 }
1133 __ jmp(to);
1134 return;
1135 }
1136 if (to == NULL) {
1137 __ j(condition, &backtrack_label_, hint);
1138 return;
1139 }
1140 __ j(condition, to, hint);
1141}
1142
1143
1144void RegExpMacroAssemblerIA32::SafeCall(Label* to) {
Steve Block6ded16b2010-05-10 14:33:55 +01001145 Label return_to;
1146 __ push(Immediate::CodeRelativeOffset(&return_to));
1147 __ jmp(to);
1148 __ bind(&return_to);
Steve Blocka7e24c12009-10-30 11:49:00 +00001149}
1150
1151
1152void RegExpMacroAssemblerIA32::SafeReturn() {
Steve Block6ded16b2010-05-10 14:33:55 +01001153 __ pop(ebx);
1154 __ add(Operand(ebx), Immediate(masm_->CodeObject()));
1155 __ jmp(Operand(ebx));
Steve Blocka7e24c12009-10-30 11:49:00 +00001156}
1157
1158
1159void RegExpMacroAssemblerIA32::SafeCallTarget(Label* name) {
1160 __ bind(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001161}
1162
1163
1164void RegExpMacroAssemblerIA32::Push(Register source) {
1165 ASSERT(!source.is(backtrack_stackpointer()));
1166 // Notice: This updates flags, unlike normal Push.
1167 __ sub(Operand(backtrack_stackpointer()), Immediate(kPointerSize));
1168 __ mov(Operand(backtrack_stackpointer(), 0), source);
1169}
1170
1171
1172void RegExpMacroAssemblerIA32::Push(Immediate value) {
1173 // Notice: This updates flags, unlike normal Push.
1174 __ sub(Operand(backtrack_stackpointer()), Immediate(kPointerSize));
1175 __ mov(Operand(backtrack_stackpointer(), 0), value);
1176}
1177
1178
1179void RegExpMacroAssemblerIA32::Pop(Register target) {
1180 ASSERT(!target.is(backtrack_stackpointer()));
1181 __ mov(target, Operand(backtrack_stackpointer(), 0));
1182 // Notice: This updates flags, unlike normal Pop.
1183 __ add(Operand(backtrack_stackpointer()), Immediate(kPointerSize));
1184}
1185
1186
1187void RegExpMacroAssemblerIA32::CheckPreemption() {
1188 // Check for preemption.
1189 Label no_preempt;
Steve Blockd0582a62009-12-15 09:54:21 +00001190 ExternalReference stack_limit =
1191 ExternalReference::address_of_stack_limit();
1192 __ cmp(esp, Operand::StaticVariable(stack_limit));
Steve Blocka7e24c12009-10-30 11:49:00 +00001193 __ j(above, &no_preempt, taken);
1194
1195 SafeCall(&check_preempt_label_);
1196
1197 __ bind(&no_preempt);
1198}
1199
1200
1201void RegExpMacroAssemblerIA32::CheckStackLimit() {
Steve Blockd0582a62009-12-15 09:54:21 +00001202 Label no_stack_overflow;
1203 ExternalReference stack_limit =
1204 ExternalReference::address_of_regexp_stack_limit();
1205 __ cmp(backtrack_stackpointer(), Operand::StaticVariable(stack_limit));
1206 __ j(above, &no_stack_overflow);
Steve Blocka7e24c12009-10-30 11:49:00 +00001207
Steve Blockd0582a62009-12-15 09:54:21 +00001208 SafeCall(&stack_overflow_label_);
Steve Blocka7e24c12009-10-30 11:49:00 +00001209
Steve Blockd0582a62009-12-15 09:54:21 +00001210 __ bind(&no_stack_overflow);
Steve Blocka7e24c12009-10-30 11:49:00 +00001211}
1212
1213
Steve Blocka7e24c12009-10-30 11:49:00 +00001214void RegExpMacroAssemblerIA32::LoadCurrentCharacterUnchecked(int cp_offset,
1215 int characters) {
1216 if (mode_ == ASCII) {
1217 if (characters == 4) {
1218 __ mov(current_character(), Operand(esi, edi, times_1, cp_offset));
1219 } else if (characters == 2) {
1220 __ movzx_w(current_character(), Operand(esi, edi, times_1, cp_offset));
1221 } else {
1222 ASSERT(characters == 1);
1223 __ movzx_b(current_character(), Operand(esi, edi, times_1, cp_offset));
1224 }
1225 } else {
1226 ASSERT(mode_ == UC16);
1227 if (characters == 2) {
1228 __ mov(current_character(),
1229 Operand(esi, edi, times_1, cp_offset * sizeof(uc16)));
1230 } else {
1231 ASSERT(characters == 1);
1232 __ movzx_w(current_character(),
1233 Operand(esi, edi, times_1, cp_offset * sizeof(uc16)));
1234 }
1235 }
1236}
1237
1238
Steve Blocka7e24c12009-10-30 11:49:00 +00001239#undef __
1240
Steve Block6ded16b2010-05-10 14:33:55 +01001241#endif // V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +00001242
1243}} // namespace v8::internal