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