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