1 // Copyright 2008-2009 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_IA32) 31 32 #include "unicode.h" 33 #include "log.h" 34 #include "regexp-stack.h" 35 #include "macro-assembler.h" 36 #include "regexp-macro-assembler.h" 37 #include "ia32/regexp-macro-assembler-ia32.h" 38 39 namespace v8 { 40 namespace internal { 41 42 #ifndef V8_INTERPRETED_REGEXP 43 /* 44 * This assembler uses the following register assignment convention 45 * - edx : current character. Must be loaded using LoadCurrentCharacter 46 * before using any of the dispatch methods. 47 * - edi : current position in input, as negative offset from end of string. 48 * Please notice that this is the byte offset, not the character offset! 49 * - esi : end of input (points to byte after last character in input). 50 * - ebp : frame pointer. Used to access arguments, local variables and 51 * RegExp registers. 52 * - esp : points to tip of C stack. 53 * - ecx : points to tip of backtrack stack 54 * 55 * The registers eax and ebx are free to use for computations. 56 * 57 * Each call to a public method should retain this convention. 58 * The stack will have the following structure: 59 * - Isolate* isolate (Address of the current isolate) 60 * - direct_call (if 1, direct call from JavaScript code, if 0 61 * call through the runtime system) 62 * - stack_area_base (High end of the memory area to use as 63 * backtracking stack) 64 * - int* capture_array (int[num_saved_registers_], for output). 65 * - end of input (Address of end of string) 66 * - start of input (Address of first character in string) 67 * - start index (character index of start) 68 * - String* input_string (location of a handle containing the string) 69 * --- frame alignment (if applicable) --- 70 * - return address 71 * ebp-> - old ebp 72 * - backup of caller esi 73 * - backup of caller edi 74 * - backup of caller ebx 75 * - Offset of location before start of input (effectively character 76 * position -1). Used to initialize capture registers to a non-position. 77 * - register 0 ebp[-4] (Only positions must be stored in the first 78 * - register 1 ebp[-8] num_saved_registers_ registers) 79 * - ... 80 * 81 * The first num_saved_registers_ registers are initialized to point to 82 * "character -1" in the string (i.e., char_size() bytes before the first 83 * character of the string). The remaining registers starts out as garbage. 84 * 85 * The data up to the return address must be placed there by the calling 86 * code, by calling the code entry as cast to a function with the signature: 87 * int (*match)(String* input_string, 88 * int start_index, 89 * Address start, 90 * Address end, 91 * int* capture_output_array, 92 * bool at_start, 93 * byte* stack_area_base, 94 * bool direct_call) 95 */ 96 97 #define __ ACCESS_MASM(masm_) 98 99 RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32( 100 Mode mode, 101 int registers_to_save) 102 : masm_(new MacroAssembler(Isolate::Current(), NULL, kRegExpCodeSize)), 103 mode_(mode), 104 num_registers_(registers_to_save), 105 num_saved_registers_(registers_to_save), 106 entry_label_(), 107 start_label_(), 108 success_label_(), 109 backtrack_label_(), 110 exit_label_() { 111 ASSERT_EQ(0, registers_to_save % 2); 112 __ jmp(&entry_label_); // We'll write the entry code later. 113 __ bind(&start_label_); // And then continue from here. 114 } 115 116 117 RegExpMacroAssemblerIA32::~RegExpMacroAssemblerIA32() { 118 delete masm_; 119 // Unuse labels in case we throw away the assembler without calling GetCode. 120 entry_label_.Unuse(); 121 start_label_.Unuse(); 122 success_label_.Unuse(); 123 backtrack_label_.Unuse(); 124 exit_label_.Unuse(); 125 check_preempt_label_.Unuse(); 126 stack_overflow_label_.Unuse(); 127 } 128 129 130 int RegExpMacroAssemblerIA32::stack_limit_slack() { 131 return RegExpStack::kStackLimitSlack; 132 } 133 134 135 void RegExpMacroAssemblerIA32::AdvanceCurrentPosition(int by) { 136 if (by != 0) { 137 __ add(Operand(edi), Immediate(by * char_size())); 138 } 139 } 140 141 142 void RegExpMacroAssemblerIA32::AdvanceRegister(int reg, int by) { 143 ASSERT(reg >= 0); 144 ASSERT(reg < num_registers_); 145 if (by != 0) { 146 __ add(register_location(reg), Immediate(by)); 147 } 148 } 149 150 151 void RegExpMacroAssemblerIA32::Backtrack() { 152 CheckPreemption(); 153 // Pop Code* offset from backtrack stack, add Code* and jump to location. 154 Pop(ebx); 155 __ add(Operand(ebx), Immediate(masm_->CodeObject())); 156 __ jmp(Operand(ebx)); 157 } 158 159 160 void RegExpMacroAssemblerIA32::Bind(Label* label) { 161 __ bind(label); 162 } 163 164 165 void RegExpMacroAssemblerIA32::CheckCharacter(uint32_t c, Label* on_equal) { 166 __ cmp(current_character(), c); 167 BranchOrBacktrack(equal, on_equal); 168 } 169 170 171 void RegExpMacroAssemblerIA32::CheckCharacterGT(uc16 limit, Label* on_greater) { 172 __ cmp(current_character(), limit); 173 BranchOrBacktrack(greater, on_greater); 174 } 175 176 177 void RegExpMacroAssemblerIA32::CheckAtStart(Label* on_at_start) { 178 Label not_at_start; 179 // Did we start the match at the start of the string at all? 180 __ cmp(Operand(ebp, kStartIndex), Immediate(0)); 181 BranchOrBacktrack(not_equal, ¬_at_start); 182 // If we did, are we still at the start of the input? 183 __ lea(eax, Operand(esi, edi, times_1, 0)); 184 __ cmp(eax, Operand(ebp, kInputStart)); 185 BranchOrBacktrack(equal, on_at_start); 186 __ bind(¬_at_start); 187 } 188 189 190 void RegExpMacroAssemblerIA32::CheckNotAtStart(Label* on_not_at_start) { 191 // Did we start the match at the start of the string at all? 192 __ cmp(Operand(ebp, kStartIndex), Immediate(0)); 193 BranchOrBacktrack(not_equal, on_not_at_start); 194 // If we did, are we still at the start of the input? 195 __ lea(eax, Operand(esi, edi, times_1, 0)); 196 __ cmp(eax, Operand(ebp, kInputStart)); 197 BranchOrBacktrack(not_equal, on_not_at_start); 198 } 199 200 201 void RegExpMacroAssemblerIA32::CheckCharacterLT(uc16 limit, Label* on_less) { 202 __ cmp(current_character(), limit); 203 BranchOrBacktrack(less, on_less); 204 } 205 206 207 void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str, 208 int cp_offset, 209 Label* on_failure, 210 bool check_end_of_string) { 211 #ifdef DEBUG 212 // If input is ASCII, don't even bother calling here if the string to 213 // match contains a non-ascii character. 214 if (mode_ == ASCII) { 215 ASSERT(String::IsAscii(str.start(), str.length())); 216 } 217 #endif 218 int byte_length = str.length() * char_size(); 219 int byte_offset = cp_offset * char_size(); 220 if (check_end_of_string) { 221 // Check that there are at least str.length() characters left in the input. 222 __ cmp(Operand(edi), Immediate(-(byte_offset + byte_length))); 223 BranchOrBacktrack(greater, on_failure); 224 } 225 226 if (on_failure == NULL) { 227 // Instead of inlining a backtrack, (re)use the global backtrack target. 228 on_failure = &backtrack_label_; 229 } 230 231 // Do one character test first to minimize loading for the case that 232 // we don't match at all (loading more than one character introduces that 233 // chance of reading unaligned and reading across cache boundaries). 234 // If the first character matches, expect a larger chance of matching the 235 // string, and start loading more characters at a time. 236 if (mode_ == ASCII) { 237 __ cmpb(Operand(esi, edi, times_1, byte_offset), 238 static_cast<int8_t>(str[0])); 239 } else { 240 // Don't use 16-bit immediate. The size changing prefix throws off 241 // pre-decoding. 242 __ movzx_w(eax, 243 Operand(esi, edi, times_1, byte_offset)); 244 __ cmp(eax, static_cast<int32_t>(str[0])); 245 } 246 BranchOrBacktrack(not_equal, on_failure); 247 248 __ lea(ebx, Operand(esi, edi, times_1, 0)); 249 for (int i = 1, n = str.length(); i < n;) { 250 if (mode_ == ASCII) { 251 if (i <= n - 4) { 252 int combined_chars = 253 (static_cast<uint32_t>(str[i + 0]) << 0) | 254 (static_cast<uint32_t>(str[i + 1]) << 8) | 255 (static_cast<uint32_t>(str[i + 2]) << 16) | 256 (static_cast<uint32_t>(str[i + 3]) << 24); 257 __ cmp(Operand(ebx, byte_offset + i), Immediate(combined_chars)); 258 i += 4; 259 } else { 260 __ cmpb(Operand(ebx, byte_offset + i), 261 static_cast<int8_t>(str[i])); 262 i += 1; 263 } 264 } else { 265 ASSERT(mode_ == UC16); 266 if (i <= n - 2) { 267 __ cmp(Operand(ebx, byte_offset + i * sizeof(uc16)), 268 Immediate(*reinterpret_cast<const int*>(&str[i]))); 269 i += 2; 270 } else { 271 // Avoid a 16-bit immediate operation. It uses the length-changing 272 // 0x66 prefix which causes pre-decoder misprediction and pipeline 273 // stalls. See 274 // "Intel(R) 64 and IA-32 Architectures Optimization Reference Manual" 275 // (248966.pdf) section 3.4.2.3 "Length-Changing Prefixes (LCP)" 276 __ movzx_w(eax, 277 Operand(ebx, byte_offset + i * sizeof(uc16))); 278 __ cmp(eax, static_cast<int32_t>(str[i])); 279 i += 1; 280 } 281 } 282 BranchOrBacktrack(not_equal, on_failure); 283 } 284 } 285 286 287 void RegExpMacroAssemblerIA32::CheckGreedyLoop(Label* on_equal) { 288 Label fallthrough; 289 __ cmp(edi, Operand(backtrack_stackpointer(), 0)); 290 __ j(not_equal, &fallthrough); 291 __ add(Operand(backtrack_stackpointer()), Immediate(kPointerSize)); // Pop. 292 BranchOrBacktrack(no_condition, on_equal); 293 __ bind(&fallthrough); 294 } 295 296 297 void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase( 298 int start_reg, 299 Label* on_no_match) { 300 Label fallthrough; 301 __ mov(edx, register_location(start_reg)); // Index of start of capture 302 __ mov(ebx, register_location(start_reg + 1)); // Index of end of capture 303 __ sub(ebx, Operand(edx)); // Length of capture. 304 305 // The length of a capture should not be negative. This can only happen 306 // if the end of the capture is unrecorded, or at a point earlier than 307 // the start of the capture. 308 BranchOrBacktrack(less, on_no_match, not_taken); 309 310 // If length is zero, either the capture is empty or it is completely 311 // uncaptured. In either case succeed immediately. 312 __ j(equal, &fallthrough); 313 314 if (mode_ == ASCII) { 315 Label success; 316 Label fail; 317 Label loop_increment; 318 // Save register contents to make the registers available below. 319 __ push(edi); 320 __ push(backtrack_stackpointer()); 321 // After this, the eax, ecx, and edi registers are available. 322 323 __ add(edx, Operand(esi)); // Start of capture 324 __ add(edi, Operand(esi)); // Start of text to match against capture. 325 __ add(ebx, Operand(edi)); // End of text to match against capture. 326 327 Label loop; 328 __ bind(&loop); 329 __ movzx_b(eax, Operand(edi, 0)); 330 __ cmpb_al(Operand(edx, 0)); 331 __ j(equal, &loop_increment); 332 333 // Mismatch, try case-insensitive match (converting letters to lower-case). 334 __ or_(eax, 0x20); // Convert match character to lower-case. 335 __ lea(ecx, Operand(eax, -'a')); 336 __ cmp(ecx, static_cast<int32_t>('z' - 'a')); // Is eax a lowercase letter? 337 __ j(above, &fail); 338 // Also convert capture character. 339 __ movzx_b(ecx, Operand(edx, 0)); 340 __ or_(ecx, 0x20); 341 342 __ cmp(eax, Operand(ecx)); 343 __ j(not_equal, &fail); 344 345 __ bind(&loop_increment); 346 // Increment pointers into match and capture strings. 347 __ add(Operand(edx), Immediate(1)); 348 __ add(Operand(edi), Immediate(1)); 349 // Compare to end of match, and loop if not done. 350 __ cmp(edi, Operand(ebx)); 351 __ j(below, &loop, taken); 352 __ jmp(&success); 353 354 __ bind(&fail); 355 // Restore original values before failing. 356 __ pop(backtrack_stackpointer()); 357 __ pop(edi); 358 BranchOrBacktrack(no_condition, on_no_match); 359 360 __ bind(&success); 361 // Restore original value before continuing. 362 __ pop(backtrack_stackpointer()); 363 // Drop original value of character position. 364 __ add(Operand(esp), Immediate(kPointerSize)); 365 // Compute new value of character position after the matched part. 366 __ sub(edi, Operand(esi)); 367 } else { 368 ASSERT(mode_ == UC16); 369 // Save registers before calling C function. 370 __ push(esi); 371 __ push(edi); 372 __ push(backtrack_stackpointer()); 373 __ push(ebx); 374 375 static const int argument_count = 4; 376 __ PrepareCallCFunction(argument_count, ecx); 377 // Put arguments into allocated stack area, last argument highest on stack. 378 // Parameters are 379 // Address byte_offset1 - Address captured substring's start. 380 // Address byte_offset2 - Address of current character position. 381 // size_t byte_length - length of capture in bytes(!) 382 // Isolate* isolate 383 384 // Set isolate. 385 __ mov(Operand(esp, 3 * kPointerSize), 386 Immediate(ExternalReference::isolate_address())); 387 // Set byte_length. 388 __ mov(Operand(esp, 2 * kPointerSize), ebx); 389 // Set byte_offset2. 390 // Found by adding negative string-end offset of current position (edi) 391 // to end of string. 392 __ add(edi, Operand(esi)); 393 __ mov(Operand(esp, 1 * kPointerSize), edi); 394 // Set byte_offset1. 395 // Start of capture, where edx already holds string-end negative offset. 396 __ add(edx, Operand(esi)); 397 __ mov(Operand(esp, 0 * kPointerSize), edx); 398 399 ExternalReference compare = 400 ExternalReference::re_case_insensitive_compare_uc16(masm_->isolate()); 401 __ CallCFunction(compare, argument_count); 402 // Pop original values before reacting on result value. 403 __ pop(ebx); 404 __ pop(backtrack_stackpointer()); 405 __ pop(edi); 406 __ pop(esi); 407 408 // Check if function returned non-zero for success or zero for failure. 409 __ or_(eax, Operand(eax)); 410 BranchOrBacktrack(zero, on_no_match); 411 // On success, increment position by length of capture. 412 __ add(edi, Operand(ebx)); 413 } 414 __ bind(&fallthrough); 415 } 416 417 418 void RegExpMacroAssemblerIA32::CheckNotBackReference( 419 int start_reg, 420 Label* on_no_match) { 421 Label fallthrough; 422 Label success; 423 Label fail; 424 425 // Find length of back-referenced capture. 426 __ mov(edx, register_location(start_reg)); 427 __ mov(eax, register_location(start_reg + 1)); 428 __ sub(eax, Operand(edx)); // Length to check. 429 // Fail on partial or illegal capture (start of capture after end of capture). 430 BranchOrBacktrack(less, on_no_match); 431 // Succeed on empty capture (including no capture) 432 __ j(equal, &fallthrough); 433 434 // Check that there are sufficient characters left in the input. 435 __ mov(ebx, edi); 436 __ add(ebx, Operand(eax)); 437 BranchOrBacktrack(greater, on_no_match); 438 439 // Save register to make it available below. 440 __ push(backtrack_stackpointer()); 441 442 // Compute pointers to match string and capture string 443 __ lea(ebx, Operand(esi, edi, times_1, 0)); // Start of match. 444 __ add(edx, Operand(esi)); // Start of capture. 445 __ lea(ecx, Operand(eax, ebx, times_1, 0)); // End of match 446 447 Label loop; 448 __ bind(&loop); 449 if (mode_ == ASCII) { 450 __ movzx_b(eax, Operand(edx, 0)); 451 __ cmpb_al(Operand(ebx, 0)); 452 } else { 453 ASSERT(mode_ == UC16); 454 __ movzx_w(eax, Operand(edx, 0)); 455 __ cmpw_ax(Operand(ebx, 0)); 456 } 457 __ j(not_equal, &fail); 458 // Increment pointers into capture and match string. 459 __ add(Operand(edx), Immediate(char_size())); 460 __ add(Operand(ebx), Immediate(char_size())); 461 // Check if we have reached end of match area. 462 __ cmp(ebx, Operand(ecx)); 463 __ j(below, &loop); 464 __ jmp(&success); 465 466 __ bind(&fail); 467 // Restore backtrack stackpointer. 468 __ pop(backtrack_stackpointer()); 469 BranchOrBacktrack(no_condition, on_no_match); 470 471 __ bind(&success); 472 // Move current character position to position after match. 473 __ mov(edi, ecx); 474 __ sub(Operand(edi), esi); 475 // Restore backtrack stackpointer. 476 __ pop(backtrack_stackpointer()); 477 478 __ bind(&fallthrough); 479 } 480 481 482 void RegExpMacroAssemblerIA32::CheckNotRegistersEqual(int reg1, 483 int reg2, 484 Label* on_not_equal) { 485 __ mov(eax, register_location(reg1)); 486 __ cmp(eax, register_location(reg2)); 487 BranchOrBacktrack(not_equal, on_not_equal); 488 } 489 490 491 void RegExpMacroAssemblerIA32::CheckNotCharacter(uint32_t c, 492 Label* on_not_equal) { 493 __ cmp(current_character(), c); 494 BranchOrBacktrack(not_equal, on_not_equal); 495 } 496 497 498 void RegExpMacroAssemblerIA32::CheckCharacterAfterAnd(uint32_t c, 499 uint32_t mask, 500 Label* on_equal) { 501 __ mov(eax, current_character()); 502 __ and_(eax, mask); 503 __ cmp(eax, c); 504 BranchOrBacktrack(equal, on_equal); 505 } 506 507 508 void RegExpMacroAssemblerIA32::CheckNotCharacterAfterAnd(uint32_t c, 509 uint32_t mask, 510 Label* on_not_equal) { 511 __ mov(eax, current_character()); 512 __ and_(eax, mask); 513 __ cmp(eax, c); 514 BranchOrBacktrack(not_equal, on_not_equal); 515 } 516 517 518 void RegExpMacroAssemblerIA32::CheckNotCharacterAfterMinusAnd( 519 uc16 c, 520 uc16 minus, 521 uc16 mask, 522 Label* on_not_equal) { 523 ASSERT(minus < String::kMaxUC16CharCode); 524 __ lea(eax, Operand(current_character(), -minus)); 525 __ and_(eax, mask); 526 __ cmp(eax, c); 527 BranchOrBacktrack(not_equal, on_not_equal); 528 } 529 530 531 bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type, 532 Label* on_no_match) { 533 // Range checks (c in min..max) are generally implemented by an unsigned 534 // (c - min) <= (max - min) check 535 switch (type) { 536 case 's': 537 // Match space-characters 538 if (mode_ == ASCII) { 539 // ASCII space characters are '\t'..'\r' and ' '. 540 Label success; 541 __ cmp(current_character(), ' '); 542 __ j(equal, &success); 543 // Check range 0x09..0x0d 544 __ lea(eax, Operand(current_character(), -'\t')); 545 __ cmp(eax, '\r' - '\t'); 546 BranchOrBacktrack(above, on_no_match); 547 __ bind(&success); 548 return true; 549 } 550 return false; 551 case 'S': 552 // Match non-space characters. 553 if (mode_ == ASCII) { 554 // ASCII space characters are '\t'..'\r' and ' '. 555 __ cmp(current_character(), ' '); 556 BranchOrBacktrack(equal, on_no_match); 557 __ lea(eax, Operand(current_character(), -'\t')); 558 __ cmp(eax, '\r' - '\t'); 559 BranchOrBacktrack(below_equal, on_no_match); 560 return true; 561 } 562 return false; 563 case 'd': 564 // Match ASCII digits ('0'..'9') 565 __ lea(eax, Operand(current_character(), -'0')); 566 __ cmp(eax, '9' - '0'); 567 BranchOrBacktrack(above, on_no_match); 568 return true; 569 case 'D': 570 // Match non ASCII-digits 571 __ lea(eax, Operand(current_character(), -'0')); 572 __ cmp(eax, '9' - '0'); 573 BranchOrBacktrack(below_equal, on_no_match); 574 return true; 575 case '.': { 576 // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029) 577 __ mov(Operand(eax), current_character()); 578 __ xor_(Operand(eax), Immediate(0x01)); 579 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c 580 __ sub(Operand(eax), Immediate(0x0b)); 581 __ cmp(eax, 0x0c - 0x0b); 582 BranchOrBacktrack(below_equal, on_no_match); 583 if (mode_ == UC16) { 584 // Compare original value to 0x2028 and 0x2029, using the already 585 // computed (current_char ^ 0x01 - 0x0b). I.e., check for 586 // 0x201d (0x2028 - 0x0b) or 0x201e. 587 __ sub(Operand(eax), Immediate(0x2028 - 0x0b)); 588 __ cmp(eax, 0x2029 - 0x2028); 589 BranchOrBacktrack(below_equal, on_no_match); 590 } 591 return true; 592 } 593 case 'w': { 594 if (mode_ != ASCII) { 595 // Table is 128 entries, so all ASCII characters can be tested. 596 __ cmp(Operand(current_character()), Immediate('z')); 597 BranchOrBacktrack(above, on_no_match); 598 } 599 ASSERT_EQ(0, word_character_map[0]); // Character '\0' is not a word char. 600 ExternalReference word_map = ExternalReference::re_word_character_map(); 601 __ test_b(current_character(), 602 Operand::StaticArray(current_character(), times_1, word_map)); 603 BranchOrBacktrack(zero, on_no_match); 604 return true; 605 } 606 case 'W': { 607 Label done; 608 if (mode_ != ASCII) { 609 // Table is 128 entries, so all ASCII characters can be tested. 610 __ cmp(Operand(current_character()), Immediate('z')); 611 __ j(above, &done); 612 } 613 ASSERT_EQ(0, word_character_map[0]); // Character '\0' is not a word char. 614 ExternalReference word_map = ExternalReference::re_word_character_map(); 615 __ test_b(current_character(), 616 Operand::StaticArray(current_character(), times_1, word_map)); 617 BranchOrBacktrack(not_zero, on_no_match); 618 if (mode_ != ASCII) { 619 __ bind(&done); 620 } 621 return true; 622 } 623 // Non-standard classes (with no syntactic shorthand) used internally. 624 case '*': 625 // Match any character. 626 return true; 627 case 'n': { 628 // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 or 0x2029). 629 // The opposite of '.'. 630 __ mov(Operand(eax), current_character()); 631 __ xor_(Operand(eax), Immediate(0x01)); 632 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c 633 __ sub(Operand(eax), Immediate(0x0b)); 634 __ cmp(eax, 0x0c - 0x0b); 635 if (mode_ == ASCII) { 636 BranchOrBacktrack(above, on_no_match); 637 } else { 638 Label done; 639 BranchOrBacktrack(below_equal, &done); 640 ASSERT_EQ(UC16, mode_); 641 // Compare original value to 0x2028 and 0x2029, using the already 642 // computed (current_char ^ 0x01 - 0x0b). I.e., check for 643 // 0x201d (0x2028 - 0x0b) or 0x201e. 644 __ sub(Operand(eax), Immediate(0x2028 - 0x0b)); 645 __ cmp(eax, 1); 646 BranchOrBacktrack(above, on_no_match); 647 __ bind(&done); 648 } 649 return true; 650 } 651 // No custom implementation (yet): s(UC16), S(UC16). 652 default: 653 return false; 654 } 655 } 656 657 658 void RegExpMacroAssemblerIA32::Fail() { 659 ASSERT(FAILURE == 0); // Return value for failure is zero. 660 __ Set(eax, Immediate(0)); 661 __ jmp(&exit_label_); 662 } 663 664 665 Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) { 666 // Finalize code - write the entry point code now we know how many 667 // registers we need. 668 669 // Entry code: 670 __ bind(&entry_label_); 671 // Start new stack frame. 672 __ push(ebp); 673 __ mov(ebp, esp); 674 // Save callee-save registers. Order here should correspond to order of 675 // kBackup_ebx etc. 676 __ push(esi); 677 __ push(edi); 678 __ push(ebx); // Callee-save on MacOS. 679 __ push(Immediate(0)); // Make room for "input start - 1" constant. 680 681 // Check if we have space on the stack for registers. 682 Label stack_limit_hit; 683 Label stack_ok; 684 685 ExternalReference stack_limit = 686 ExternalReference::address_of_stack_limit(masm_->isolate()); 687 __ mov(ecx, esp); 688 __ sub(ecx, Operand::StaticVariable(stack_limit)); 689 // Handle it if the stack pointer is already below the stack limit. 690 __ j(below_equal, &stack_limit_hit, not_taken); 691 // Check if there is room for the variable number of registers above 692 // the stack limit. 693 __ cmp(ecx, num_registers_ * kPointerSize); 694 __ j(above_equal, &stack_ok, taken); 695 // Exit with OutOfMemory exception. There is not enough space on the stack 696 // for our working registers. 697 __ mov(eax, EXCEPTION); 698 __ jmp(&exit_label_); 699 700 __ bind(&stack_limit_hit); 701 CallCheckStackGuardState(ebx); 702 __ or_(eax, Operand(eax)); 703 // If returned value is non-zero, we exit with the returned value as result. 704 __ j(not_zero, &exit_label_); 705 706 __ bind(&stack_ok); 707 // Load start index for later use. 708 __ mov(ebx, Operand(ebp, kStartIndex)); 709 710 // Allocate space on stack for registers. 711 __ sub(Operand(esp), Immediate(num_registers_ * kPointerSize)); 712 // Load string length. 713 __ mov(esi, Operand(ebp, kInputEnd)); 714 // Load input position. 715 __ mov(edi, Operand(ebp, kInputStart)); 716 // Set up edi to be negative offset from string end. 717 __ sub(edi, Operand(esi)); 718 719 // Set eax to address of char before start of the string. 720 // (effectively string position -1). 721 __ neg(ebx); 722 if (mode_ == UC16) { 723 __ lea(eax, Operand(edi, ebx, times_2, -char_size())); 724 } else { 725 __ lea(eax, Operand(edi, ebx, times_1, -char_size())); 726 } 727 // Store this value in a local variable, for use when clearing 728 // position registers. 729 __ mov(Operand(ebp, kInputStartMinusOne), eax); 730 731 if (num_saved_registers_ > 0) { // Always is, if generated from a regexp. 732 // Fill saved registers with initial value = start offset - 1 733 // Fill in stack push order, to avoid accessing across an unwritten 734 // page (a problem on Windows). 735 __ mov(ecx, kRegisterZero); 736 Label init_loop; 737 __ bind(&init_loop); 738 __ mov(Operand(ebp, ecx, times_1, +0), eax); 739 __ sub(Operand(ecx), Immediate(kPointerSize)); 740 __ cmp(ecx, kRegisterZero - num_saved_registers_ * kPointerSize); 741 __ j(greater, &init_loop); 742 } 743 // Ensure that we have written to each stack page, in order. Skipping a page 744 // on Windows can cause segmentation faults. Assuming page size is 4k. 745 const int kPageSize = 4096; 746 const int kRegistersPerPage = kPageSize / kPointerSize; 747 for (int i = num_saved_registers_ + kRegistersPerPage - 1; 748 i < num_registers_; 749 i += kRegistersPerPage) { 750 __ mov(register_location(i), eax); // One write every page. 751 } 752 753 754 // Initialize backtrack stack pointer. 755 __ mov(backtrack_stackpointer(), Operand(ebp, kStackHighEnd)); 756 // Load previous char as initial value of current-character. 757 Label at_start; 758 __ cmp(Operand(ebp, kStartIndex), Immediate(0)); 759 __ j(equal, &at_start); 760 LoadCurrentCharacterUnchecked(-1, 1); // Load previous char. 761 __ jmp(&start_label_); 762 __ bind(&at_start); 763 __ mov(current_character(), '\n'); 764 __ jmp(&start_label_); 765 766 767 // Exit code: 768 if (success_label_.is_linked()) { 769 // Save captures when successful. 770 __ bind(&success_label_); 771 if (num_saved_registers_ > 0) { 772 // copy captures to output 773 __ mov(ebx, Operand(ebp, kRegisterOutput)); 774 __ mov(ecx, Operand(ebp, kInputEnd)); 775 __ mov(edx, Operand(ebp, kStartIndex)); 776 __ sub(ecx, Operand(ebp, kInputStart)); 777 if (mode_ == UC16) { 778 __ lea(ecx, Operand(ecx, edx, times_2, 0)); 779 } else { 780 __ add(ecx, Operand(edx)); 781 } 782 for (int i = 0; i < num_saved_registers_; i++) { 783 __ mov(eax, register_location(i)); 784 // Convert to index from start of string, not end. 785 __ add(eax, Operand(ecx)); 786 if (mode_ == UC16) { 787 __ sar(eax, 1); // Convert byte index to character index. 788 } 789 __ mov(Operand(ebx, i * kPointerSize), eax); 790 } 791 } 792 __ mov(eax, Immediate(SUCCESS)); 793 } 794 // Exit and return eax 795 __ bind(&exit_label_); 796 // Skip esp past regexp registers. 797 __ lea(esp, Operand(ebp, kBackup_ebx)); 798 // Restore callee-save registers. 799 __ pop(ebx); 800 __ pop(edi); 801 __ pop(esi); 802 // Exit function frame, restore previous one. 803 __ pop(ebp); 804 __ ret(0); 805 806 // Backtrack code (branch target for conditional backtracks). 807 if (backtrack_label_.is_linked()) { 808 __ bind(&backtrack_label_); 809 Backtrack(); 810 } 811 812 Label exit_with_exception; 813 814 // Preempt-code 815 if (check_preempt_label_.is_linked()) { 816 SafeCallTarget(&check_preempt_label_); 817 818 __ push(backtrack_stackpointer()); 819 __ push(edi); 820 821 CallCheckStackGuardState(ebx); 822 __ or_(eax, Operand(eax)); 823 // If returning non-zero, we should end execution with the given 824 // result as return value. 825 __ j(not_zero, &exit_label_); 826 827 __ pop(edi); 828 __ pop(backtrack_stackpointer()); 829 // String might have moved: Reload esi from frame. 830 __ mov(esi, Operand(ebp, kInputEnd)); 831 SafeReturn(); 832 } 833 834 // Backtrack stack overflow code. 835 if (stack_overflow_label_.is_linked()) { 836 SafeCallTarget(&stack_overflow_label_); 837 // Reached if the backtrack-stack limit has been hit. 838 839 Label grow_failed; 840 // Save registers before calling C function 841 __ push(esi); 842 __ push(edi); 843 844 // Call GrowStack(backtrack_stackpointer()) 845 static const int num_arguments = 3; 846 __ PrepareCallCFunction(num_arguments, ebx); 847 __ mov(Operand(esp, 2 * kPointerSize), 848 Immediate(ExternalReference::isolate_address())); 849 __ lea(eax, Operand(ebp, kStackHighEnd)); 850 __ mov(Operand(esp, 1 * kPointerSize), eax); 851 __ mov(Operand(esp, 0 * kPointerSize), backtrack_stackpointer()); 852 ExternalReference grow_stack = 853 ExternalReference::re_grow_stack(masm_->isolate()); 854 __ CallCFunction(grow_stack, num_arguments); 855 // If return NULL, we have failed to grow the stack, and 856 // must exit with a stack-overflow exception. 857 __ or_(eax, Operand(eax)); 858 __ j(equal, &exit_with_exception); 859 // Otherwise use return value as new stack pointer. 860 __ mov(backtrack_stackpointer(), eax); 861 // Restore saved registers and continue. 862 __ pop(edi); 863 __ pop(esi); 864 SafeReturn(); 865 } 866 867 if (exit_with_exception.is_linked()) { 868 // If any of the code above needed to exit with an exception. 869 __ bind(&exit_with_exception); 870 // Exit with Result EXCEPTION(-1) to signal thrown exception. 871 __ mov(eax, EXCEPTION); 872 __ jmp(&exit_label_); 873 } 874 875 CodeDesc code_desc; 876 masm_->GetCode(&code_desc); 877 Handle<Code> code = 878 masm_->isolate()->factory()->NewCode(code_desc, 879 Code::ComputeFlags(Code::REGEXP), 880 masm_->CodeObject()); 881 PROFILE(masm_->isolate(), RegExpCodeCreateEvent(*code, *source)); 882 return Handle<HeapObject>::cast(code); 883 } 884 885 886 void RegExpMacroAssemblerIA32::GoTo(Label* to) { 887 BranchOrBacktrack(no_condition, to); 888 } 889 890 891 void RegExpMacroAssemblerIA32::IfRegisterGE(int reg, 892 int comparand, 893 Label* if_ge) { 894 __ cmp(register_location(reg), Immediate(comparand)); 895 BranchOrBacktrack(greater_equal, if_ge); 896 } 897 898 899 void RegExpMacroAssemblerIA32::IfRegisterLT(int reg, 900 int comparand, 901 Label* if_lt) { 902 __ cmp(register_location(reg), Immediate(comparand)); 903 BranchOrBacktrack(less, if_lt); 904 } 905 906 907 void RegExpMacroAssemblerIA32::IfRegisterEqPos(int reg, 908 Label* if_eq) { 909 __ cmp(edi, register_location(reg)); 910 BranchOrBacktrack(equal, if_eq); 911 } 912 913 914 RegExpMacroAssembler::IrregexpImplementation 915 RegExpMacroAssemblerIA32::Implementation() { 916 return kIA32Implementation; 917 } 918 919 920 void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset, 921 Label* on_end_of_input, 922 bool check_bounds, 923 int characters) { 924 ASSERT(cp_offset >= -1); // ^ and \b can look behind one character. 925 ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works) 926 if (check_bounds) { 927 CheckPosition(cp_offset + characters - 1, on_end_of_input); 928 } 929 LoadCurrentCharacterUnchecked(cp_offset, characters); 930 } 931 932 933 void RegExpMacroAssemblerIA32::PopCurrentPosition() { 934 Pop(edi); 935 } 936 937 938 void RegExpMacroAssemblerIA32::PopRegister(int register_index) { 939 Pop(eax); 940 __ mov(register_location(register_index), eax); 941 } 942 943 944 void RegExpMacroAssemblerIA32::PushBacktrack(Label* label) { 945 Push(Immediate::CodeRelativeOffset(label)); 946 CheckStackLimit(); 947 } 948 949 950 void RegExpMacroAssemblerIA32::PushCurrentPosition() { 951 Push(edi); 952 } 953 954 955 void RegExpMacroAssemblerIA32::PushRegister(int register_index, 956 StackCheckFlag check_stack_limit) { 957 __ mov(eax, register_location(register_index)); 958 Push(eax); 959 if (check_stack_limit) CheckStackLimit(); 960 } 961 962 963 void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) { 964 __ mov(edi, register_location(reg)); 965 } 966 967 968 void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) { 969 __ mov(backtrack_stackpointer(), register_location(reg)); 970 __ add(backtrack_stackpointer(), Operand(ebp, kStackHighEnd)); 971 } 972 973 void RegExpMacroAssemblerIA32::SetCurrentPositionFromEnd(int by) { 974 NearLabel after_position; 975 __ cmp(edi, -by * char_size()); 976 __ j(greater_equal, &after_position); 977 __ mov(edi, -by * char_size()); 978 // On RegExp code entry (where this operation is used), the character before 979 // the current position is expected to be already loaded. 980 // We have advanced the position, so it's safe to read backwards. 981 LoadCurrentCharacterUnchecked(-1, 1); 982 __ bind(&after_position); 983 } 984 985 void RegExpMacroAssemblerIA32::SetRegister(int register_index, int to) { 986 ASSERT(register_index >= num_saved_registers_); // Reserved for positions! 987 __ mov(register_location(register_index), Immediate(to)); 988 } 989 990 991 void RegExpMacroAssemblerIA32::Succeed() { 992 __ jmp(&success_label_); 993 } 994 995 996 void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(int reg, 997 int cp_offset) { 998 if (cp_offset == 0) { 999 __ mov(register_location(reg), edi); 1000 } else { 1001 __ lea(eax, Operand(edi, cp_offset * char_size())); 1002 __ mov(register_location(reg), eax); 1003 } 1004 } 1005 1006 1007 void RegExpMacroAssemblerIA32::ClearRegisters(int reg_from, int reg_to) { 1008 ASSERT(reg_from <= reg_to); 1009 __ mov(eax, Operand(ebp, kInputStartMinusOne)); 1010 for (int reg = reg_from; reg <= reg_to; reg++) { 1011 __ mov(register_location(reg), eax); 1012 } 1013 } 1014 1015 1016 void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) { 1017 __ mov(eax, backtrack_stackpointer()); 1018 __ sub(eax, Operand(ebp, kStackHighEnd)); 1019 __ mov(register_location(reg), eax); 1020 } 1021 1022 1023 // Private methods: 1024 1025 void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) { 1026 static const int num_arguments = 3; 1027 __ PrepareCallCFunction(num_arguments, scratch); 1028 // RegExp code frame pointer. 1029 __ mov(Operand(esp, 2 * kPointerSize), ebp); 1030 // Code* of self. 1031 __ mov(Operand(esp, 1 * kPointerSize), Immediate(masm_->CodeObject())); 1032 // Next address on the stack (will be address of return address). 1033 __ lea(eax, Operand(esp, -kPointerSize)); 1034 __ mov(Operand(esp, 0 * kPointerSize), eax); 1035 ExternalReference check_stack_guard = 1036 ExternalReference::re_check_stack_guard_state(masm_->isolate()); 1037 __ CallCFunction(check_stack_guard, num_arguments); 1038 } 1039 1040 1041 // Helper function for reading a value out of a stack frame. 1042 template <typename T> 1043 static T& frame_entry(Address re_frame, int frame_offset) { 1044 return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset)); 1045 } 1046 1047 1048 int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address, 1049 Code* re_code, 1050 Address re_frame) { 1051 Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate); 1052 ASSERT(isolate == Isolate::Current()); 1053 if (isolate->stack_guard()->IsStackOverflow()) { 1054 isolate->StackOverflow(); 1055 return EXCEPTION; 1056 } 1057 1058 // If not real stack overflow the stack guard was used to interrupt 1059 // execution for another purpose. 1060 1061 // If this is a direct call from JavaScript retry the RegExp forcing the call 1062 // through the runtime system. Currently the direct call cannot handle a GC. 1063 if (frame_entry<int>(re_frame, kDirectCall) == 1) { 1064 return RETRY; 1065 } 1066 1067 // Prepare for possible GC. 1068 HandleScope handles; 1069 Handle<Code> code_handle(re_code); 1070 1071 Handle<String> subject(frame_entry<String*>(re_frame, kInputString)); 1072 // Current string. 1073 bool is_ascii = subject->IsAsciiRepresentation(); 1074 1075 ASSERT(re_code->instruction_start() <= *return_address); 1076 ASSERT(*return_address <= 1077 re_code->instruction_start() + re_code->instruction_size()); 1078 1079 MaybeObject* result = Execution::HandleStackGuardInterrupt(); 1080 1081 if (*code_handle != re_code) { // Return address no longer valid 1082 int delta = *code_handle - re_code; 1083 // Overwrite the return address on the stack. 1084 *return_address += delta; 1085 } 1086 1087 if (result->IsException()) { 1088 return EXCEPTION; 1089 } 1090 1091 // String might have changed. 1092 if (subject->IsAsciiRepresentation() != is_ascii) { 1093 // If we changed between an ASCII and an UC16 string, the specialized 1094 // code cannot be used, and we need to restart regexp matching from 1095 // scratch (including, potentially, compiling a new version of the code). 1096 return RETRY; 1097 } 1098 1099 // Otherwise, the content of the string might have moved. It must still 1100 // be a sequential or external string with the same content. 1101 // Update the start and end pointers in the stack frame to the current 1102 // location (whether it has actually moved or not). 1103 ASSERT(StringShape(*subject).IsSequential() || 1104 StringShape(*subject).IsExternal()); 1105 1106 // The original start address of the characters to match. 1107 const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart); 1108 1109 // Find the current start address of the same character at the current string 1110 // position. 1111 int start_index = frame_entry<int>(re_frame, kStartIndex); 1112 const byte* new_address = StringCharacterPosition(*subject, start_index); 1113 1114 if (start_address != new_address) { 1115 // If there is a difference, update the object pointer and start and end 1116 // addresses in the RegExp stack frame to match the new value. 1117 const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd); 1118 int byte_length = end_address - start_address; 1119 frame_entry<const String*>(re_frame, kInputString) = *subject; 1120 frame_entry<const byte*>(re_frame, kInputStart) = new_address; 1121 frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length; 1122 } 1123 1124 return 0; 1125 } 1126 1127 1128 Operand RegExpMacroAssemblerIA32::register_location(int register_index) { 1129 ASSERT(register_index < (1<<30)); 1130 if (num_registers_ <= register_index) { 1131 num_registers_ = register_index + 1; 1132 } 1133 return Operand(ebp, kRegisterZero - register_index * kPointerSize); 1134 } 1135 1136 1137 void RegExpMacroAssemblerIA32::CheckPosition(int cp_offset, 1138 Label* on_outside_input) { 1139 __ cmp(edi, -cp_offset * char_size()); 1140 BranchOrBacktrack(greater_equal, on_outside_input); 1141 } 1142 1143 1144 void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition, 1145 Label* to, 1146 Hint hint) { 1147 if (condition < 0) { // No condition 1148 if (to == NULL) { 1149 Backtrack(); 1150 return; 1151 } 1152 __ jmp(to); 1153 return; 1154 } 1155 if (to == NULL) { 1156 __ j(condition, &backtrack_label_, hint); 1157 return; 1158 } 1159 __ j(condition, to, hint); 1160 } 1161 1162 1163 void RegExpMacroAssemblerIA32::SafeCall(Label* to) { 1164 Label return_to; 1165 __ push(Immediate::CodeRelativeOffset(&return_to)); 1166 __ jmp(to); 1167 __ bind(&return_to); 1168 } 1169 1170 1171 void RegExpMacroAssemblerIA32::SafeReturn() { 1172 __ pop(ebx); 1173 __ add(Operand(ebx), Immediate(masm_->CodeObject())); 1174 __ jmp(Operand(ebx)); 1175 } 1176 1177 1178 void RegExpMacroAssemblerIA32::SafeCallTarget(Label* name) { 1179 __ bind(name); 1180 } 1181 1182 1183 void RegExpMacroAssemblerIA32::Push(Register source) { 1184 ASSERT(!source.is(backtrack_stackpointer())); 1185 // Notice: This updates flags, unlike normal Push. 1186 __ sub(Operand(backtrack_stackpointer()), Immediate(kPointerSize)); 1187 __ mov(Operand(backtrack_stackpointer(), 0), source); 1188 } 1189 1190 1191 void RegExpMacroAssemblerIA32::Push(Immediate value) { 1192 // Notice: This updates flags, unlike normal Push. 1193 __ sub(Operand(backtrack_stackpointer()), Immediate(kPointerSize)); 1194 __ mov(Operand(backtrack_stackpointer(), 0), value); 1195 } 1196 1197 1198 void RegExpMacroAssemblerIA32::Pop(Register target) { 1199 ASSERT(!target.is(backtrack_stackpointer())); 1200 __ mov(target, Operand(backtrack_stackpointer(), 0)); 1201 // Notice: This updates flags, unlike normal Pop. 1202 __ add(Operand(backtrack_stackpointer()), Immediate(kPointerSize)); 1203 } 1204 1205 1206 void RegExpMacroAssemblerIA32::CheckPreemption() { 1207 // Check for preemption. 1208 Label no_preempt; 1209 ExternalReference stack_limit = 1210 ExternalReference::address_of_stack_limit(masm_->isolate()); 1211 __ cmp(esp, Operand::StaticVariable(stack_limit)); 1212 __ j(above, &no_preempt, taken); 1213 1214 SafeCall(&check_preempt_label_); 1215 1216 __ bind(&no_preempt); 1217 } 1218 1219 1220 void RegExpMacroAssemblerIA32::CheckStackLimit() { 1221 Label no_stack_overflow; 1222 ExternalReference stack_limit = 1223 ExternalReference::address_of_regexp_stack_limit(masm_->isolate()); 1224 __ cmp(backtrack_stackpointer(), Operand::StaticVariable(stack_limit)); 1225 __ j(above, &no_stack_overflow); 1226 1227 SafeCall(&stack_overflow_label_); 1228 1229 __ bind(&no_stack_overflow); 1230 } 1231 1232 1233 void RegExpMacroAssemblerIA32::LoadCurrentCharacterUnchecked(int cp_offset, 1234 int characters) { 1235 if (mode_ == ASCII) { 1236 if (characters == 4) { 1237 __ mov(current_character(), Operand(esi, edi, times_1, cp_offset)); 1238 } else if (characters == 2) { 1239 __ movzx_w(current_character(), Operand(esi, edi, times_1, cp_offset)); 1240 } else { 1241 ASSERT(characters == 1); 1242 __ movzx_b(current_character(), Operand(esi, edi, times_1, cp_offset)); 1243 } 1244 } else { 1245 ASSERT(mode_ == UC16); 1246 if (characters == 2) { 1247 __ mov(current_character(), 1248 Operand(esi, edi, times_1, cp_offset * sizeof(uc16))); 1249 } else { 1250 ASSERT(characters == 1); 1251 __ movzx_w(current_character(), 1252 Operand(esi, edi, times_1, cp_offset * sizeof(uc16))); 1253 } 1254 } 1255 } 1256 1257 1258 #undef __ 1259 1260 #endif // V8_INTERPRETED_REGEXP 1261 1262 }} // namespace v8::internal 1263 1264 #endif // V8_TARGET_ARCH_IA32 1265