1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #if V8_TARGET_ARCH_IA32
6
7 #include "src/regexp/ia32/regexp-macro-assembler-ia32.h"
8
9 #include "src/codegen/assembler-inl.h"
10 #include "src/codegen/macro-assembler.h"
11 #include "src/logging/log.h"
12 #include "src/objects/objects-inl.h"
13 #include "src/regexp/regexp-macro-assembler.h"
14 #include "src/regexp/regexp-stack.h"
15 #include "src/strings/unicode.h"
16
17 namespace v8 {
18 namespace internal {
19
20 /*
21 * This assembler uses the following register assignment convention
22 * - edx : Current character. Must be loaded using LoadCurrentCharacter
23 * before using any of the dispatch methods. Temporarily stores the
24 * index of capture start after a matching pass for a global regexp.
25 * - edi : Current position in input, as negative offset from end of string.
26 * Please notice that this is the byte offset, not the character offset!
27 * - esi : end of input (points to byte after last character in input).
28 * - ebp : Frame pointer. Used to access arguments, local variables and
29 * RegExp registers.
30 * - esp : Points to tip of C stack.
31 * - ecx : Points to tip of backtrack stack
32 *
33 * The registers eax and ebx are free to use for computations.
34 *
35 * Each call to a public method should retain this convention.
36 * The stack will have the following structure:
37 * - Address regexp (address of the JSRegExp object; unused in
38 * native code, passed to match signature of
39 * the interpreter)
40 * - Isolate* isolate (address of the current isolate)
41 * - direct_call (if 1, direct call from JavaScript code, if 0
42 * call through the runtime system)
43 * - capture array size (may fit multiple sets of matches)
44 * - int* capture_array (int[num_saved_registers_], for output).
45 * - end of input (address of end of string)
46 * - start of input (address of first character in string)
47 * - start index (character index of start)
48 * - String input_string (location of a handle containing the string)
49 * --- frame alignment (if applicable) ---
50 * - return address
51 * ebp-> - old ebp
52 * - backup of caller esi
53 * - backup of caller edi
54 * - backup of caller ebx
55 * - success counter (only for global regexps to count matches).
56 * - Offset of location before start of input (effectively character
57 * string start - 1). Used to initialize capture registers to a
58 * non-position.
59 * - register 0 ebp[-4] (only positions must be stored in the first
60 * - register 1 ebp[-8] num_saved_registers_ registers)
61 * - ...
62 *
63 * The first num_saved_registers_ registers are initialized to point to
64 * "character -1" in the string (i.e., char_size() bytes before the first
65 * character of the string). The remaining registers starts out as garbage.
66 *
67 * The data up to the return address must be placed there by the calling
68 * code, by calling the code entry as cast to a function with the signature:
69 * int (*match)(String input_string,
70 * int start_index,
71 * Address start,
72 * Address end,
73 * int* capture_output_array,
74 * int num_capture_registers,
75 * bool direct_call = false,
76 * Isolate* isolate
77 * Address regexp);
78 */
79
80 #define __ ACCESS_MASM(masm_)
81
82 const int RegExpMacroAssemblerIA32::kRegExpCodeSize;
83
RegExpMacroAssemblerIA32(Isolate* isolate, Zone* zone, Mode mode, int registers_to_save)84 RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(Isolate* isolate, Zone* zone,
85 Mode mode,
86 int registers_to_save)
87 : NativeRegExpMacroAssembler(isolate, zone),
88 masm_(std::make_unique<MacroAssembler>(
89 isolate, CodeObjectRequired::kYes,
90 NewAssemblerBuffer(kRegExpCodeSize))),
91 no_root_array_scope_(masm_.get()),
92 mode_(mode),
93 num_registers_(registers_to_save),
94 num_saved_registers_(registers_to_save),
95 entry_label_(),
96 start_label_(),
97 success_label_(),
98 backtrack_label_(),
99 exit_label_() {
100 DCHECK_EQ(0, registers_to_save % 2);
101 __ jmp(&entry_label_); // We'll write the entry code later.
102 __ bind(&start_label_); // And then continue from here.
103 }
104
~RegExpMacroAssemblerIA32()105 RegExpMacroAssemblerIA32::~RegExpMacroAssemblerIA32() {
106 // Unuse labels in case we throw away the assembler without calling GetCode.
107 entry_label_.Unuse();
108 start_label_.Unuse();
109 success_label_.Unuse();
110 backtrack_label_.Unuse();
111 exit_label_.Unuse();
112 check_preempt_label_.Unuse();
113 stack_overflow_label_.Unuse();
114 fallback_label_.Unuse();
115 }
116
117
stack_limit_slack()118 int RegExpMacroAssemblerIA32::stack_limit_slack() {
119 return RegExpStack::kStackLimitSlack;
120 }
121
122
AdvanceCurrentPosition(int by)123 void RegExpMacroAssemblerIA32::AdvanceCurrentPosition(int by) {
124 if (by != 0) {
125 __ add(edi, Immediate(by * char_size()));
126 }
127 }
128
129
AdvanceRegister(int reg, int by)130 void RegExpMacroAssemblerIA32::AdvanceRegister(int reg, int by) {
131 DCHECK_LE(0, reg);
132 DCHECK_GT(num_registers_, reg);
133 if (by != 0) {
134 __ add(register_location(reg), Immediate(by));
135 }
136 }
137
138
Backtrack()139 void RegExpMacroAssemblerIA32::Backtrack() {
140 CheckPreemption();
141 if (has_backtrack_limit()) {
142 Label next;
143 __ inc(Operand(ebp, kBacktrackCount));
144 __ cmp(Operand(ebp, kBacktrackCount), Immediate(backtrack_limit()));
145 __ j(not_equal, &next);
146
147 // Backtrack limit exceeded.
148 if (can_fallback()) {
149 __ jmp(&fallback_label_);
150 } else {
151 // Can't fallback, so we treat it as a failed match.
152 Fail();
153 }
154
155 __ bind(&next);
156 }
157 // Pop Code offset from backtrack stack, add Code and jump to location.
158 Pop(ebx);
159 __ add(ebx, Immediate(masm_->CodeObject()));
160 __ jmp(ebx);
161 }
162
163
Bind(Label* label)164 void RegExpMacroAssemblerIA32::Bind(Label* label) {
165 __ bind(label);
166 }
167
168
CheckCharacter(uint32_t c, Label* on_equal)169 void RegExpMacroAssemblerIA32::CheckCharacter(uint32_t c, Label* on_equal) {
170 __ cmp(current_character(), c);
171 BranchOrBacktrack(equal, on_equal);
172 }
173
CheckCharacterGT(base::uc16 limit, Label* on_greater)174 void RegExpMacroAssemblerIA32::CheckCharacterGT(base::uc16 limit,
175 Label* on_greater) {
176 __ cmp(current_character(), limit);
177 BranchOrBacktrack(greater, on_greater);
178 }
179
CheckAtStart(int cp_offset, Label* on_at_start)180 void RegExpMacroAssemblerIA32::CheckAtStart(int cp_offset, Label* on_at_start) {
181 __ lea(eax, Operand(edi, -char_size() + cp_offset * char_size()));
182 __ cmp(eax, Operand(ebp, kStringStartMinusOne));
183 BranchOrBacktrack(equal, on_at_start);
184 }
185
CheckNotAtStart(int cp_offset, Label* on_not_at_start)186 void RegExpMacroAssemblerIA32::CheckNotAtStart(int cp_offset,
187 Label* on_not_at_start) {
188 __ lea(eax, Operand(edi, -char_size() + cp_offset * char_size()));
189 __ cmp(eax, Operand(ebp, kStringStartMinusOne));
190 BranchOrBacktrack(not_equal, on_not_at_start);
191 }
192
CheckCharacterLT(base::uc16 limit, Label* on_less)193 void RegExpMacroAssemblerIA32::CheckCharacterLT(base::uc16 limit,
194 Label* on_less) {
195 __ cmp(current_character(), limit);
196 BranchOrBacktrack(less, on_less);
197 }
198
CheckGreedyLoop(Label* on_equal)199 void RegExpMacroAssemblerIA32::CheckGreedyLoop(Label* on_equal) {
200 Label fallthrough;
201 __ cmp(edi, Operand(backtrack_stackpointer(), 0));
202 __ j(not_equal, &fallthrough);
203 __ add(backtrack_stackpointer(), Immediate(kSystemPointerSize)); // Pop.
204 BranchOrBacktrack(no_condition, on_equal);
205 __ bind(&fallthrough);
206 }
207
PushCallerSavedRegisters()208 void RegExpMacroAssemblerIA32::PushCallerSavedRegisters() {
209 STATIC_ASSERT(backtrack_stackpointer() == ecx);
210 STATIC_ASSERT(current_character() == edx);
211 __ push(ecx);
212 __ push(edx);
213 }
214
PopCallerSavedRegisters()215 void RegExpMacroAssemblerIA32::PopCallerSavedRegisters() {
216 __ pop(edx);
217 __ pop(ecx);
218 }
219
CheckNotBackReferenceIgnoreCase( int start_reg, bool read_backward, bool unicode, Label* on_no_match)220 void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
221 int start_reg, bool read_backward, bool unicode, Label* on_no_match) {
222 Label fallthrough;
223 __ mov(edx, register_location(start_reg)); // Index of start of capture
224 __ mov(ebx, register_location(start_reg + 1)); // Index of end of capture
225 __ sub(ebx, edx); // Length of capture.
226
227 // At this point, the capture registers are either both set or both cleared.
228 // If the capture length is zero, then the capture is either empty or cleared.
229 // Fall through in both cases.
230 __ j(equal, &fallthrough);
231
232 // Check that there are sufficient characters left in the input.
233 if (read_backward) {
234 __ mov(eax, Operand(ebp, kStringStartMinusOne));
235 __ add(eax, ebx);
236 __ cmp(edi, eax);
237 BranchOrBacktrack(less_equal, on_no_match);
238 } else {
239 __ mov(eax, edi);
240 __ add(eax, ebx);
241 BranchOrBacktrack(greater, on_no_match);
242 }
243
244 if (mode_ == LATIN1) {
245 Label success;
246 Label fail;
247 Label loop_increment;
248 // Save register contents to make the registers available below.
249 __ push(edi);
250 __ push(backtrack_stackpointer());
251 // After this, the eax, ecx, and edi registers are available.
252
253 __ add(edx, esi); // Start of capture
254 __ add(edi, esi); // Start of text to match against capture.
255 if (read_backward) {
256 __ sub(edi, ebx); // Offset by length when matching backwards.
257 }
258 __ add(ebx, edi); // End of text to match against capture.
259
260 Label loop;
261 __ bind(&loop);
262 __ movzx_b(eax, Operand(edi, 0));
263 __ cmpb_al(Operand(edx, 0));
264 __ j(equal, &loop_increment);
265
266 // Mismatch, try case-insensitive match (converting letters to lower-case).
267 __ or_(eax, 0x20); // Convert match character to lower-case.
268 __ lea(ecx, Operand(eax, -'a'));
269 __ cmp(ecx, static_cast<int32_t>('z' - 'a')); // Is eax a lowercase letter?
270 Label convert_capture;
271 __ j(below_equal, &convert_capture); // In range 'a'-'z'.
272 // Latin-1: Check for values in range [224,254] but not 247.
273 __ sub(ecx, Immediate(224 - 'a'));
274 __ cmp(ecx, Immediate(254 - 224));
275 __ j(above, &fail); // Weren't Latin-1 letters.
276 __ cmp(ecx, Immediate(247 - 224)); // Check for 247.
277 __ j(equal, &fail);
278 __ bind(&convert_capture);
279 // Also convert capture character.
280 __ movzx_b(ecx, Operand(edx, 0));
281 __ or_(ecx, 0x20);
282
283 __ cmp(eax, ecx);
284 __ j(not_equal, &fail);
285
286 __ bind(&loop_increment);
287 // Increment pointers into match and capture strings.
288 __ add(edx, Immediate(1));
289 __ add(edi, Immediate(1));
290 // Compare to end of match, and loop if not done.
291 __ cmp(edi, ebx);
292 __ j(below, &loop);
293 __ jmp(&success);
294
295 __ bind(&fail);
296 // Restore original values before failing.
297 __ pop(backtrack_stackpointer());
298 __ pop(edi);
299 BranchOrBacktrack(no_condition, on_no_match);
300
301 __ bind(&success);
302 // Restore original value before continuing.
303 __ pop(backtrack_stackpointer());
304 // Drop original value of character position.
305 __ add(esp, Immediate(kSystemPointerSize));
306 // Compute new value of character position after the matched part.
307 __ sub(edi, esi);
308 if (read_backward) {
309 // Subtract match length if we matched backward.
310 __ add(edi, register_location(start_reg));
311 __ sub(edi, register_location(start_reg + 1));
312 }
313 } else {
314 DCHECK(mode_ == UC16);
315 // Save registers before calling C function.
316 __ push(esi);
317 __ push(edi);
318 __ push(backtrack_stackpointer());
319 __ push(ebx);
320
321 static const int argument_count = 4;
322 __ PrepareCallCFunction(argument_count, ecx);
323 // Put arguments into allocated stack area, last argument highest on stack.
324 // Parameters are
325 // Address byte_offset1 - Address captured substring's start.
326 // Address byte_offset2 - Address of current character position.
327 // size_t byte_length - length of capture in bytes(!)
328 // Isolate* isolate.
329
330 // Set isolate.
331 __ mov(Operand(esp, 3 * kSystemPointerSize),
332 Immediate(ExternalReference::isolate_address(isolate())));
333 // Set byte_length.
334 __ mov(Operand(esp, 2 * kSystemPointerSize), ebx);
335 // Set byte_offset2.
336 // Found by adding negative string-end offset of current position (edi)
337 // to end of string.
338 __ add(edi, esi);
339 if (read_backward) {
340 __ sub(edi, ebx); // Offset by length when matching backwards.
341 }
342 __ mov(Operand(esp, 1 * kSystemPointerSize), edi);
343 // Set byte_offset1.
344 // Start of capture, where edx already holds string-end negative offset.
345 __ add(edx, esi);
346 __ mov(Operand(esp, 0 * kSystemPointerSize), edx);
347
348 {
349 AllowExternalCallThatCantCauseGC scope(masm_.get());
350 ExternalReference compare =
351 unicode
352 ? ExternalReference::re_case_insensitive_compare_unicode()
353 : ExternalReference::re_case_insensitive_compare_non_unicode();
354 __ CallCFunction(compare, argument_count);
355 }
356 // Pop original values before reacting on result value.
357 __ pop(ebx);
358 __ pop(backtrack_stackpointer());
359 __ pop(edi);
360 __ pop(esi);
361
362 // Check if function returned non-zero for success or zero for failure.
363 __ or_(eax, eax);
364 BranchOrBacktrack(zero, on_no_match);
365 // On success, advance position by length of capture.
366 if (read_backward) {
367 __ sub(edi, ebx);
368 } else {
369 __ add(edi, ebx);
370 }
371 }
372 __ bind(&fallthrough);
373 }
374
CheckNotBackReference(int start_reg, bool read_backward, Label* on_no_match)375 void RegExpMacroAssemblerIA32::CheckNotBackReference(int start_reg,
376 bool read_backward,
377 Label* on_no_match) {
378 Label fallthrough;
379 Label success;
380 Label fail;
381
382 // Find length of back-referenced capture.
383 __ mov(edx, register_location(start_reg));
384 __ mov(eax, register_location(start_reg + 1));
385 __ sub(eax, edx); // Length to check.
386
387 // At this point, the capture registers are either both set or both cleared.
388 // If the capture length is zero, then the capture is either empty or cleared.
389 // Fall through in both cases.
390 __ j(equal, &fallthrough);
391
392 // Check that there are sufficient characters left in the input.
393 if (read_backward) {
394 __ mov(ebx, Operand(ebp, kStringStartMinusOne));
395 __ add(ebx, eax);
396 __ cmp(edi, ebx);
397 BranchOrBacktrack(less_equal, on_no_match);
398 } else {
399 __ mov(ebx, edi);
400 __ add(ebx, eax);
401 BranchOrBacktrack(greater, on_no_match);
402 }
403
404 // Save register to make it available below.
405 __ push(backtrack_stackpointer());
406
407 // Compute pointers to match string and capture string
408 __ add(edx, esi); // Start of capture.
409 __ lea(ebx, Operand(esi, edi, times_1, 0)); // Start of match.
410 if (read_backward) {
411 __ sub(ebx, eax); // Offset by length when matching backwards.
412 }
413 __ lea(ecx, Operand(eax, ebx, times_1, 0)); // End of match
414
415 Label loop;
416 __ bind(&loop);
417 if (mode_ == LATIN1) {
418 __ movzx_b(eax, Operand(edx, 0));
419 __ cmpb_al(Operand(ebx, 0));
420 } else {
421 DCHECK(mode_ == UC16);
422 __ movzx_w(eax, Operand(edx, 0));
423 __ cmpw_ax(Operand(ebx, 0));
424 }
425 __ j(not_equal, &fail);
426 // Increment pointers into capture and match string.
427 __ add(edx, Immediate(char_size()));
428 __ add(ebx, Immediate(char_size()));
429 // Check if we have reached end of match area.
430 __ cmp(ebx, ecx);
431 __ j(below, &loop);
432 __ jmp(&success);
433
434 __ bind(&fail);
435 // Restore backtrack stackpointer.
436 __ pop(backtrack_stackpointer());
437 BranchOrBacktrack(no_condition, on_no_match);
438
439 __ bind(&success);
440 // Move current character position to position after match.
441 __ mov(edi, ecx);
442 __ sub(edi, esi);
443 if (read_backward) {
444 // Subtract match length if we matched backward.
445 __ add(edi, register_location(start_reg));
446 __ sub(edi, register_location(start_reg + 1));
447 }
448 // Restore backtrack stackpointer.
449 __ pop(backtrack_stackpointer());
450
451 __ bind(&fallthrough);
452 }
453
454
CheckNotCharacter(uint32_t c, Label* on_not_equal)455 void RegExpMacroAssemblerIA32::CheckNotCharacter(uint32_t c,
456 Label* on_not_equal) {
457 __ cmp(current_character(), c);
458 BranchOrBacktrack(not_equal, on_not_equal);
459 }
460
461
CheckCharacterAfterAnd(uint32_t c, uint32_t mask, Label* on_equal)462 void RegExpMacroAssemblerIA32::CheckCharacterAfterAnd(uint32_t c,
463 uint32_t mask,
464 Label* on_equal) {
465 if (c == 0) {
466 __ test(current_character(), Immediate(mask));
467 } else {
468 __ mov(eax, mask);
469 __ and_(eax, current_character());
470 __ cmp(eax, c);
471 }
472 BranchOrBacktrack(equal, on_equal);
473 }
474
475
CheckNotCharacterAfterAnd(uint32_t c, uint32_t mask, Label* on_not_equal)476 void RegExpMacroAssemblerIA32::CheckNotCharacterAfterAnd(uint32_t c,
477 uint32_t mask,
478 Label* on_not_equal) {
479 if (c == 0) {
480 __ test(current_character(), Immediate(mask));
481 } else {
482 __ mov(eax, mask);
483 __ and_(eax, current_character());
484 __ cmp(eax, c);
485 }
486 BranchOrBacktrack(not_equal, on_not_equal);
487 }
488
CheckNotCharacterAfterMinusAnd( base::uc16 c, base::uc16 minus, base::uc16 mask, Label* on_not_equal)489 void RegExpMacroAssemblerIA32::CheckNotCharacterAfterMinusAnd(
490 base::uc16 c, base::uc16 minus, base::uc16 mask, Label* on_not_equal) {
491 DCHECK_GT(String::kMaxUtf16CodeUnit, minus);
492 __ lea(eax, Operand(current_character(), -minus));
493 if (c == 0) {
494 __ test(eax, Immediate(mask));
495 } else {
496 __ and_(eax, mask);
497 __ cmp(eax, c);
498 }
499 BranchOrBacktrack(not_equal, on_not_equal);
500 }
501
CheckCharacterInRange(base::uc16 from, base::uc16 to, Label* on_in_range)502 void RegExpMacroAssemblerIA32::CheckCharacterInRange(base::uc16 from,
503 base::uc16 to,
504 Label* on_in_range) {
505 __ lea(eax, Operand(current_character(), -from));
506 __ cmp(eax, to - from);
507 BranchOrBacktrack(below_equal, on_in_range);
508 }
509
CheckCharacterNotInRange( base::uc16 from, base::uc16 to, Label* on_not_in_range)510 void RegExpMacroAssemblerIA32::CheckCharacterNotInRange(
511 base::uc16 from, base::uc16 to, Label* on_not_in_range) {
512 __ lea(eax, Operand(current_character(), -from));
513 __ cmp(eax, to - from);
514 BranchOrBacktrack(above, on_not_in_range);
515 }
516
CallIsCharacterInRangeArray( const ZoneList<CharacterRange>* ranges)517 void RegExpMacroAssemblerIA32::CallIsCharacterInRangeArray(
518 const ZoneList<CharacterRange>* ranges) {
519 PushCallerSavedRegisters();
520
521 static const int kNumArguments = 3;
522 __ PrepareCallCFunction(kNumArguments, ecx);
523
524 __ mov(Operand(esp, 0 * kSystemPointerSize), current_character());
525 __ mov(Operand(esp, 1 * kSystemPointerSize), GetOrAddRangeArray(ranges));
526 __ mov(Operand(esp, 2 * kSystemPointerSize),
527 Immediate(ExternalReference::isolate_address(isolate())));
528
529 {
530 // We have a frame (set up in GetCode), but the assembler doesn't know.
531 FrameScope scope(masm_.get(), StackFrame::MANUAL);
532 __ CallCFunction(ExternalReference::re_is_character_in_range_array(),
533 kNumArguments);
534 }
535
536 PopCallerSavedRegisters();
537 }
538
CheckCharacterInRangeArray( const ZoneList<CharacterRange>* ranges, Label* on_in_range)539 bool RegExpMacroAssemblerIA32::CheckCharacterInRangeArray(
540 const ZoneList<CharacterRange>* ranges, Label* on_in_range) {
541 CallIsCharacterInRangeArray(ranges);
542 __ or_(eax, eax);
543 BranchOrBacktrack(not_zero, on_in_range);
544 return true;
545 }
546
CheckCharacterNotInRangeArray( const ZoneList<CharacterRange>* ranges, Label* on_not_in_range)547 bool RegExpMacroAssemblerIA32::CheckCharacterNotInRangeArray(
548 const ZoneList<CharacterRange>* ranges, Label* on_not_in_range) {
549 CallIsCharacterInRangeArray(ranges);
550 __ or_(eax, eax);
551 BranchOrBacktrack(zero, on_not_in_range);
552 return true;
553 }
554
CheckBitInTable( Handle<ByteArray> table, Label* on_bit_set)555 void RegExpMacroAssemblerIA32::CheckBitInTable(
556 Handle<ByteArray> table,
557 Label* on_bit_set) {
558 __ mov(eax, Immediate(table));
559 Register index = current_character();
560 if (mode_ != LATIN1 || kTableMask != String::kMaxOneByteCharCode) {
561 __ mov(ebx, kTableSize - 1);
562 __ and_(ebx, current_character());
563 index = ebx;
564 }
565 __ cmpb(FieldOperand(eax, index, times_1, ByteArray::kHeaderSize),
566 Immediate(0));
567 BranchOrBacktrack(not_equal, on_bit_set);
568 }
569
CheckSpecialCharacterClass( StandardCharacterSet type, Label* on_no_match)570 bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(
571 StandardCharacterSet type, Label* on_no_match) {
572 // Range checks (c in min..max) are generally implemented by an unsigned
573 // (c - min) <= (max - min) check
574 // TODO(jgruber): No custom implementation (yet): s(UC16), S(UC16).
575 switch (type) {
576 case StandardCharacterSet::kWhitespace:
577 // Match space-characters.
578 if (mode_ == LATIN1) {
579 // One byte space characters are '\t'..'\r', ' ' and \u00a0.
580 Label success;
581 __ cmp(current_character(), ' ');
582 __ j(equal, &success, Label::kNear);
583 // Check range 0x09..0x0D.
584 __ lea(eax, Operand(current_character(), -'\t'));
585 __ cmp(eax, '\r' - '\t');
586 __ j(below_equal, &success, Label::kNear);
587 // \u00a0 (NBSP).
588 __ cmp(eax, 0x00A0 - '\t');
589 BranchOrBacktrack(not_equal, on_no_match);
590 __ bind(&success);
591 return true;
592 }
593 return false;
594 case StandardCharacterSet::kNotWhitespace:
595 // The emitted code for generic character classes is good enough.
596 return false;
597 case StandardCharacterSet::kDigit:
598 // Match ASCII digits ('0'..'9').
599 __ lea(eax, Operand(current_character(), -'0'));
600 __ cmp(eax, '9' - '0');
601 BranchOrBacktrack(above, on_no_match);
602 return true;
603 case StandardCharacterSet::kNotDigit:
604 // Match non ASCII-digits.
605 __ lea(eax, Operand(current_character(), -'0'));
606 __ cmp(eax, '9' - '0');
607 BranchOrBacktrack(below_equal, on_no_match);
608 return true;
609 case StandardCharacterSet::kLineTerminator:
610 // Match newlines (0x0A('\n'), 0x0D('\r'), 0x2028 or 0x2029).
611 // The opposite of '.'.
612 __ mov(eax, current_character());
613 __ xor_(eax, Immediate(0x01));
614 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0B or 0x0C.
615 __ sub(eax, Immediate(0x0B));
616 __ cmp(eax, 0x0C - 0x0B);
617 if (mode_ == LATIN1) {
618 BranchOrBacktrack(above, on_no_match);
619 } else {
620 Label done;
621 BranchOrBacktrack(below_equal, &done);
622 DCHECK_EQ(UC16, mode_);
623 // Compare original value to 0x2028 and 0x2029, using the already
624 // computed (current_char ^ 0x01 - 0x0B). I.e., check for
625 // 0x201D (0x2028 - 0x0B) or 0x201E.
626 __ sub(eax, Immediate(0x2028 - 0x0B));
627 __ cmp(eax, 1);
628 BranchOrBacktrack(above, on_no_match);
629 __ bind(&done);
630 }
631 return true;
632 case StandardCharacterSet::kNotLineTerminator: {
633 // Match non-newlines (not 0x0A('\n'), 0x0D('\r'), 0x2028 and 0x2029).
634 __ mov(eax, current_character());
635 __ xor_(eax, Immediate(0x01));
636 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0B or 0x0C.
637 __ sub(eax, Immediate(0x0B));
638 __ cmp(eax, 0x0C - 0x0B);
639 BranchOrBacktrack(below_equal, on_no_match);
640 if (mode_ == UC16) {
641 // Compare original value to 0x2028 and 0x2029, using the already
642 // computed (current_char ^ 0x01 - 0x0B). I.e., check for
643 // 0x201D (0x2028 - 0x0B) or 0x201E.
644 __ sub(eax, Immediate(0x2028 - 0x0B));
645 __ cmp(eax, 0x2029 - 0x2028);
646 BranchOrBacktrack(below_equal, on_no_match);
647 }
648 return true;
649 }
650 case StandardCharacterSet::kWord: {
651 if (mode_ != LATIN1) {
652 // Table is 256 entries, so all Latin1 characters can be tested.
653 __ cmp(current_character(), Immediate('z'));
654 BranchOrBacktrack(above, on_no_match);
655 }
656 DCHECK_EQ(0,
657 word_character_map[0]); // Character '\0' is not a word char.
658 ExternalReference word_map = ExternalReference::re_word_character_map();
659 __ test_b(current_character(),
660 Operand(current_character(), times_1, word_map.address(),
661 RelocInfo::EXTERNAL_REFERENCE));
662 BranchOrBacktrack(zero, on_no_match);
663 return true;
664 }
665 case StandardCharacterSet::kNotWord: {
666 Label done;
667 if (mode_ != LATIN1) {
668 // Table is 256 entries, so all Latin1 characters can be tested.
669 __ cmp(current_character(), Immediate('z'));
670 __ j(above, &done);
671 }
672 DCHECK_EQ(0,
673 word_character_map[0]); // Character '\0' is not a word char.
674 ExternalReference word_map = ExternalReference::re_word_character_map();
675 __ test_b(current_character(),
676 Operand(current_character(), times_1, word_map.address(),
677 RelocInfo::EXTERNAL_REFERENCE));
678 BranchOrBacktrack(not_zero, on_no_match);
679 if (mode_ != LATIN1) {
680 __ bind(&done);
681 }
682 return true;
683 }
684 // Non-standard classes (with no syntactic shorthand) used internally.
685 case StandardCharacterSet::kEverything:
686 // Match any character.
687 return true;
688 }
689 }
690
Fail()691 void RegExpMacroAssemblerIA32::Fail() {
692 STATIC_ASSERT(FAILURE == 0); // Return value for failure is zero.
693 if (!global()) {
694 __ Move(eax, Immediate(FAILURE));
695 }
696 __ jmp(&exit_label_);
697 }
698
LoadRegExpStackPointerFromMemory(Register dst)699 void RegExpMacroAssemblerIA32::LoadRegExpStackPointerFromMemory(Register dst) {
700 ExternalReference ref =
701 ExternalReference::address_of_regexp_stack_stack_pointer(isolate());
702 __ mov(dst, __ ExternalReferenceAsOperand(ref, dst));
703 }
704
StoreRegExpStackPointerToMemory( Register src, Register scratch)705 void RegExpMacroAssemblerIA32::StoreRegExpStackPointerToMemory(
706 Register src, Register scratch) {
707 ExternalReference ref =
708 ExternalReference::address_of_regexp_stack_stack_pointer(isolate());
709 __ mov(__ ExternalReferenceAsOperand(ref, scratch), src);
710 }
711
PushRegExpBasePointer(Register stack_pointer, Register scratch)712 void RegExpMacroAssemblerIA32::PushRegExpBasePointer(Register stack_pointer,
713 Register scratch) {
714 ExternalReference ref =
715 ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
716 __ mov(scratch, __ ExternalReferenceAsOperand(ref, scratch));
717 __ sub(scratch, stack_pointer);
718 __ mov(Operand(ebp, kRegExpStackBasePointer), scratch);
719 }
720
PopRegExpBasePointer(Register stack_pointer_out, Register scratch)721 void RegExpMacroAssemblerIA32::PopRegExpBasePointer(Register stack_pointer_out,
722 Register scratch) {
723 ExternalReference ref =
724 ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
725 __ mov(scratch, Operand(ebp, kRegExpStackBasePointer));
726 __ mov(stack_pointer_out,
727 __ ExternalReferenceAsOperand(ref, stack_pointer_out));
728 __ sub(stack_pointer_out, scratch);
729 StoreRegExpStackPointerToMemory(stack_pointer_out, scratch);
730 }
731
GetCode(Handle<String> source)732 Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
733 Label return_eax;
734 // Finalize code - write the entry point code now we know how many
735 // registers we need.
736
737 // Entry code:
738 __ bind(&entry_label_);
739
740 // Tell the system that we have a stack frame. Because the type is MANUAL, no
741 // code is generated.
742 FrameScope scope(masm_.get(), StackFrame::MANUAL);
743
744 // Actually emit code to start a new stack frame.
745 __ push(ebp);
746 __ mov(ebp, esp);
747 // Save callee-save registers. Order here should correspond to order of
748 // kBackup_ebx etc.
749 __ push(esi);
750 __ push(edi);
751 __ push(ebx); // Callee-save on MacOS.
752 STATIC_ASSERT(kLastCalleeSaveRegister == kBackup_ebx);
753
754 STATIC_ASSERT(kSuccessfulCaptures ==
755 kLastCalleeSaveRegister - kSystemPointerSize);
756 __ push(Immediate(0)); // Number of successful matches in a global regexp.
757 STATIC_ASSERT(kStringStartMinusOne ==
758 kSuccessfulCaptures - kSystemPointerSize);
759 __ push(Immediate(0)); // Make room for "string start - 1" constant.
760 STATIC_ASSERT(kBacktrackCount == kStringStartMinusOne - kSystemPointerSize);
761 __ push(Immediate(0)); // The backtrack counter.
762 STATIC_ASSERT(kRegExpStackBasePointer ==
763 kBacktrackCount - kSystemPointerSize);
764 __ push(Immediate(0)); // The regexp stack base ptr.
765
766 // Initialize backtrack stack pointer. It must not be clobbered from here on.
767 // Note the backtrack_stackpointer is *not* callee-saved.
768 STATIC_ASSERT(backtrack_stackpointer() == ecx);
769 LoadRegExpStackPointerFromMemory(backtrack_stackpointer());
770
771 // Store the regexp base pointer - we'll later restore it / write it to
772 // memory when returning from this irregexp code object.
773 PushRegExpBasePointer(backtrack_stackpointer(), eax);
774
775 {
776 // Check if we have space on the stack for registers.
777 Label stack_limit_hit, stack_ok;
778
779 ExternalReference stack_limit =
780 ExternalReference::address_of_jslimit(isolate());
781 __ mov(eax, esp);
782 __ sub(eax, StaticVariable(stack_limit));
783 // Handle it if the stack pointer is already below the stack limit.
784 __ j(below_equal, &stack_limit_hit);
785 // Check if there is room for the variable number of registers above
786 // the stack limit.
787 __ cmp(eax, num_registers_ * kSystemPointerSize);
788 __ j(above_equal, &stack_ok);
789 // Exit with OutOfMemory exception. There is not enough space on the stack
790 // for our working registers.
791 __ mov(eax, EXCEPTION);
792 __ jmp(&return_eax);
793
794 __ bind(&stack_limit_hit);
795 __ push(backtrack_stackpointer());
796 CallCheckStackGuardState(ebx);
797 __ pop(backtrack_stackpointer());
798 __ or_(eax, eax);
799 // If returned value is non-zero, we exit with the returned value as result.
800 __ j(not_zero, &return_eax);
801
802 __ bind(&stack_ok);
803 }
804
805 // Load start index for later use.
806 __ mov(ebx, Operand(ebp, kStartIndex));
807
808 // Allocate space on stack for registers.
809 __ AllocateStackSpace(num_registers_ * kSystemPointerSize);
810 // Load string length.
811 __ mov(esi, Operand(ebp, kInputEnd));
812 // Load input position.
813 __ mov(edi, Operand(ebp, kInputStart));
814 // Set up edi to be negative offset from string end.
815 __ sub(edi, esi);
816
817 // Set eax to address of char before start of the string.
818 // (effectively string position -1).
819 __ neg(ebx);
820 if (mode_ == UC16) {
821 __ lea(eax, Operand(edi, ebx, times_2, -char_size()));
822 } else {
823 __ lea(eax, Operand(edi, ebx, times_1, -char_size()));
824 }
825 // Store this value in a local variable, for use when clearing
826 // position registers.
827 __ mov(Operand(ebp, kStringStartMinusOne), eax);
828
829 Label load_char_start_regexp;
830 {
831 Label start_regexp;
832
833 // Load newline if index is at start, previous character otherwise.
834 __ cmp(Operand(ebp, kStartIndex), Immediate(0));
835 __ j(not_equal, &load_char_start_regexp, Label::kNear);
836 __ mov(current_character(), '\n');
837 __ jmp(&start_regexp, Label::kNear);
838
839 // Global regexp restarts matching here.
840 __ bind(&load_char_start_regexp);
841 // Load previous char as initial value of current character register.
842 LoadCurrentCharacterUnchecked(-1, 1);
843 __ bind(&start_regexp);
844 }
845
846 // Initialize on-stack registers.
847 if (num_saved_registers_ > 0) { // Always is, if generated from a regexp.
848 // Fill saved registers with initial value = start offset - 1
849 // Fill in stack push order, to avoid accessing across an unwritten
850 // page (a problem on Windows).
851 if (num_saved_registers_ > 8) {
852 DCHECK_EQ(ecx, backtrack_stackpointer());
853 __ push(ecx);
854 __ mov(ecx, kRegisterZero);
855 Label init_loop;
856 __ bind(&init_loop);
857 __ mov(Operand(ebp, ecx, times_1, 0), eax);
858 __ sub(ecx, Immediate(kSystemPointerSize));
859 __ cmp(ecx, kRegisterZero - num_saved_registers_ * kSystemPointerSize);
860 __ j(greater, &init_loop);
861 __ pop(ecx);
862 } else { // Unroll the loop.
863 for (int i = 0; i < num_saved_registers_; i++) {
864 __ mov(register_location(i), eax);
865 }
866 }
867 }
868
869 __ jmp(&start_label_);
870
871 // Exit code:
872 if (success_label_.is_linked()) {
873 // Save captures when successful.
874 __ bind(&success_label_);
875 if (num_saved_registers_ > 0) {
876 // copy captures to output
877 __ mov(ebx, Operand(ebp, kRegisterOutput));
878 __ mov(ecx, Operand(ebp, kInputEnd));
879 __ mov(edx, Operand(ebp, kStartIndex));
880 __ sub(ecx, Operand(ebp, kInputStart));
881 if (mode_ == UC16) {
882 __ lea(ecx, Operand(ecx, edx, times_2, 0));
883 } else {
884 __ add(ecx, edx);
885 }
886 for (int i = 0; i < num_saved_registers_; i++) {
887 __ mov(eax, register_location(i));
888 if (i == 0 && global_with_zero_length_check()) {
889 // Keep capture start in edx for the zero-length check later.
890 __ mov(edx, eax);
891 }
892 // Convert to index from start of string, not end.
893 __ add(eax, ecx);
894 if (mode_ == UC16) {
895 __ sar(eax, 1); // Convert byte index to character index.
896 }
897 __ mov(Operand(ebx, i * kSystemPointerSize), eax);
898 }
899 }
900
901 if (global()) {
902 // Restart matching if the regular expression is flagged as global.
903 // Increment success counter.
904 __ inc(Operand(ebp, kSuccessfulCaptures));
905 // Capture results have been stored, so the number of remaining global
906 // output registers is reduced by the number of stored captures.
907 __ mov(ecx, Operand(ebp, kNumOutputRegisters));
908 __ sub(ecx, Immediate(num_saved_registers_));
909 // Check whether we have enough room for another set of capture results.
910 __ cmp(ecx, Immediate(num_saved_registers_));
911 __ j(less, &exit_label_);
912
913 __ mov(Operand(ebp, kNumOutputRegisters), ecx);
914 // Advance the location for output.
915 __ add(Operand(ebp, kRegisterOutput),
916 Immediate(num_saved_registers_ * kSystemPointerSize));
917
918 // Prepare eax to initialize registers with its value in the next run.
919 __ mov(eax, Operand(ebp, kStringStartMinusOne));
920
921 // Restore the original regexp stack pointer value (effectively, pop the
922 // stored base pointer).
923 PopRegExpBasePointer(backtrack_stackpointer(), ebx);
924
925 if (global_with_zero_length_check()) {
926 // Special case for zero-length matches.
927 // edx: capture start index
928 __ cmp(edi, edx);
929 // Not a zero-length match, restart.
930 __ j(not_equal, &load_char_start_regexp);
931 // edi (offset from the end) is zero if we already reached the end.
932 __ test(edi, edi);
933 __ j(zero, &exit_label_, Label::kNear);
934 // Advance current position after a zero-length match.
935 Label advance;
936 __ bind(&advance);
937 if (mode_ == UC16) {
938 __ add(edi, Immediate(2));
939 } else {
940 __ inc(edi);
941 }
942 if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
943 }
944 __ jmp(&load_char_start_regexp);
945 } else {
946 __ mov(eax, Immediate(SUCCESS));
947 }
948 }
949
950 __ bind(&exit_label_);
951 if (global()) {
952 // Return the number of successful captures.
953 __ mov(eax, Operand(ebp, kSuccessfulCaptures));
954 }
955
956 __ bind(&return_eax);
957 // Restore the original regexp stack pointer value (effectively, pop the
958 // stored base pointer).
959 PopRegExpBasePointer(backtrack_stackpointer(), ebx);
960
961 // Skip esp past regexp registers.
962 __ lea(esp, Operand(ebp, kLastCalleeSaveRegister));
963 // Restore callee-save registers.
964 __ pop(ebx);
965 __ pop(edi);
966 __ pop(esi);
967 // Exit function frame, restore previous one.
968 __ pop(ebp);
969 __ ret(0);
970
971 // Backtrack code (branch target for conditional backtracks).
972 if (backtrack_label_.is_linked()) {
973 __ bind(&backtrack_label_);
974 Backtrack();
975 }
976
977 Label exit_with_exception;
978
979 // Preempt-code
980 if (check_preempt_label_.is_linked()) {
981 SafeCallTarget(&check_preempt_label_);
982
983 StoreRegExpStackPointerToMemory(backtrack_stackpointer(), edi);
984
985 __ push(edi);
986
987 CallCheckStackGuardState(ebx);
988 __ or_(eax, eax);
989 // If returning non-zero, we should end execution with the given
990 // result as return value.
991 __ j(not_zero, &return_eax);
992
993 __ pop(edi);
994
995 LoadRegExpStackPointerFromMemory(backtrack_stackpointer());
996
997 // String might have moved: Reload esi from frame.
998 __ mov(esi, Operand(ebp, kInputEnd));
999 SafeReturn();
1000 }
1001
1002 // Backtrack stack overflow code.
1003 if (stack_overflow_label_.is_linked()) {
1004 SafeCallTarget(&stack_overflow_label_);
1005 // Reached if the backtrack-stack limit has been hit.
1006
1007 // Save registers before calling C function.
1008 __ push(esi);
1009 __ push(edi);
1010
1011 StoreRegExpStackPointerToMemory(backtrack_stackpointer(), edi);
1012
1013 // Call GrowStack(isolate).
1014 static const int kNumArguments = 1;
1015 __ PrepareCallCFunction(kNumArguments, ebx);
1016 __ mov(Operand(esp, 0 * kSystemPointerSize),
1017 Immediate(ExternalReference::isolate_address(isolate())));
1018 __ CallCFunction(ExternalReference::re_grow_stack(), kNumArguments);
1019 // If return nullptr, we have failed to grow the stack, and
1020 // must exit with a stack-overflow exception.
1021 __ or_(eax, eax);
1022 __ j(equal, &exit_with_exception);
1023 // Otherwise use return value as new stack pointer.
1024 __ mov(backtrack_stackpointer(), eax);
1025 // Restore saved registers and continue.
1026 __ pop(edi);
1027 __ pop(esi);
1028 SafeReturn();
1029 }
1030
1031 if (exit_with_exception.is_linked()) {
1032 // If any of the code above needed to exit with an exception.
1033 __ bind(&exit_with_exception);
1034 // Exit with Result EXCEPTION(-1) to signal thrown exception.
1035 __ mov(eax, EXCEPTION);
1036 __ jmp(&return_eax);
1037 }
1038
1039 if (fallback_label_.is_linked()) {
1040 __ bind(&fallback_label_);
1041 __ mov(eax, FALLBACK_TO_EXPERIMENTAL);
1042 __ jmp(&return_eax);
1043 }
1044
1045 CodeDesc code_desc;
1046 masm_->GetCode(masm_->isolate(), &code_desc);
1047 Handle<Code> code =
1048 Factory::CodeBuilder(isolate(), code_desc, CodeKind::REGEXP)
1049 .set_self_reference(masm_->CodeObject())
1050 .Build();
1051 PROFILE(masm_->isolate(),
1052 RegExpCodeCreateEvent(Handle<AbstractCode>::cast(code), source));
1053 return Handle<HeapObject>::cast(code);
1054 }
1055
1056
GoTo(Label* to)1057 void RegExpMacroAssemblerIA32::GoTo(Label* to) {
1058 BranchOrBacktrack(no_condition, to);
1059 }
1060
1061
IfRegisterGE(int reg, int comparand, Label* if_ge)1062 void RegExpMacroAssemblerIA32::IfRegisterGE(int reg,
1063 int comparand,
1064 Label* if_ge) {
1065 __ cmp(register_location(reg), Immediate(comparand));
1066 BranchOrBacktrack(greater_equal, if_ge);
1067 }
1068
1069
IfRegisterLT(int reg, int comparand, Label* if_lt)1070 void RegExpMacroAssemblerIA32::IfRegisterLT(int reg,
1071 int comparand,
1072 Label* if_lt) {
1073 __ cmp(register_location(reg), Immediate(comparand));
1074 BranchOrBacktrack(less, if_lt);
1075 }
1076
1077
IfRegisterEqPos(int reg, Label* if_eq)1078 void RegExpMacroAssemblerIA32::IfRegisterEqPos(int reg,
1079 Label* if_eq) {
1080 __ cmp(edi, register_location(reg));
1081 BranchOrBacktrack(equal, if_eq);
1082 }
1083
1084
1085 RegExpMacroAssembler::IrregexpImplementation
Implementation()1086 RegExpMacroAssemblerIA32::Implementation() {
1087 return kIA32Implementation;
1088 }
1089
1090
PopCurrentPosition()1091 void RegExpMacroAssemblerIA32::PopCurrentPosition() {
1092 Pop(edi);
1093 }
1094
1095
PopRegister(int register_index)1096 void RegExpMacroAssemblerIA32::PopRegister(int register_index) {
1097 Pop(eax);
1098 __ mov(register_location(register_index), eax);
1099 }
1100
1101
PushBacktrack(Label* label)1102 void RegExpMacroAssemblerIA32::PushBacktrack(Label* label) {
1103 Push(Immediate::CodeRelativeOffset(label));
1104 CheckStackLimit();
1105 }
1106
1107
PushCurrentPosition()1108 void RegExpMacroAssemblerIA32::PushCurrentPosition() {
1109 Push(edi);
1110 }
1111
1112
PushRegister(int register_index, StackCheckFlag check_stack_limit)1113 void RegExpMacroAssemblerIA32::PushRegister(int register_index,
1114 StackCheckFlag check_stack_limit) {
1115 __ mov(eax, register_location(register_index));
1116 Push(eax);
1117 if (check_stack_limit) CheckStackLimit();
1118 }
1119
1120
ReadCurrentPositionFromRegister(int reg)1121 void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) {
1122 __ mov(edi, register_location(reg));
1123 }
1124
WriteStackPointerToRegister(int reg)1125 void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
1126 ExternalReference stack_top_address =
1127 ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
1128 __ mov(eax, __ ExternalReferenceAsOperand(stack_top_address, eax));
1129 __ sub(eax, backtrack_stackpointer());
1130 __ mov(register_location(reg), eax);
1131 }
1132
ReadStackPointerFromRegister(int reg)1133 void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) {
1134 ExternalReference stack_top_address =
1135 ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
1136 __ mov(backtrack_stackpointer(),
1137 __ ExternalReferenceAsOperand(stack_top_address,
1138 backtrack_stackpointer()));
1139 __ sub(backtrack_stackpointer(), register_location(reg));
1140 }
1141
SetCurrentPositionFromEnd(int by)1142 void RegExpMacroAssemblerIA32::SetCurrentPositionFromEnd(int by) {
1143 Label after_position;
1144 __ cmp(edi, -by * char_size());
1145 __ j(greater_equal, &after_position, Label::kNear);
1146 __ mov(edi, -by * char_size());
1147 // On RegExp code entry (where this operation is used), the character before
1148 // the current position is expected to be already loaded.
1149 // We have advanced the position, so it's safe to read backwards.
1150 LoadCurrentCharacterUnchecked(-1, 1);
1151 __ bind(&after_position);
1152 }
1153
1154
SetRegister(int register_index, int to)1155 void RegExpMacroAssemblerIA32::SetRegister(int register_index, int to) {
1156 DCHECK(register_index >= num_saved_registers_); // Reserved for positions!
1157 __ mov(register_location(register_index), Immediate(to));
1158 }
1159
1160
Succeed()1161 bool RegExpMacroAssemblerIA32::Succeed() {
1162 __ jmp(&success_label_);
1163 return global();
1164 }
1165
1166
WriteCurrentPositionToRegister(int reg, int cp_offset)1167 void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(int reg,
1168 int cp_offset) {
1169 if (cp_offset == 0) {
1170 __ mov(register_location(reg), edi);
1171 } else {
1172 __ lea(eax, Operand(edi, cp_offset * char_size()));
1173 __ mov(register_location(reg), eax);
1174 }
1175 }
1176
1177
ClearRegisters(int reg_from, int reg_to)1178 void RegExpMacroAssemblerIA32::ClearRegisters(int reg_from, int reg_to) {
1179 DCHECK(reg_from <= reg_to);
1180 __ mov(eax, Operand(ebp, kStringStartMinusOne));
1181 for (int reg = reg_from; reg <= reg_to; reg++) {
1182 __ mov(register_location(reg), eax);
1183 }
1184 }
1185
1186 // Private methods:
1187
CallCheckStackGuardState(Register scratch)1188 void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) {
1189 static const int num_arguments = 3;
1190 __ PrepareCallCFunction(num_arguments, scratch);
1191 // RegExp code frame pointer.
1192 __ mov(Operand(esp, 2 * kSystemPointerSize), ebp);
1193 // Code of self.
1194 __ mov(Operand(esp, 1 * kSystemPointerSize), Immediate(masm_->CodeObject()));
1195 // Next address on the stack (will be address of return address).
1196 __ lea(eax, Operand(esp, -kSystemPointerSize));
1197 __ mov(Operand(esp, 0 * kSystemPointerSize), eax);
1198 ExternalReference check_stack_guard =
1199 ExternalReference::re_check_stack_guard_state();
1200 __ CallCFunction(check_stack_guard, num_arguments);
1201 }
1202
StaticVariable(const ExternalReference& ext)1203 Operand RegExpMacroAssemblerIA32::StaticVariable(const ExternalReference& ext) {
1204 return Operand(ext.address(), RelocInfo::EXTERNAL_REFERENCE);
1205 }
1206
1207 // Helper function for reading a value out of a stack frame.
1208 template <typename T>
frame_entry(Address re_frame, int frame_offset)1209 static T& frame_entry(Address re_frame, int frame_offset) {
1210 return reinterpret_cast<T&>(Memory<int32_t>(re_frame + frame_offset));
1211 }
1212
1213
1214 template <typename T>
frame_entry_address(Address re_frame, int frame_offset)1215 static T* frame_entry_address(Address re_frame, int frame_offset) {
1216 return reinterpret_cast<T*>(re_frame + frame_offset);
1217 }
1218
CheckStackGuardState(Address* return_address, Address raw_code, Address re_frame)1219 int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
1220 Address raw_code,
1221 Address re_frame) {
1222 Code re_code = Code::cast(Object(raw_code));
1223 return NativeRegExpMacroAssembler::CheckStackGuardState(
1224 frame_entry<Isolate*>(re_frame, kIsolate),
1225 frame_entry<int>(re_frame, kStartIndex),
1226 static_cast<RegExp::CallOrigin>(frame_entry<int>(re_frame, kDirectCall)),
1227 return_address, re_code,
1228 frame_entry_address<Address>(re_frame, kInputString),
1229 frame_entry_address<const byte*>(re_frame, kInputStart),
1230 frame_entry_address<const byte*>(re_frame, kInputEnd));
1231 }
1232
1233
register_location(int register_index)1234 Operand RegExpMacroAssemblerIA32::register_location(int register_index) {
1235 DCHECK(register_index < (1<<30));
1236 if (num_registers_ <= register_index) {
1237 num_registers_ = register_index + 1;
1238 }
1239 return Operand(ebp, kRegisterZero - register_index * kSystemPointerSize);
1240 }
1241
1242
1243 void RegExpMacroAssemblerIA32::CheckPosition(int cp_offset,
1244 Label* on_outside_input) {
1245 if (cp_offset >= 0) {
1246 __ cmp(edi, -cp_offset * char_size());
1247 BranchOrBacktrack(greater_equal, on_outside_input);
1248 } else {
1249 __ lea(eax, Operand(edi, cp_offset * char_size()));
1250 __ cmp(eax, Operand(ebp, kStringStartMinusOne));
1251 BranchOrBacktrack(less_equal, on_outside_input);
1252 }
1253 }
1254
1255
1256 void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition,
1257 Label* to) {
1258 if (condition < 0) { // No condition
1259 if (to == nullptr) {
1260 Backtrack();
1261 return;
1262 }
1263 __ jmp(to);
1264 return;
1265 }
1266 if (to == nullptr) {
1267 __ j(condition, &backtrack_label_);
1268 return;
1269 }
1270 __ j(condition, to);
1271 }
1272
1273
1274 void RegExpMacroAssemblerIA32::SafeCall(Label* to) {
1275 Label return_to;
1276 __ push(Immediate::CodeRelativeOffset(&return_to));
1277 __ jmp(to);
1278 __ bind(&return_to);
1279 }
1280
1281
1282 void RegExpMacroAssemblerIA32::SafeReturn() {
1283 __ pop(ebx);
1284 __ add(ebx, Immediate(masm_->CodeObject()));
1285 __ jmp(ebx);
1286 }
1287
1288
1289 void RegExpMacroAssemblerIA32::SafeCallTarget(Label* name) {
1290 __ bind(name);
1291 }
1292
1293
1294 void RegExpMacroAssemblerIA32::Push(Register source) {
1295 DCHECK(source != backtrack_stackpointer());
1296 // Notice: This updates flags, unlike normal Push.
1297 __ sub(backtrack_stackpointer(), Immediate(kSystemPointerSize));
1298 __ mov(Operand(backtrack_stackpointer(), 0), source);
1299 }
1300
1301
1302 void RegExpMacroAssemblerIA32::Push(Immediate value) {
1303 // Notice: This updates flags, unlike normal Push.
1304 __ sub(backtrack_stackpointer(), Immediate(kSystemPointerSize));
1305 __ mov(Operand(backtrack_stackpointer(), 0), value);
1306 }
1307
1308
1309 void RegExpMacroAssemblerIA32::Pop(Register target) {
1310 DCHECK(target != backtrack_stackpointer());
1311 __ mov(target, Operand(backtrack_stackpointer(), 0));
1312 // Notice: This updates flags, unlike normal Pop.
1313 __ add(backtrack_stackpointer(), Immediate(kSystemPointerSize));
1314 }
1315
1316
1317 void RegExpMacroAssemblerIA32::CheckPreemption() {
1318 // Check for preemption.
1319 Label no_preempt;
1320 ExternalReference stack_limit =
1321 ExternalReference::address_of_jslimit(isolate());
1322 __ cmp(esp, StaticVariable(stack_limit));
1323 __ j(above, &no_preempt);
1324
1325 SafeCall(&check_preempt_label_);
1326
1327 __ bind(&no_preempt);
1328 }
1329
1330
1331 void RegExpMacroAssemblerIA32::CheckStackLimit() {
1332 Label no_stack_overflow;
1333 ExternalReference stack_limit =
1334 ExternalReference::address_of_regexp_stack_limit_address(isolate());
1335 __ cmp(backtrack_stackpointer(), StaticVariable(stack_limit));
1336 __ j(above, &no_stack_overflow);
1337
1338 SafeCall(&stack_overflow_label_);
1339
1340 __ bind(&no_stack_overflow);
1341 }
1342
1343
1344 void RegExpMacroAssemblerIA32::LoadCurrentCharacterUnchecked(int cp_offset,
1345 int characters) {
1346 if (mode_ == LATIN1) {
1347 if (characters == 4) {
1348 __ mov(current_character(), Operand(esi, edi, times_1, cp_offset));
1349 } else if (characters == 2) {
1350 __ movzx_w(current_character(), Operand(esi, edi, times_1, cp_offset));
1351 } else {
1352 DCHECK_EQ(1, characters);
1353 __ movzx_b(current_character(), Operand(esi, edi, times_1, cp_offset));
1354 }
1355 } else {
1356 DCHECK(mode_ == UC16);
1357 if (characters == 2) {
1358 __ mov(current_character(),
1359 Operand(esi, edi, times_1, cp_offset * sizeof(base::uc16)));
1360 } else {
1361 DCHECK_EQ(1, characters);
1362 __ movzx_w(current_character(),
1363 Operand(esi, edi, times_1, cp_offset * sizeof(base::uc16)));
1364 }
1365 }
1366 }
1367
1368
1369 #undef __
1370
1371 } // namespace internal
1372 } // namespace v8
1373
1374 #endif // V8_TARGET_ARCH_IA32
1375