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