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