blob: d635fe1a8a5a7d457d6950f9f9269080824bfae8 [file] [log] [blame]
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001// Copyright 2012 the V8 project authors. All rights reserved.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002// 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
ager@chromium.orga74f0da2008-12-03 16:05:52 +000028#include "v8.h"
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000029
30#if defined(V8_TARGET_ARCH_IA32)
31
ager@chromium.org8bb60582008-12-11 12:02:20 +000032#include "unicode.h"
ager@chromium.orga74f0da2008-12-03 16:05:52 +000033#include "log.h"
ager@chromium.org32912102009-01-16 10:38:43 +000034#include "regexp-stack.h"
ager@chromium.orga74f0da2008-12-03 16:05:52 +000035#include "macro-assembler.h"
36#include "regexp-macro-assembler.h"
ager@chromium.org3a37e9b2009-04-27 09:26:21 +000037#include "ia32/regexp-macro-assembler-ia32.h"
ager@chromium.orga74f0da2008-12-03 16:05:52 +000038
kasperl@chromium.org71affb52009-05-26 05:44:31 +000039namespace v8 {
40namespace internal {
ager@chromium.orga74f0da2008-12-03 16:05:52 +000041
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000042#ifndef V8_INTERPRETED_REGEXP
ager@chromium.orga74f0da2008-12-03 16:05:52 +000043/*
44 * This assembler uses the following register assignment convention
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +000045 * - edx : Current character. Must be loaded using LoadCurrentCharacter
46 * before using any of the dispatch methods. Temporarily stores the
47 * index of capture start after a matching pass for a global regexp.
48 * - edi : Current position in input, as negative offset from end of string.
ager@chromium.orga74f0da2008-12-03 16:05:52 +000049 * Please notice that this is the byte offset, not the character offset!
50 * - esi : end of input (points to byte after last character in input).
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +000051 * - ebp : Frame pointer. Used to access arguments, local variables and
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000052 * RegExp registers.
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +000053 * - esp : Points to tip of C stack.
54 * - ecx : Points to tip of backtrack stack
ager@chromium.orga74f0da2008-12-03 16:05:52 +000055 *
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +000056 * The registers eax and ebx are free to use for computations.
ager@chromium.orga74f0da2008-12-03 16:05:52 +000057 *
58 * Each call to a public method should retain this convention.
59 * The stack will have the following structure:
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +000060 * - Isolate* isolate (address of the current isolate)
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000061 * - direct_call (if 1, direct call from JavaScript code, if 0
62 * call through the runtime system)
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +000063 * - stack_area_base (high end of the memory area to use as
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000064 * backtracking stack)
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +000065 * - capture array size (may fit multiple sets of matches)
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000066 * - int* capture_array (int[num_saved_registers_], for output).
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +000067 * - end of input (address of end of string)
68 * - start of input (address of first character in string)
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000069 * - start index (character index of start)
70 * - String* input_string (location of a handle containing the string)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000071 * --- frame alignment (if applicable) ---
ager@chromium.orga74f0da2008-12-03 16:05:52 +000072 * - return address
ager@chromium.orga74f0da2008-12-03 16:05:52 +000073 * ebp-> - old ebp
ager@chromium.org32912102009-01-16 10:38:43 +000074 * - backup of caller esi
75 * - backup of caller edi
76 * - backup of caller ebx
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +000077 * - success counter (only for global regexps to count matches).
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000078 * - Offset of location before start of input (effectively character
79 * position -1). Used to initialize capture registers to a non-position.
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +000080 * - register 0 ebp[-4] (only positions must be stored in the first
ager@chromium.orga74f0da2008-12-03 16:05:52 +000081 * - register 1 ebp[-8] num_saved_registers_ registers)
82 * - ...
83 *
84 * The first num_saved_registers_ registers are initialized to point to
85 * "character -1" in the string (i.e., char_size() bytes before the first
86 * character of the string). The remaining registers starts out as garbage.
87 *
88 * The data up to the return address must be placed there by the calling
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000089 * code, by calling the code entry as cast to a function with the signature:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000090 * int (*match)(String* input_string,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000091 * int start_index,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000092 * Address start,
93 * Address end,
94 * int* capture_output_array,
95 * bool at_start,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000096 * byte* stack_area_base,
97 * bool direct_call)
ager@chromium.orga74f0da2008-12-03 16:05:52 +000098 */
99
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000100#define __ ACCESS_MASM(masm_)
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000101
102RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(
103 Mode mode,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000104 int registers_to_save,
105 Zone* zone)
106 : NativeRegExpMacroAssembler(zone),
107 masm_(new MacroAssembler(Isolate::Current(), NULL, kRegExpCodeSize)),
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000108 mode_(mode),
109 num_registers_(registers_to_save),
110 num_saved_registers_(registers_to_save),
111 entry_label_(),
112 start_label_(),
113 success_label_(),
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000114 backtrack_label_(),
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000115 exit_label_() {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000116 ASSERT_EQ(0, registers_to_save % 2);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000117 __ jmp(&entry_label_); // We'll write the entry code later.
118 __ bind(&start_label_); // And then continue from here.
119}
120
121
122RegExpMacroAssemblerIA32::~RegExpMacroAssemblerIA32() {
123 delete masm_;
124 // Unuse labels in case we throw away the assembler without calling GetCode.
125 entry_label_.Unuse();
126 start_label_.Unuse();
127 success_label_.Unuse();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000128 backtrack_label_.Unuse();
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000129 exit_label_.Unuse();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000130 check_preempt_label_.Unuse();
ager@chromium.org32912102009-01-16 10:38:43 +0000131 stack_overflow_label_.Unuse();
132}
133
134
135int RegExpMacroAssemblerIA32::stack_limit_slack() {
136 return RegExpStack::kStackLimitSlack;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000137}
138
139
140void RegExpMacroAssemblerIA32::AdvanceCurrentPosition(int by) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000141 if (by != 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000142 __ add(edi, Immediate(by * char_size()));
ager@chromium.org8bb60582008-12-11 12:02:20 +0000143 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000144}
145
146
147void RegExpMacroAssemblerIA32::AdvanceRegister(int reg, int by) {
148 ASSERT(reg >= 0);
149 ASSERT(reg < num_registers_);
ager@chromium.org32912102009-01-16 10:38:43 +0000150 if (by != 0) {
151 __ add(register_location(reg), Immediate(by));
152 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000153}
154
155
156void RegExpMacroAssemblerIA32::Backtrack() {
ager@chromium.org32912102009-01-16 10:38:43 +0000157 CheckPreemption();
158 // Pop Code* offset from backtrack stack, add Code* and jump to location.
159 Pop(ebx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000160 __ add(ebx, Immediate(masm_->CodeObject()));
161 __ jmp(ebx);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000162}
163
164
165void RegExpMacroAssemblerIA32::Bind(Label* label) {
166 __ bind(label);
167}
168
ager@chromium.org32912102009-01-16 10:38:43 +0000169
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000170void RegExpMacroAssemblerIA32::CheckCharacter(uint32_t c, Label* on_equal) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000171 __ cmp(current_character(), c);
172 BranchOrBacktrack(equal, on_equal);
173}
174
175
176void RegExpMacroAssemblerIA32::CheckCharacterGT(uc16 limit, Label* on_greater) {
177 __ cmp(current_character(), limit);
178 BranchOrBacktrack(greater, on_greater);
179}
180
181
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000182void RegExpMacroAssemblerIA32::CheckAtStart(Label* on_at_start) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000183 Label not_at_start;
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000184 // Did we start the match at the start of the string at all?
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000185 __ cmp(Operand(ebp, kStartIndex), Immediate(0));
186 BranchOrBacktrack(not_equal, &not_at_start);
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000187 // If we did, are we still at the start of the input?
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000188 __ lea(eax, Operand(esi, edi, times_1, 0));
189 __ cmp(eax, Operand(ebp, kInputStart));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000190 BranchOrBacktrack(equal, on_at_start);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000191 __ bind(&not_at_start);
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000192}
193
194
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000195void RegExpMacroAssemblerIA32::CheckNotAtStart(Label* on_not_at_start) {
ager@chromium.org32912102009-01-16 10:38:43 +0000196 // Did we start the match at the start of the string at all?
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000197 __ cmp(Operand(ebp, kStartIndex), Immediate(0));
198 BranchOrBacktrack(not_equal, on_not_at_start);
ager@chromium.org32912102009-01-16 10:38:43 +0000199 // If we did, are we still at the start of the input?
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000200 __ lea(eax, Operand(esi, edi, times_1, 0));
201 __ cmp(eax, Operand(ebp, kInputStart));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000202 BranchOrBacktrack(not_equal, on_not_at_start);
203}
204
205
206void RegExpMacroAssemblerIA32::CheckCharacterLT(uc16 limit, Label* on_less) {
207 __ cmp(current_character(), limit);
208 BranchOrBacktrack(less, on_less);
209}
210
211
212void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str,
213 int cp_offset,
ager@chromium.org8bb60582008-12-11 12:02:20 +0000214 Label* on_failure,
215 bool check_end_of_string) {
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000216#ifdef DEBUG
217 // If input is ASCII, don't even bother calling here if the string to
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000218 // match contains a non-ASCII character.
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000219 if (mode_ == ASCII) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000220 ASSERT(String::IsOneByte(str.start(), str.length()));
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000221 }
222#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000223 int byte_length = str.length() * char_size();
224 int byte_offset = cp_offset * char_size();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000225 if (check_end_of_string) {
ager@chromium.org32912102009-01-16 10:38:43 +0000226 // Check that there are at least str.length() characters left in the input.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000227 __ cmp(edi, Immediate(-(byte_offset + byte_length)));
ager@chromium.org8bb60582008-12-11 12:02:20 +0000228 BranchOrBacktrack(greater, on_failure);
229 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000230
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000231 if (on_failure == NULL) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000232 // Instead of inlining a backtrack, (re)use the global backtrack target.
233 on_failure = &backtrack_label_;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000234 }
235
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000236 // Do one character test first to minimize loading for the case that
237 // we don't match at all (loading more than one character introduces that
238 // chance of reading unaligned and reading across cache boundaries).
239 // If the first character matches, expect a larger chance of matching the
240 // string, and start loading more characters at a time.
241 if (mode_ == ASCII) {
242 __ cmpb(Operand(esi, edi, times_1, byte_offset),
243 static_cast<int8_t>(str[0]));
244 } else {
245 // Don't use 16-bit immediate. The size changing prefix throws off
246 // pre-decoding.
247 __ movzx_w(eax,
248 Operand(esi, edi, times_1, byte_offset));
249 __ cmp(eax, static_cast<int32_t>(str[0]));
250 }
251 BranchOrBacktrack(not_equal, on_failure);
252
253 __ lea(ebx, Operand(esi, edi, times_1, 0));
254 for (int i = 1, n = str.length(); i < n;) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000255 if (mode_ == ASCII) {
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000256 if (i <= n - 4) {
257 int combined_chars =
258 (static_cast<uint32_t>(str[i + 0]) << 0) |
259 (static_cast<uint32_t>(str[i + 1]) << 8) |
260 (static_cast<uint32_t>(str[i + 2]) << 16) |
261 (static_cast<uint32_t>(str[i + 3]) << 24);
262 __ cmp(Operand(ebx, byte_offset + i), Immediate(combined_chars));
263 i += 4;
264 } else {
265 __ cmpb(Operand(ebx, byte_offset + i),
266 static_cast<int8_t>(str[i]));
267 i += 1;
268 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000269 } else {
270 ASSERT(mode_ == UC16);
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000271 if (i <= n - 2) {
272 __ cmp(Operand(ebx, byte_offset + i * sizeof(uc16)),
273 Immediate(*reinterpret_cast<const int*>(&str[i])));
274 i += 2;
275 } else {
276 // Avoid a 16-bit immediate operation. It uses the length-changing
277 // 0x66 prefix which causes pre-decoder misprediction and pipeline
278 // stalls. See
279 // "Intel(R) 64 and IA-32 Architectures Optimization Reference Manual"
280 // (248966.pdf) section 3.4.2.3 "Length-Changing Prefixes (LCP)"
281 __ movzx_w(eax,
282 Operand(ebx, byte_offset + i * sizeof(uc16)));
283 __ cmp(eax, static_cast<int32_t>(str[i]));
284 i += 1;
285 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000286 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000287 BranchOrBacktrack(not_equal, on_failure);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000288 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000289}
290
291
ager@chromium.org8bb60582008-12-11 12:02:20 +0000292void RegExpMacroAssemblerIA32::CheckGreedyLoop(Label* on_equal) {
293 Label fallthrough;
ager@chromium.org32912102009-01-16 10:38:43 +0000294 __ cmp(edi, Operand(backtrack_stackpointer(), 0));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000295 __ j(not_equal, &fallthrough);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000296 __ add(backtrack_stackpointer(), Immediate(kPointerSize)); // Pop.
ager@chromium.org8bb60582008-12-11 12:02:20 +0000297 BranchOrBacktrack(no_condition, on_equal);
298 __ bind(&fallthrough);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000299}
300
301
302void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
ager@chromium.org8bb60582008-12-11 12:02:20 +0000303 int start_reg,
304 Label* on_no_match) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000305 Label fallthrough;
ager@chromium.org32912102009-01-16 10:38:43 +0000306 __ mov(edx, register_location(start_reg)); // Index of start of capture
307 __ mov(ebx, register_location(start_reg + 1)); // Index of end of capture
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000308 __ sub(ebx, edx); // Length of capture.
ager@chromium.org32912102009-01-16 10:38:43 +0000309
310 // The length of a capture should not be negative. This can only happen
311 // if the end of the capture is unrecorded, or at a point earlier than
312 // the start of the capture.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000313 BranchOrBacktrack(less, on_no_match);
ager@chromium.org32912102009-01-16 10:38:43 +0000314
315 // If length is zero, either the capture is empty or it is completely
316 // uncaptured. In either case succeed immediately.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000317 __ j(equal, &fallthrough);
318
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000319 // Check that there are sufficient characters left in the input.
320 __ mov(eax, edi);
321 __ add(eax, ebx);
322 BranchOrBacktrack(greater, on_no_match);
323
ager@chromium.org8bb60582008-12-11 12:02:20 +0000324 if (mode_ == ASCII) {
325 Label success;
326 Label fail;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000327 Label loop_increment;
ager@chromium.org32912102009-01-16 10:38:43 +0000328 // Save register contents to make the registers available below.
ager@chromium.org8bb60582008-12-11 12:02:20 +0000329 __ push(edi);
ager@chromium.org32912102009-01-16 10:38:43 +0000330 __ push(backtrack_stackpointer());
iposva@chromium.org245aa852009-02-10 00:49:54 +0000331 // After this, the eax, ecx, and edi registers are available.
ager@chromium.org32912102009-01-16 10:38:43 +0000332
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000333 __ add(edx, esi); // Start of capture
334 __ add(edi, esi); // Start of text to match against capture.
335 __ add(ebx, edi); // End of text to match against capture.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000336
ager@chromium.org8bb60582008-12-11 12:02:20 +0000337 Label loop;
338 __ bind(&loop);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000339 __ movzx_b(eax, Operand(edi, 0));
340 __ cmpb_al(Operand(edx, 0));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000341 __ j(equal, &loop_increment);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000342
ager@chromium.org32912102009-01-16 10:38:43 +0000343 // Mismatch, try case-insensitive match (converting letters to lower-case).
344 __ or_(eax, 0x20); // Convert match character to lower-case.
345 __ lea(ecx, Operand(eax, -'a'));
346 __ cmp(ecx, static_cast<int32_t>('z' - 'a')); // Is eax a lowercase letter?
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000347 Label convert_capture;
348 __ j(below_equal, &convert_capture); // In range 'a'-'z'.
349 // Latin-1: Check for values in range [224,254] but not 247.
350 __ sub(ecx, Immediate(224 - 'a'));
351 __ cmp(ecx, Immediate(254 - 224));
352 __ j(above, &fail); // Weren't Latin-1 letters.
353 __ cmp(ecx, Immediate(247 - 224)); // Check for 247.
354 __ j(equal, &fail);
355 __ bind(&convert_capture);
ager@chromium.org32912102009-01-16 10:38:43 +0000356 // Also convert capture character.
357 __ movzx_b(ecx, Operand(edx, 0));
358 __ or_(ecx, 0x20);
359
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000360 __ cmp(eax, ecx);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000361 __ j(not_equal, &fail);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000362
363 __ bind(&loop_increment);
ager@chromium.org32912102009-01-16 10:38:43 +0000364 // Increment pointers into match and capture strings.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000365 __ add(edx, Immediate(1));
366 __ add(edi, Immediate(1));
ager@chromium.org32912102009-01-16 10:38:43 +0000367 // Compare to end of match, and loop if not done.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000368 __ cmp(edi, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000369 __ j(below, &loop);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000370 __ jmp(&success);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000371
ager@chromium.org8bb60582008-12-11 12:02:20 +0000372 __ bind(&fail);
ager@chromium.org32912102009-01-16 10:38:43 +0000373 // Restore original values before failing.
374 __ pop(backtrack_stackpointer());
ager@chromium.org8bb60582008-12-11 12:02:20 +0000375 __ pop(edi);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000376 BranchOrBacktrack(no_condition, on_no_match);
377
378 __ bind(&success);
ager@chromium.org32912102009-01-16 10:38:43 +0000379 // Restore original value before continuing.
380 __ pop(backtrack_stackpointer());
381 // Drop original value of character position.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000382 __ add(esp, Immediate(kPointerSize));
ager@chromium.org32912102009-01-16 10:38:43 +0000383 // Compute new value of character position after the matched part.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000384 __ sub(edi, esi);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000385 } else {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000386 ASSERT(mode_ == UC16);
ager@chromium.org32912102009-01-16 10:38:43 +0000387 // Save registers before calling C function.
ager@chromium.org8bb60582008-12-11 12:02:20 +0000388 __ push(esi);
389 __ push(edi);
ager@chromium.org32912102009-01-16 10:38:43 +0000390 __ push(backtrack_stackpointer());
391 __ push(ebx);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000392
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000393 static const int argument_count = 4;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000394 __ PrepareCallCFunction(argument_count, ecx);
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000395 // Put arguments into allocated stack area, last argument highest on stack.
396 // Parameters are
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000397 // Address byte_offset1 - Address captured substring's start.
398 // Address byte_offset2 - Address of current character position.
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000399 // size_t byte_length - length of capture in bytes(!)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000400 // Isolate* isolate
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000401
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000402 // Set isolate.
403 __ mov(Operand(esp, 3 * kPointerSize),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000404 Immediate(ExternalReference::isolate_address(isolate())));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000405 // Set byte_length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000406 __ mov(Operand(esp, 2 * kPointerSize), ebx);
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000407 // Set byte_offset2.
408 // Found by adding negative string-end offset of current position (edi)
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000409 // to end of string.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000410 __ add(edi, esi);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000411 __ mov(Operand(esp, 1 * kPointerSize), edi);
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000412 // Set byte_offset1.
iposva@chromium.org245aa852009-02-10 00:49:54 +0000413 // Start of capture, where edx already holds string-end negative offset.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000414 __ add(edx, esi);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000415 __ mov(Operand(esp, 0 * kPointerSize), edx);
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000416
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000417 {
418 AllowExternalCallThatCantCauseGC scope(masm_);
419 ExternalReference compare =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000420 ExternalReference::re_case_insensitive_compare_uc16(isolate());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000421 __ CallCFunction(compare, argument_count);
422 }
ager@chromium.org32912102009-01-16 10:38:43 +0000423 // Pop original values before reacting on result value.
424 __ pop(ebx);
425 __ pop(backtrack_stackpointer());
ager@chromium.org8bb60582008-12-11 12:02:20 +0000426 __ pop(edi);
427 __ pop(esi);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000428
ager@chromium.org32912102009-01-16 10:38:43 +0000429 // Check if function returned non-zero for success or zero for failure.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000430 __ or_(eax, eax);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000431 BranchOrBacktrack(zero, on_no_match);
ager@chromium.org32912102009-01-16 10:38:43 +0000432 // On success, increment position by length of capture.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000433 __ add(edi, ebx);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000434 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000435 __ bind(&fallthrough);
436}
437
438
439void RegExpMacroAssemblerIA32::CheckNotBackReference(
ager@chromium.org8bb60582008-12-11 12:02:20 +0000440 int start_reg,
441 Label* on_no_match) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000442 Label fallthrough;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000443 Label success;
444 Label fail;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000445
ager@chromium.org32912102009-01-16 10:38:43 +0000446 // Find length of back-referenced capture.
447 __ mov(edx, register_location(start_reg));
448 __ mov(eax, register_location(start_reg + 1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000449 __ sub(eax, edx); // Length to check.
ager@chromium.org32912102009-01-16 10:38:43 +0000450 // Fail on partial or illegal capture (start of capture after end of capture).
451 BranchOrBacktrack(less, on_no_match);
452 // Succeed on empty capture (including no capture)
453 __ j(equal, &fallthrough);
454
455 // Check that there are sufficient characters left in the input.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000456 __ mov(ebx, edi);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000457 __ add(ebx, eax);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000458 BranchOrBacktrack(greater, on_no_match);
459
ager@chromium.org32912102009-01-16 10:38:43 +0000460 // Save register to make it available below.
461 __ push(backtrack_stackpointer());
462
463 // Compute pointers to match string and capture string
464 __ lea(ebx, Operand(esi, edi, times_1, 0)); // Start of match.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000465 __ add(edx, esi); // Start of capture.
ager@chromium.org32912102009-01-16 10:38:43 +0000466 __ lea(ecx, Operand(eax, ebx, times_1, 0)); // End of match
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000467
468 Label loop;
469 __ bind(&loop);
470 if (mode_ == ASCII) {
471 __ movzx_b(eax, Operand(edx, 0));
ager@chromium.org32912102009-01-16 10:38:43 +0000472 __ cmpb_al(Operand(ebx, 0));
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000473 } else {
474 ASSERT(mode_ == UC16);
475 __ movzx_w(eax, Operand(edx, 0));
ager@chromium.org32912102009-01-16 10:38:43 +0000476 __ cmpw_ax(Operand(ebx, 0));
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000477 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000478 __ j(not_equal, &fail);
ager@chromium.org32912102009-01-16 10:38:43 +0000479 // Increment pointers into capture and match string.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000480 __ add(edx, Immediate(char_size()));
481 __ add(ebx, Immediate(char_size()));
ager@chromium.org32912102009-01-16 10:38:43 +0000482 // Check if we have reached end of match area.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000483 __ cmp(ebx, ecx);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000484 __ j(below, &loop);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000485 __ jmp(&success);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000486
487 __ bind(&fail);
ager@chromium.org32912102009-01-16 10:38:43 +0000488 // Restore backtrack stackpointer.
489 __ pop(backtrack_stackpointer());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000490 BranchOrBacktrack(no_condition, on_no_match);
491
492 __ bind(&success);
ager@chromium.org32912102009-01-16 10:38:43 +0000493 // Move current character position to position after match.
494 __ mov(edi, ecx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000495 __ sub(edi, esi);
ager@chromium.org32912102009-01-16 10:38:43 +0000496 // Restore backtrack stackpointer.
497 __ pop(backtrack_stackpointer());
498
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000499 __ bind(&fallthrough);
500}
501
502
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000503void RegExpMacroAssemblerIA32::CheckNotCharacter(uint32_t c,
504 Label* on_not_equal) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000505 __ cmp(current_character(), c);
506 BranchOrBacktrack(not_equal, on_not_equal);
507}
508
509
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000510void RegExpMacroAssemblerIA32::CheckCharacterAfterAnd(uint32_t c,
511 uint32_t mask,
512 Label* on_equal) {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000513 if (c == 0) {
514 __ test(current_character(), Immediate(mask));
515 } else {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000516 __ mov(eax, mask);
517 __ and_(eax, current_character());
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000518 __ cmp(eax, c);
519 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000520 BranchOrBacktrack(equal, on_equal);
521}
522
523
524void RegExpMacroAssemblerIA32::CheckNotCharacterAfterAnd(uint32_t c,
525 uint32_t mask,
526 Label* on_not_equal) {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000527 if (c == 0) {
528 __ test(current_character(), Immediate(mask));
529 } else {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000530 __ mov(eax, mask);
531 __ and_(eax, current_character());
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000532 __ cmp(eax, c);
533 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000534 BranchOrBacktrack(not_equal, on_not_equal);
535}
536
537
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000538void RegExpMacroAssemblerIA32::CheckNotCharacterAfterMinusAnd(
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000539 uc16 c,
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000540 uc16 minus,
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000541 uc16 mask,
542 Label* on_not_equal) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +0000543 ASSERT(minus < String::kMaxUtf16CodeUnit);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000544 __ lea(eax, Operand(current_character(), -minus));
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000545 if (c == 0) {
546 __ test(eax, Immediate(mask));
547 } else {
548 __ and_(eax, mask);
549 __ cmp(eax, c);
550 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000551 BranchOrBacktrack(not_equal, on_not_equal);
552}
553
ager@chromium.org32912102009-01-16 10:38:43 +0000554
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000555void RegExpMacroAssemblerIA32::CheckCharacterInRange(
556 uc16 from,
557 uc16 to,
558 Label* on_in_range) {
559 __ lea(eax, Operand(current_character(), -from));
560 __ cmp(eax, to - from);
561 BranchOrBacktrack(below_equal, on_in_range);
562}
563
564
565void RegExpMacroAssemblerIA32::CheckCharacterNotInRange(
566 uc16 from,
567 uc16 to,
568 Label* on_not_in_range) {
569 __ lea(eax, Operand(current_character(), -from));
570 __ cmp(eax, to - from);
571 BranchOrBacktrack(above, on_not_in_range);
572}
573
574
575void RegExpMacroAssemblerIA32::CheckBitInTable(
576 Handle<ByteArray> table,
577 Label* on_bit_set) {
578 __ mov(eax, Immediate(table));
579 Register index = current_character();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000580 if (mode_ != ASCII || kTableMask != String::kMaxOneByteCharCode) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000581 __ mov(ebx, kTableSize - 1);
582 __ and_(ebx, current_character());
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000583 index = ebx;
584 }
585 __ cmpb(FieldOperand(eax, index, times_1, ByteArray::kHeaderSize), 0);
586 BranchOrBacktrack(not_equal, on_bit_set);
587}
588
589
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000590bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type,
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000591 Label* on_no_match) {
592 // Range checks (c in min..max) are generally implemented by an unsigned
593 // (c - min) <= (max - min) check
594 switch (type) {
595 case 's':
596 // Match space-characters
597 if (mode_ == ASCII) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000598 // One byte space characters are '\t'..'\r', ' ' and \u00a0.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000599 Label success;
600 __ cmp(current_character(), ' ');
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000601 __ j(equal, &success, Label::kNear);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000602 // Check range 0x09..0x0d
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000603 __ lea(eax, Operand(current_character(), -'\t'));
604 __ cmp(eax, '\r' - '\t');
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000605 __ j(below_equal, &success, Label::kNear);
606 // \u00a0 (NBSP).
607 __ cmp(eax, 0x00a0 - '\t');
608 BranchOrBacktrack(not_equal, on_no_match);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000609 __ bind(&success);
610 return true;
611 }
612 return false;
613 case 'S':
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000614 // The emitted code for generic character classes is good enough.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000615 return false;
616 case 'd':
617 // Match ASCII digits ('0'..'9')
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000618 __ lea(eax, Operand(current_character(), -'0'));
619 __ cmp(eax, '9' - '0');
ager@chromium.org32912102009-01-16 10:38:43 +0000620 BranchOrBacktrack(above, on_no_match);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000621 return true;
622 case 'D':
623 // Match non ASCII-digits
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000624 __ lea(eax, Operand(current_character(), -'0'));
625 __ cmp(eax, '9' - '0');
ager@chromium.org32912102009-01-16 10:38:43 +0000626 BranchOrBacktrack(below_equal, on_no_match);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000627 return true;
628 case '.': {
629 // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000630 __ mov(eax, current_character());
631 __ xor_(eax, Immediate(0x01));
ager@chromium.org32912102009-01-16 10:38:43 +0000632 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000633 __ sub(eax, Immediate(0x0b));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000634 __ cmp(eax, 0x0c - 0x0b);
ager@chromium.org32912102009-01-16 10:38:43 +0000635 BranchOrBacktrack(below_equal, on_no_match);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000636 if (mode_ == UC16) {
637 // Compare original value to 0x2028 and 0x2029, using the already
ager@chromium.org32912102009-01-16 10:38:43 +0000638 // computed (current_char ^ 0x01 - 0x0b). I.e., check for
639 // 0x201d (0x2028 - 0x0b) or 0x201e.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000640 __ sub(eax, Immediate(0x2028 - 0x0b));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000641 __ cmp(eax, 0x2029 - 0x2028);
ager@chromium.org32912102009-01-16 10:38:43 +0000642 BranchOrBacktrack(below_equal, on_no_match);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000643 }
644 return true;
645 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000646 case 'w': {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000647 if (mode_ != ASCII) {
648 // Table is 128 entries, so all ASCII characters can be tested.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000649 __ cmp(current_character(), Immediate('z'));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000650 BranchOrBacktrack(above, on_no_match);
651 }
652 ASSERT_EQ(0, word_character_map[0]); // Character '\0' is not a word char.
653 ExternalReference word_map = ExternalReference::re_word_character_map();
654 __ test_b(current_character(),
655 Operand::StaticArray(current_character(), times_1, word_map));
656 BranchOrBacktrack(zero, on_no_match);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000657 return true;
658 }
659 case 'W': {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000660 Label done;
661 if (mode_ != ASCII) {
662 // Table is 128 entries, so all ASCII characters can be tested.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000663 __ cmp(current_character(), Immediate('z'));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000664 __ j(above, &done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000665 }
666 ASSERT_EQ(0, word_character_map[0]); // Character '\0' is not a word char.
667 ExternalReference word_map = ExternalReference::re_word_character_map();
668 __ test_b(current_character(),
669 Operand::StaticArray(current_character(), times_1, word_map));
670 BranchOrBacktrack(not_zero, on_no_match);
671 if (mode_ != ASCII) {
672 __ bind(&done);
673 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000674 return true;
675 }
676 // Non-standard classes (with no syntactic shorthand) used internally.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000677 case '*':
678 // Match any character.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000679 return true;
680 case 'n': {
681 // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 or 0x2029).
682 // The opposite of '.'.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000683 __ mov(eax, current_character());
684 __ xor_(eax, Immediate(0x01));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000685 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000686 __ sub(eax, Immediate(0x0b));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000687 __ cmp(eax, 0x0c - 0x0b);
688 if (mode_ == ASCII) {
689 BranchOrBacktrack(above, on_no_match);
690 } else {
691 Label done;
692 BranchOrBacktrack(below_equal, &done);
693 ASSERT_EQ(UC16, mode_);
694 // Compare original value to 0x2028 and 0x2029, using the already
695 // computed (current_char ^ 0x01 - 0x0b). I.e., check for
696 // 0x201d (0x2028 - 0x0b) or 0x201e.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000697 __ sub(eax, Immediate(0x2028 - 0x0b));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000698 __ cmp(eax, 1);
699 BranchOrBacktrack(above, on_no_match);
700 __ bind(&done);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000701 }
702 return true;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000703 }
704 // No custom implementation (yet): s(UC16), S(UC16).
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000705 default:
706 return false;
707 }
708}
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000709
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000710
711void RegExpMacroAssemblerIA32::Fail() {
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000712 STATIC_ASSERT(FAILURE == 0); // Return value for failure is zero.
713 if (!global()) {
714 __ Set(eax, Immediate(FAILURE));
715 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000716 __ jmp(&exit_label_);
717}
718
719
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000720Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000721 Label return_eax;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000722 // Finalize code - write the entry point code now we know how many
723 // registers we need.
724
725 // Entry code:
726 __ bind(&entry_label_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000727
728 // Tell the system that we have a stack frame. Because the type is MANUAL, no
729 // code is generated.
730 FrameScope scope(masm_, StackFrame::MANUAL);
731
732 // Actually emit code to start a new stack frame.
ager@chromium.org32912102009-01-16 10:38:43 +0000733 __ push(ebp);
734 __ mov(ebp, esp);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000735 // Save callee-save registers. Order here should correspond to order of
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000736 // kBackup_ebx etc.
737 __ push(esi);
738 __ push(edi);
739 __ push(ebx); // Callee-save on MacOS.
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000740 __ push(Immediate(0)); // Number of successful matches in a global regexp.
iposva@chromium.org245aa852009-02-10 00:49:54 +0000741 __ push(Immediate(0)); // Make room for "input start - 1" constant.
ager@chromium.org32912102009-01-16 10:38:43 +0000742
743 // Check if we have space on the stack for registers.
ager@chromium.org32912102009-01-16 10:38:43 +0000744 Label stack_limit_hit;
745 Label stack_ok;
746
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000747 ExternalReference stack_limit =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000748 ExternalReference::address_of_stack_limit(isolate());
ager@chromium.org32912102009-01-16 10:38:43 +0000749 __ mov(ecx, esp);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000750 __ sub(ecx, Operand::StaticVariable(stack_limit));
ager@chromium.org32912102009-01-16 10:38:43 +0000751 // Handle it if the stack pointer is already below the stack limit.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000752 __ j(below_equal, &stack_limit_hit);
ager@chromium.org32912102009-01-16 10:38:43 +0000753 // Check if there is room for the variable number of registers above
754 // the stack limit.
755 __ cmp(ecx, num_registers_ * kPointerSize);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000756 __ j(above_equal, &stack_ok);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000757 // Exit with OutOfMemory exception. There is not enough space on the stack
758 // for our working registers.
ager@chromium.org32912102009-01-16 10:38:43 +0000759 __ mov(eax, EXCEPTION);
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000760 __ jmp(&return_eax);
ager@chromium.org32912102009-01-16 10:38:43 +0000761
762 __ bind(&stack_limit_hit);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000763 CallCheckStackGuardState(ebx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000764 __ or_(eax, eax);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000765 // If returned value is non-zero, we exit with the returned value as result.
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000766 __ j(not_zero, &return_eax);
ager@chromium.org32912102009-01-16 10:38:43 +0000767
768 __ bind(&stack_ok);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000769 // Load start index for later use.
770 __ mov(ebx, Operand(ebp, kStartIndex));
ager@chromium.org32912102009-01-16 10:38:43 +0000771
772 // Allocate space on stack for registers.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000773 __ sub(esp, Immediate(num_registers_ * kPointerSize));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000774 // Load string length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000775 __ mov(esi, Operand(ebp, kInputEnd));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000776 // Load input position.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000777 __ mov(edi, Operand(ebp, kInputStart));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000778 // Set up edi to be negative offset from string end.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000779 __ sub(edi, esi);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000780
781 // Set eax to address of char before start of the string.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000782 // (effectively string position -1).
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000783 __ neg(ebx);
784 if (mode_ == UC16) {
785 __ lea(eax, Operand(edi, ebx, times_2, -char_size()));
786 } else {
787 __ lea(eax, Operand(edi, ebx, times_1, -char_size()));
788 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000789 // Store this value in a local variable, for use when clearing
790 // position registers.
791 __ mov(Operand(ebp, kInputStartMinusOne), eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000792
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000793#ifdef WIN32
794 // Ensure that we write to each stack page, in order. Skipping a page
ager@chromium.org32912102009-01-16 10:38:43 +0000795 // on Windows can cause segmentation faults. Assuming page size is 4k.
796 const int kPageSize = 4096;
797 const int kRegistersPerPage = kPageSize / kPointerSize;
798 for (int i = num_saved_registers_ + kRegistersPerPage - 1;
799 i < num_registers_;
800 i += kRegistersPerPage) {
801 __ mov(register_location(i), eax); // One write every page.
802 }
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000803#endif // WIN32
ager@chromium.org32912102009-01-16 10:38:43 +0000804
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000805 Label load_char_start_regexp, start_regexp;
806 // Load newline if index is at start, previous character otherwise.
807 __ cmp(Operand(ebp, kStartIndex), Immediate(0));
808 __ j(not_equal, &load_char_start_regexp, Label::kNear);
809 __ mov(current_character(), '\n');
810 __ jmp(&start_regexp, Label::kNear);
811
812 // Global regexp restarts matching here.
813 __ bind(&load_char_start_regexp);
814 // Load previous char as initial value of current character register.
815 LoadCurrentCharacterUnchecked(-1, 1);
816 __ bind(&start_regexp);
817
818 // Initialize on-stack registers.
819 if (num_saved_registers_ > 0) { // Always is, if generated from a regexp.
820 // Fill saved registers with initial value = start offset - 1
821 // Fill in stack push order, to avoid accessing across an unwritten
822 // page (a problem on Windows).
823 if (num_saved_registers_ > 8) {
824 __ mov(ecx, kRegisterZero);
825 Label init_loop;
826 __ bind(&init_loop);
827 __ mov(Operand(ebp, ecx, times_1, 0), eax);
828 __ sub(ecx, Immediate(kPointerSize));
829 __ cmp(ecx, kRegisterZero - num_saved_registers_ * kPointerSize);
830 __ j(greater, &init_loop);
831 } else { // Unroll the loop.
832 for (int i = 0; i < num_saved_registers_; i++) {
833 __ mov(register_location(i), eax);
834 }
835 }
836 }
ager@chromium.org32912102009-01-16 10:38:43 +0000837
838 // Initialize backtrack stack pointer.
839 __ mov(backtrack_stackpointer(), Operand(ebp, kStackHighEnd));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000840
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000841 __ jmp(&start_label_);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000842
843 // Exit code:
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000844 if (success_label_.is_linked()) {
ager@chromium.org32912102009-01-16 10:38:43 +0000845 // Save captures when successful.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000846 __ bind(&success_label_);
847 if (num_saved_registers_ > 0) {
848 // copy captures to output
849 __ mov(ebx, Operand(ebp, kRegisterOutput));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000850 __ mov(ecx, Operand(ebp, kInputEnd));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000851 __ mov(edx, Operand(ebp, kStartIndex));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000852 __ sub(ecx, Operand(ebp, kInputStart));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000853 if (mode_ == UC16) {
854 __ lea(ecx, Operand(ecx, edx, times_2, 0));
855 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000856 __ add(ecx, edx);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000857 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000858 for (int i = 0; i < num_saved_registers_; i++) {
859 __ mov(eax, register_location(i));
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000860 if (i == 0 && global_with_zero_length_check()) {
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000861 // Keep capture start in edx for the zero-length check later.
862 __ mov(edx, eax);
863 }
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000864 // Convert to index from start of string, not end.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000865 __ add(eax, ecx);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000866 if (mode_ == UC16) {
867 __ sar(eax, 1); // Convert byte index to character index.
868 }
869 __ mov(Operand(ebx, i * kPointerSize), eax);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000870 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000871 }
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000872
873 if (global()) {
874 // Restart matching if the regular expression is flagged as global.
875 // Increment success counter.
876 __ inc(Operand(ebp, kSuccessfulCaptures));
877 // Capture results have been stored, so the number of remaining global
878 // output registers is reduced by the number of stored captures.
879 __ mov(ecx, Operand(ebp, kNumOutputRegisters));
880 __ sub(ecx, Immediate(num_saved_registers_));
881 // Check whether we have enough room for another set of capture results.
882 __ cmp(ecx, Immediate(num_saved_registers_));
883 __ j(less, &exit_label_);
884
885 __ mov(Operand(ebp, kNumOutputRegisters), ecx);
886 // Advance the location for output.
887 __ add(Operand(ebp, kRegisterOutput),
888 Immediate(num_saved_registers_ * kPointerSize));
889
890 // Prepare eax to initialize registers with its value in the next run.
891 __ mov(eax, Operand(ebp, kInputStartMinusOne));
892
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000893 if (global_with_zero_length_check()) {
894 // Special case for zero-length matches.
895 // edx: capture start index
896 __ cmp(edi, edx);
897 // Not a zero-length match, restart.
898 __ j(not_equal, &load_char_start_regexp);
899 // edi (offset from the end) is zero if we already reached the end.
900 __ test(edi, edi);
901 __ j(zero, &exit_label_, Label::kNear);
902 // Advance current position after a zero-length match.
903 if (mode_ == UC16) {
904 __ add(edi, Immediate(2));
905 } else {
906 __ inc(edi);
907 }
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000908 }
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000909
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000910 __ jmp(&load_char_start_regexp);
911 } else {
912 __ mov(eax, Immediate(SUCCESS));
913 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000914 }
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000915
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000916 __ bind(&exit_label_);
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000917 if (global()) {
918 // Return the number of successful captures.
919 __ mov(eax, Operand(ebp, kSuccessfulCaptures));
920 }
921
922 __ bind(&return_eax);
ager@chromium.org32912102009-01-16 10:38:43 +0000923 // Skip esp past regexp registers.
924 __ lea(esp, Operand(ebp, kBackup_ebx));
925 // Restore callee-save registers.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000926 __ pop(ebx);
927 __ pop(edi);
928 __ pop(esi);
ager@chromium.org32912102009-01-16 10:38:43 +0000929 // Exit function frame, restore previous one.
930 __ pop(ebp);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000931 __ ret(0);
932
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000933 // Backtrack code (branch target for conditional backtracks).
934 if (backtrack_label_.is_linked()) {
935 __ bind(&backtrack_label_);
936 Backtrack();
937 }
938
ager@chromium.org32912102009-01-16 10:38:43 +0000939 Label exit_with_exception;
940
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000941 // Preempt-code
942 if (check_preempt_label_.is_linked()) {
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000943 SafeCallTarget(&check_preempt_label_);
ager@chromium.org32912102009-01-16 10:38:43 +0000944
945 __ push(backtrack_stackpointer());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000946 __ push(edi);
947
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000948 CallCheckStackGuardState(ebx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000949 __ or_(eax, eax);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000950 // If returning non-zero, we should end execution with the given
951 // result as return value.
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000952 __ j(not_zero, &return_eax);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000953
954 __ pop(edi);
ager@chromium.org32912102009-01-16 10:38:43 +0000955 __ pop(backtrack_stackpointer());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000956 // String might have moved: Reload esi from frame.
957 __ mov(esi, Operand(ebp, kInputEnd));
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000958 SafeReturn();
ager@chromium.org32912102009-01-16 10:38:43 +0000959 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000960
ager@chromium.org32912102009-01-16 10:38:43 +0000961 // Backtrack stack overflow code.
962 if (stack_overflow_label_.is_linked()) {
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000963 SafeCallTarget(&stack_overflow_label_);
ager@chromium.org32912102009-01-16 10:38:43 +0000964 // Reached if the backtrack-stack limit has been hit.
965
966 Label grow_failed;
967 // Save registers before calling C function
968 __ push(esi);
969 __ push(edi);
970
971 // Call GrowStack(backtrack_stackpointer())
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000972 static const int num_arguments = 3;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000973 __ PrepareCallCFunction(num_arguments, ebx);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000974 __ mov(Operand(esp, 2 * kPointerSize),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000975 Immediate(ExternalReference::isolate_address(isolate())));
ager@chromium.org6f10e412009-02-13 10:11:16 +0000976 __ lea(eax, Operand(ebp, kStackHighEnd));
977 __ mov(Operand(esp, 1 * kPointerSize), eax);
978 __ mov(Operand(esp, 0 * kPointerSize), backtrack_stackpointer());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000979 ExternalReference grow_stack =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000980 ExternalReference::re_grow_stack(isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000981 __ CallCFunction(grow_stack, num_arguments);
ager@chromium.org32912102009-01-16 10:38:43 +0000982 // If return NULL, we have failed to grow the stack, and
983 // must exit with a stack-overflow exception.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000984 __ or_(eax, eax);
ager@chromium.org32912102009-01-16 10:38:43 +0000985 __ j(equal, &exit_with_exception);
986 // Otherwise use return value as new stack pointer.
987 __ mov(backtrack_stackpointer(), eax);
988 // Restore saved registers and continue.
989 __ pop(edi);
990 __ pop(esi);
991 SafeReturn();
992 }
993
994 if (exit_with_exception.is_linked()) {
995 // If any of the code above needed to exit with an exception.
996 __ bind(&exit_with_exception);
997 // Exit with Result EXCEPTION(-1) to signal thrown exception.
998 __ mov(eax, EXCEPTION);
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +0000999 __ jmp(&return_eax);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001000 }
1001
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001002 CodeDesc code_desc;
1003 masm_->GetCode(&code_desc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001004 Handle<Code> code =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001005 isolate()->factory()->NewCode(code_desc,
1006 Code::ComputeFlags(Code::REGEXP),
1007 masm_->CodeObject());
1008 PROFILE(isolate(), RegExpCodeCreateEvent(*code, *source));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001009 return Handle<HeapObject>::cast(code);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001010}
1011
1012
1013void RegExpMacroAssemblerIA32::GoTo(Label* to) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00001014 BranchOrBacktrack(no_condition, to);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001015}
1016
1017
1018void RegExpMacroAssemblerIA32::IfRegisterGE(int reg,
1019 int comparand,
1020 Label* if_ge) {
1021 __ cmp(register_location(reg), Immediate(comparand));
1022 BranchOrBacktrack(greater_equal, if_ge);
1023}
1024
1025
1026void RegExpMacroAssemblerIA32::IfRegisterLT(int reg,
1027 int comparand,
1028 Label* if_lt) {
1029 __ cmp(register_location(reg), Immediate(comparand));
1030 BranchOrBacktrack(less, if_lt);
1031}
1032
1033
ager@chromium.org32912102009-01-16 10:38:43 +00001034void RegExpMacroAssemblerIA32::IfRegisterEqPos(int reg,
1035 Label* if_eq) {
1036 __ cmp(edi, register_location(reg));
1037 BranchOrBacktrack(equal, if_eq);
1038}
1039
1040
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001041RegExpMacroAssembler::IrregexpImplementation
1042 RegExpMacroAssemblerIA32::Implementation() {
1043 return kIA32Implementation;
1044}
1045
1046
1047void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset,
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001048 Label* on_end_of_input,
1049 bool check_bounds,
1050 int characters) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001051 ASSERT(cp_offset >= -1); // ^ and \b can look behind one character.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001052 ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works)
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001053 if (check_bounds) {
1054 CheckPosition(cp_offset + characters - 1, on_end_of_input);
1055 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001056 LoadCurrentCharacterUnchecked(cp_offset, characters);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001057}
1058
1059
1060void RegExpMacroAssemblerIA32::PopCurrentPosition() {
ager@chromium.org32912102009-01-16 10:38:43 +00001061 Pop(edi);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001062}
1063
1064
1065void RegExpMacroAssemblerIA32::PopRegister(int register_index) {
ager@chromium.org32912102009-01-16 10:38:43 +00001066 Pop(eax);
1067 __ mov(register_location(register_index), eax);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001068}
1069
1070
1071void RegExpMacroAssemblerIA32::PushBacktrack(Label* label) {
ager@chromium.org32912102009-01-16 10:38:43 +00001072 Push(Immediate::CodeRelativeOffset(label));
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001073 CheckStackLimit();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001074}
1075
1076
1077void RegExpMacroAssemblerIA32::PushCurrentPosition() {
ager@chromium.org32912102009-01-16 10:38:43 +00001078 Push(edi);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001079}
1080
1081
ager@chromium.org32912102009-01-16 10:38:43 +00001082void RegExpMacroAssemblerIA32::PushRegister(int register_index,
1083 StackCheckFlag check_stack_limit) {
1084 __ mov(eax, register_location(register_index));
1085 Push(eax);
1086 if (check_stack_limit) CheckStackLimit();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001087}
1088
1089
1090void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) {
1091 __ mov(edi, register_location(reg));
1092}
1093
1094
1095void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) {
ager@chromium.org32912102009-01-16 10:38:43 +00001096 __ mov(backtrack_stackpointer(), register_location(reg));
ager@chromium.org6f10e412009-02-13 10:11:16 +00001097 __ add(backtrack_stackpointer(), Operand(ebp, kStackHighEnd));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001098}
1099
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001100void RegExpMacroAssemblerIA32::SetCurrentPositionFromEnd(int by) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001101 Label after_position;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001102 __ cmp(edi, -by * char_size());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001103 __ j(greater_equal, &after_position, Label::kNear);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001104 __ mov(edi, -by * char_size());
1105 // On RegExp code entry (where this operation is used), the character before
1106 // the current position is expected to be already loaded.
1107 // We have advanced the position, so it's safe to read backwards.
1108 LoadCurrentCharacterUnchecked(-1, 1);
1109 __ bind(&after_position);
1110}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001111
1112void RegExpMacroAssemblerIA32::SetRegister(int register_index, int to) {
1113 ASSERT(register_index >= num_saved_registers_); // Reserved for positions!
1114 __ mov(register_location(register_index), Immediate(to));
1115}
1116
1117
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001118bool RegExpMacroAssemblerIA32::Succeed() {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001119 __ jmp(&success_label_);
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00001120 return global();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001121}
1122
1123
ager@chromium.org8bb60582008-12-11 12:02:20 +00001124void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(int reg,
1125 int cp_offset) {
1126 if (cp_offset == 0) {
1127 __ mov(register_location(reg), edi);
1128 } else {
1129 __ lea(eax, Operand(edi, cp_offset * char_size()));
1130 __ mov(register_location(reg), eax);
1131 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001132}
1133
ager@chromium.org8bb60582008-12-11 12:02:20 +00001134
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001135void RegExpMacroAssemblerIA32::ClearRegisters(int reg_from, int reg_to) {
1136 ASSERT(reg_from <= reg_to);
ager@chromium.org32912102009-01-16 10:38:43 +00001137 __ mov(eax, Operand(ebp, kInputStartMinusOne));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001138 for (int reg = reg_from; reg <= reg_to; reg++) {
1139 __ mov(register_location(reg), eax);
1140 }
ager@chromium.org32912102009-01-16 10:38:43 +00001141}
1142
1143
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001144void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
ager@chromium.org6f10e412009-02-13 10:11:16 +00001145 __ mov(eax, backtrack_stackpointer());
1146 __ sub(eax, Operand(ebp, kStackHighEnd));
1147 __ mov(register_location(reg), eax);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001148}
1149
1150
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001151// Private methods:
ager@chromium.org8bb60582008-12-11 12:02:20 +00001152
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001153void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001154 static const int num_arguments = 3;
1155 __ PrepareCallCFunction(num_arguments, scratch);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001156 // RegExp code frame pointer.
1157 __ mov(Operand(esp, 2 * kPointerSize), ebp);
1158 // Code* of self.
1159 __ mov(Operand(esp, 1 * kPointerSize), Immediate(masm_->CodeObject()));
1160 // Next address on the stack (will be address of return address).
1161 __ lea(eax, Operand(esp, -kPointerSize));
1162 __ mov(Operand(esp, 0 * kPointerSize), eax);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001163 ExternalReference check_stack_guard =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001164 ExternalReference::re_check_stack_guard_state(isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001165 __ CallCFunction(check_stack_guard, num_arguments);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001166}
1167
1168
1169// Helper function for reading a value out of a stack frame.
1170template <typename T>
1171static T& frame_entry(Address re_frame, int frame_offset) {
1172 return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset));
1173}
1174
1175
ager@chromium.org381abbb2009-02-25 13:23:22 +00001176int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001177 Code* re_code,
1178 Address re_frame) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001179 Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
1180 ASSERT(isolate == Isolate::Current());
1181 if (isolate->stack_guard()->IsStackOverflow()) {
1182 isolate->StackOverflow();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001183 return EXCEPTION;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001184 }
1185
1186 // If not real stack overflow the stack guard was used to interrupt
1187 // execution for another purpose.
1188
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001189 // If this is a direct call from JavaScript retry the RegExp forcing the call
1190 // through the runtime system. Currently the direct call cannot handle a GC.
1191 if (frame_entry<int>(re_frame, kDirectCall) == 1) {
1192 return RETRY;
1193 }
1194
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001195 // Prepare for possible GC.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001196 HandleScope handles(isolate);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001197 Handle<Code> code_handle(re_code);
ager@chromium.org32912102009-01-16 10:38:43 +00001198
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001199 Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001200
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001201 // Current string.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001202 bool is_ascii = subject->IsOneByteRepresentationUnderneath();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001203
ager@chromium.org381abbb2009-02-25 13:23:22 +00001204 ASSERT(re_code->instruction_start() <= *return_address);
1205 ASSERT(*return_address <=
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001206 re_code->instruction_start() + re_code->instruction_size());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001207
ulan@chromium.org812308e2012-02-29 15:58:45 +00001208 MaybeObject* result = Execution::HandleStackGuardInterrupt(isolate);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001209
1210 if (*code_handle != re_code) { // Return address no longer valid
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001211 int delta = code_handle->address() - re_code->address();
ager@chromium.org381abbb2009-02-25 13:23:22 +00001212 // Overwrite the return address on the stack.
1213 *return_address += delta;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001214 }
1215
1216 if (result->IsException()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001217 return EXCEPTION;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001218 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001219
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001220 Handle<String> subject_tmp = subject;
1221 int slice_offset = 0;
1222
1223 // Extract the underlying string and the slice offset.
1224 if (StringShape(*subject_tmp).IsCons()) {
1225 subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first());
1226 } else if (StringShape(*subject_tmp).IsSliced()) {
1227 SlicedString* slice = SlicedString::cast(*subject_tmp);
1228 subject_tmp = Handle<String>(slice->parent());
1229 slice_offset = slice->offset();
1230 }
1231
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001232 // String might have changed.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001233 if (subject_tmp->IsOneByteRepresentation() != is_ascii) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001234 // If we changed between an ASCII and an UC16 string, the specialized
1235 // code cannot be used, and we need to restart regexp matching from
1236 // scratch (including, potentially, compiling a new version of the code).
1237 return RETRY;
1238 }
1239
1240 // Otherwise, the content of the string might have moved. It must still
1241 // be a sequential or external string with the same content.
1242 // Update the start and end pointers in the stack frame to the current
1243 // location (whether it has actually moved or not).
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001244 ASSERT(StringShape(*subject_tmp).IsSequential() ||
1245 StringShape(*subject_tmp).IsExternal());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001246
1247 // The original start address of the characters to match.
1248 const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
1249
1250 // Find the current start address of the same character at the current string
1251 // position.
1252 int start_index = frame_entry<int>(re_frame, kStartIndex);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001253 const byte* new_address = StringCharacterPosition(*subject_tmp,
1254 start_index + slice_offset);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001255
1256 if (start_address != new_address) {
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001257 // If there is a difference, update the object pointer and start and end
1258 // addresses in the RegExp stack frame to match the new value.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001259 const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001260 int byte_length = static_cast<int>(end_address - start_address);
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001261 frame_entry<const String*>(re_frame, kInputString) = *subject;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001262 frame_entry<const byte*>(re_frame, kInputStart) = new_address;
1263 frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001264 } else if (frame_entry<const String*>(re_frame, kInputString) != *subject) {
1265 // Subject string might have been a ConsString that underwent
1266 // short-circuiting during GC. That will not change start_address but
1267 // will change pointer inside the subject handle.
1268 frame_entry<const String*>(re_frame, kInputString) = *subject;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001269 }
1270
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001271 return 0;
1272}
1273
1274
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001275Operand RegExpMacroAssemblerIA32::register_location(int register_index) {
1276 ASSERT(register_index < (1<<30));
1277 if (num_registers_ <= register_index) {
1278 num_registers_ = register_index + 1;
1279 }
ager@chromium.org32912102009-01-16 10:38:43 +00001280 return Operand(ebp, kRegisterZero - register_index * kPointerSize);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001281}
1282
1283
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001284void RegExpMacroAssemblerIA32::CheckPosition(int cp_offset,
1285 Label* on_outside_input) {
1286 __ cmp(edi, -cp_offset * char_size());
1287 BranchOrBacktrack(greater_equal, on_outside_input);
1288}
1289
1290
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001291void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001292 Label* to) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001293 if (condition < 0) { // No condition
1294 if (to == NULL) {
1295 Backtrack();
1296 return;
1297 }
1298 __ jmp(to);
1299 return;
1300 }
1301 if (to == NULL) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001302 __ j(condition, &backtrack_label_);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001303 return;
1304 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001305 __ j(condition, to);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001306}
1307
1308
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001309void RegExpMacroAssemblerIA32::SafeCall(Label* to) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00001310 Label return_to;
1311 __ push(Immediate::CodeRelativeOffset(&return_to));
1312 __ jmp(to);
1313 __ bind(&return_to);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001314}
1315
1316
1317void RegExpMacroAssemblerIA32::SafeReturn() {
ager@chromium.orgac091b72010-05-05 07:34:42 +00001318 __ pop(ebx);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001319 __ add(ebx, Immediate(masm_->CodeObject()));
1320 __ jmp(ebx);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +00001321}
1322
1323
1324void RegExpMacroAssemblerIA32::SafeCallTarget(Label* name) {
1325 __ bind(name);
ager@chromium.org32912102009-01-16 10:38:43 +00001326}
1327
1328
1329void RegExpMacroAssemblerIA32::Push(Register source) {
1330 ASSERT(!source.is(backtrack_stackpointer()));
1331 // Notice: This updates flags, unlike normal Push.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001332 __ sub(backtrack_stackpointer(), Immediate(kPointerSize));
ager@chromium.org32912102009-01-16 10:38:43 +00001333 __ mov(Operand(backtrack_stackpointer(), 0), source);
1334}
1335
1336
1337void RegExpMacroAssemblerIA32::Push(Immediate value) {
1338 // Notice: This updates flags, unlike normal Push.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001339 __ sub(backtrack_stackpointer(), Immediate(kPointerSize));
ager@chromium.org32912102009-01-16 10:38:43 +00001340 __ mov(Operand(backtrack_stackpointer(), 0), value);
1341}
1342
1343
1344void RegExpMacroAssemblerIA32::Pop(Register target) {
1345 ASSERT(!target.is(backtrack_stackpointer()));
1346 __ mov(target, Operand(backtrack_stackpointer(), 0));
1347 // Notice: This updates flags, unlike normal Pop.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001348 __ add(backtrack_stackpointer(), Immediate(kPointerSize));
ager@chromium.org32912102009-01-16 10:38:43 +00001349}
1350
1351
1352void RegExpMacroAssemblerIA32::CheckPreemption() {
1353 // Check for preemption.
1354 Label no_preempt;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001355 ExternalReference stack_limit =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001356 ExternalReference::address_of_stack_limit(isolate());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001357 __ cmp(esp, Operand::StaticVariable(stack_limit));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001358 __ j(above, &no_preempt);
ager@chromium.org32912102009-01-16 10:38:43 +00001359
1360 SafeCall(&check_preempt_label_);
1361
1362 __ bind(&no_preempt);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001363}
1364
1365
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001366void RegExpMacroAssemblerIA32::CheckStackLimit() {
ager@chromium.org3811b432009-10-28 14:53:37 +00001367 Label no_stack_overflow;
1368 ExternalReference stack_limit =
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001369 ExternalReference::address_of_regexp_stack_limit(isolate());
ager@chromium.org3811b432009-10-28 14:53:37 +00001370 __ cmp(backtrack_stackpointer(), Operand::StaticVariable(stack_limit));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001371 __ j(above, &no_stack_overflow);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001372
ager@chromium.org3811b432009-10-28 14:53:37 +00001373 SafeCall(&stack_overflow_label_);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001374
ager@chromium.org3811b432009-10-28 14:53:37 +00001375 __ bind(&no_stack_overflow);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001376}
1377
1378
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001379void RegExpMacroAssemblerIA32::LoadCurrentCharacterUnchecked(int cp_offset,
1380 int characters) {
1381 if (mode_ == ASCII) {
1382 if (characters == 4) {
1383 __ mov(current_character(), Operand(esi, edi, times_1, cp_offset));
1384 } else if (characters == 2) {
1385 __ movzx_w(current_character(), Operand(esi, edi, times_1, cp_offset));
1386 } else {
1387 ASSERT(characters == 1);
1388 __ movzx_b(current_character(), Operand(esi, edi, times_1, cp_offset));
1389 }
1390 } else {
1391 ASSERT(mode_ == UC16);
1392 if (characters == 2) {
1393 __ mov(current_character(),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001394 Operand(esi, edi, times_1, cp_offset * sizeof(uc16)));
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001395 } else {
1396 ASSERT(characters == 1);
1397 __ movzx_w(current_character(),
1398 Operand(esi, edi, times_1, cp_offset * sizeof(uc16)));
1399 }
1400 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001401}
1402
1403
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001404#undef __
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001405
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001406#endif // V8_INTERPRETED_REGEXP
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001407
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001408}} // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001409
1410#endif // V8_TARGET_ARCH_IA32