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