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