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_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(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(ebx, Immediate(masm_->CodeObject())); 156 __ jmp(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(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(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, 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); 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, esi); // Start of capture 324 __ add(edi, esi); // Start of text to match against capture. 325 __ add(ebx, 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, ecx); 343 __ j(not_equal, &fail); 344 345 __ bind(&loop_increment); 346 // Increment pointers into match and capture strings. 347 __ add(edx, Immediate(1)); 348 __ add(edi, Immediate(1)); 349 // Compare to end of match, and loop if not done. 350 __ cmp(edi, ebx); 351 __ j(below, &loop); 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(esp, Immediate(kPointerSize)); 365 // Compute new value of character position after the matched part. 366 __ sub(edi, 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, 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, esi); 397 __ mov(Operand(esp, 0 * kPointerSize), edx); 398 399 { 400 AllowExternalCallThatCantCauseGC scope(masm_); 401 ExternalReference compare = 402 ExternalReference::re_case_insensitive_compare_uc16(masm_->isolate()); 403 __ CallCFunction(compare, argument_count); 404 } 405 // Pop original values before reacting on result value. 406 __ pop(ebx); 407 __ pop(backtrack_stackpointer()); 408 __ pop(edi); 409 __ pop(esi); 410 411 // Check if function returned non-zero for success or zero for failure. 412 __ or_(eax, eax); 413 BranchOrBacktrack(zero, on_no_match); 414 // On success, increment position by length of capture. 415 __ add(edi, ebx); 416 } 417 __ bind(&fallthrough); 418 } 419 420 421 void RegExpMacroAssemblerIA32::CheckNotBackReference( 422 int start_reg, 423 Label* on_no_match) { 424 Label fallthrough; 425 Label success; 426 Label fail; 427 428 // Find length of back-referenced capture. 429 __ mov(edx, register_location(start_reg)); 430 __ mov(eax, register_location(start_reg + 1)); 431 __ sub(eax, edx); // Length to check. 432 // Fail on partial or illegal capture (start of capture after end of capture). 433 BranchOrBacktrack(less, on_no_match); 434 // Succeed on empty capture (including no capture) 435 __ j(equal, &fallthrough); 436 437 // Check that there are sufficient characters left in the input. 438 __ mov(ebx, edi); 439 __ add(ebx, eax); 440 BranchOrBacktrack(greater, on_no_match); 441 442 // Save register to make it available below. 443 __ push(backtrack_stackpointer()); 444 445 // Compute pointers to match string and capture string 446 __ lea(ebx, Operand(esi, edi, times_1, 0)); // Start of match. 447 __ add(edx, esi); // Start of capture. 448 __ lea(ecx, Operand(eax, ebx, times_1, 0)); // End of match 449 450 Label loop; 451 __ bind(&loop); 452 if (mode_ == ASCII) { 453 __ movzx_b(eax, Operand(edx, 0)); 454 __ cmpb_al(Operand(ebx, 0)); 455 } else { 456 ASSERT(mode_ == UC16); 457 __ movzx_w(eax, Operand(edx, 0)); 458 __ cmpw_ax(Operand(ebx, 0)); 459 } 460 __ j(not_equal, &fail); 461 // Increment pointers into capture and match string. 462 __ add(edx, Immediate(char_size())); 463 __ add(ebx, Immediate(char_size())); 464 // Check if we have reached end of match area. 465 __ cmp(ebx, ecx); 466 __ j(below, &loop); 467 __ jmp(&success); 468 469 __ bind(&fail); 470 // Restore backtrack stackpointer. 471 __ pop(backtrack_stackpointer()); 472 BranchOrBacktrack(no_condition, on_no_match); 473 474 __ bind(&success); 475 // Move current character position to position after match. 476 __ mov(edi, ecx); 477 __ sub(edi, esi); 478 // Restore backtrack stackpointer. 479 __ pop(backtrack_stackpointer()); 480 481 __ bind(&fallthrough); 482 } 483 484 485 void RegExpMacroAssemblerIA32::CheckNotRegistersEqual(int reg1, 486 int reg2, 487 Label* on_not_equal) { 488 __ mov(eax, register_location(reg1)); 489 __ cmp(eax, register_location(reg2)); 490 BranchOrBacktrack(not_equal, on_not_equal); 491 } 492 493 494 void RegExpMacroAssemblerIA32::CheckNotCharacter(uint32_t c, 495 Label* on_not_equal) { 496 __ cmp(current_character(), c); 497 BranchOrBacktrack(not_equal, on_not_equal); 498 } 499 500 501 void RegExpMacroAssemblerIA32::CheckCharacterAfterAnd(uint32_t c, 502 uint32_t mask, 503 Label* on_equal) { 504 __ mov(eax, current_character()); 505 __ and_(eax, mask); 506 __ cmp(eax, c); 507 BranchOrBacktrack(equal, on_equal); 508 } 509 510 511 void RegExpMacroAssemblerIA32::CheckNotCharacterAfterAnd(uint32_t c, 512 uint32_t mask, 513 Label* on_not_equal) { 514 __ mov(eax, current_character()); 515 __ and_(eax, mask); 516 __ cmp(eax, c); 517 BranchOrBacktrack(not_equal, on_not_equal); 518 } 519 520 521 void RegExpMacroAssemblerIA32::CheckNotCharacterAfterMinusAnd( 522 uc16 c, 523 uc16 minus, 524 uc16 mask, 525 Label* on_not_equal) { 526 ASSERT(minus < String::kMaxUtf16CodeUnit); 527 __ lea(eax, Operand(current_character(), -minus)); 528 __ and_(eax, mask); 529 __ cmp(eax, c); 530 BranchOrBacktrack(not_equal, on_not_equal); 531 } 532 533 534 bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type, 535 Label* on_no_match) { 536 // Range checks (c in min..max) are generally implemented by an unsigned 537 // (c - min) <= (max - min) check 538 switch (type) { 539 case 's': 540 // Match space-characters 541 if (mode_ == ASCII) { 542 // ASCII space characters are '\t'..'\r' and ' '. 543 Label success; 544 __ cmp(current_character(), ' '); 545 __ j(equal, &success); 546 // Check range 0x09..0x0d 547 __ lea(eax, Operand(current_character(), -'\t')); 548 __ cmp(eax, '\r' - '\t'); 549 BranchOrBacktrack(above, on_no_match); 550 __ bind(&success); 551 return true; 552 } 553 return false; 554 case 'S': 555 // Match non-space characters. 556 if (mode_ == ASCII) { 557 // ASCII space characters are '\t'..'\r' and ' '. 558 __ cmp(current_character(), ' '); 559 BranchOrBacktrack(equal, on_no_match); 560 __ lea(eax, Operand(current_character(), -'\t')); 561 __ cmp(eax, '\r' - '\t'); 562 BranchOrBacktrack(below_equal, on_no_match); 563 return true; 564 } 565 return false; 566 case 'd': 567 // Match ASCII digits ('0'..'9') 568 __ lea(eax, Operand(current_character(), -'0')); 569 __ cmp(eax, '9' - '0'); 570 BranchOrBacktrack(above, on_no_match); 571 return true; 572 case 'D': 573 // Match non ASCII-digits 574 __ lea(eax, Operand(current_character(), -'0')); 575 __ cmp(eax, '9' - '0'); 576 BranchOrBacktrack(below_equal, on_no_match); 577 return true; 578 case '.': { 579 // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029) 580 __ mov(eax, current_character()); 581 __ xor_(eax, Immediate(0x01)); 582 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c 583 __ sub(eax, Immediate(0x0b)); 584 __ cmp(eax, 0x0c - 0x0b); 585 BranchOrBacktrack(below_equal, on_no_match); 586 if (mode_ == UC16) { 587 // Compare original value to 0x2028 and 0x2029, using the already 588 // computed (current_char ^ 0x01 - 0x0b). I.e., check for 589 // 0x201d (0x2028 - 0x0b) or 0x201e. 590 __ sub(eax, Immediate(0x2028 - 0x0b)); 591 __ cmp(eax, 0x2029 - 0x2028); 592 BranchOrBacktrack(below_equal, on_no_match); 593 } 594 return true; 595 } 596 case 'w': { 597 if (mode_ != ASCII) { 598 // Table is 128 entries, so all ASCII characters can be tested. 599 __ cmp(current_character(), Immediate('z')); 600 BranchOrBacktrack(above, on_no_match); 601 } 602 ASSERT_EQ(0, word_character_map[0]); // Character '\0' is not a word char. 603 ExternalReference word_map = ExternalReference::re_word_character_map(); 604 __ test_b(current_character(), 605 Operand::StaticArray(current_character(), times_1, word_map)); 606 BranchOrBacktrack(zero, on_no_match); 607 return true; 608 } 609 case 'W': { 610 Label done; 611 if (mode_ != ASCII) { 612 // Table is 128 entries, so all ASCII characters can be tested. 613 __ cmp(current_character(), Immediate('z')); 614 __ j(above, &done); 615 } 616 ASSERT_EQ(0, word_character_map[0]); // Character '\0' is not a word char. 617 ExternalReference word_map = ExternalReference::re_word_character_map(); 618 __ test_b(current_character(), 619 Operand::StaticArray(current_character(), times_1, word_map)); 620 BranchOrBacktrack(not_zero, on_no_match); 621 if (mode_ != ASCII) { 622 __ bind(&done); 623 } 624 return true; 625 } 626 // Non-standard classes (with no syntactic shorthand) used internally. 627 case '*': 628 // Match any character. 629 return true; 630 case 'n': { 631 // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 or 0x2029). 632 // The opposite of '.'. 633 __ mov(eax, current_character()); 634 __ xor_(eax, Immediate(0x01)); 635 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c 636 __ sub(eax, Immediate(0x0b)); 637 __ cmp(eax, 0x0c - 0x0b); 638 if (mode_ == ASCII) { 639 BranchOrBacktrack(above, on_no_match); 640 } else { 641 Label done; 642 BranchOrBacktrack(below_equal, &done); 643 ASSERT_EQ(UC16, mode_); 644 // Compare original value to 0x2028 and 0x2029, using the already 645 // computed (current_char ^ 0x01 - 0x0b). I.e., check for 646 // 0x201d (0x2028 - 0x0b) or 0x201e. 647 __ sub(eax, Immediate(0x2028 - 0x0b)); 648 __ cmp(eax, 1); 649 BranchOrBacktrack(above, on_no_match); 650 __ bind(&done); 651 } 652 return true; 653 } 654 // No custom implementation (yet): s(UC16), S(UC16). 655 default: 656 return false; 657 } 658 } 659 660 661 void RegExpMacroAssemblerIA32::Fail() { 662 ASSERT(FAILURE == 0); // Return value for failure is zero. 663 __ Set(eax, Immediate(0)); 664 __ jmp(&exit_label_); 665 } 666 667 668 Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) { 669 // Finalize code - write the entry point code now we know how many 670 // registers we need. 671 672 // Entry code: 673 __ bind(&entry_label_); 674 675 // Tell the system that we have a stack frame. Because the type is MANUAL, no 676 // code is generated. 677 FrameScope scope(masm_, StackFrame::MANUAL); 678 679 // Actually emit code to start a new stack frame. 680 __ push(ebp); 681 __ mov(ebp, esp); 682 // Save callee-save registers. Order here should correspond to order of 683 // kBackup_ebx etc. 684 __ push(esi); 685 __ push(edi); 686 __ push(ebx); // Callee-save on MacOS. 687 __ push(Immediate(0)); // Make room for "input start - 1" constant. 688 689 // Check if we have space on the stack for registers. 690 Label stack_limit_hit; 691 Label stack_ok; 692 693 ExternalReference stack_limit = 694 ExternalReference::address_of_stack_limit(masm_->isolate()); 695 __ mov(ecx, esp); 696 __ sub(ecx, Operand::StaticVariable(stack_limit)); 697 // Handle it if the stack pointer is already below the stack limit. 698 __ j(below_equal, &stack_limit_hit); 699 // Check if there is room for the variable number of registers above 700 // the stack limit. 701 __ cmp(ecx, num_registers_ * kPointerSize); 702 __ j(above_equal, &stack_ok); 703 // Exit with OutOfMemory exception. There is not enough space on the stack 704 // for our working registers. 705 __ mov(eax, EXCEPTION); 706 __ jmp(&exit_label_); 707 708 __ bind(&stack_limit_hit); 709 CallCheckStackGuardState(ebx); 710 __ or_(eax, eax); 711 // If returned value is non-zero, we exit with the returned value as result. 712 __ j(not_zero, &exit_label_); 713 714 __ bind(&stack_ok); 715 // Load start index for later use. 716 __ mov(ebx, Operand(ebp, kStartIndex)); 717 718 // Allocate space on stack for registers. 719 __ sub(esp, Immediate(num_registers_ * kPointerSize)); 720 // Load string length. 721 __ mov(esi, Operand(ebp, kInputEnd)); 722 // Load input position. 723 __ mov(edi, Operand(ebp, kInputStart)); 724 // Set up edi to be negative offset from string end. 725 __ sub(edi, esi); 726 727 // Set eax to address of char before start of the string. 728 // (effectively string position -1). 729 __ neg(ebx); 730 if (mode_ == UC16) { 731 __ lea(eax, Operand(edi, ebx, times_2, -char_size())); 732 } else { 733 __ lea(eax, Operand(edi, ebx, times_1, -char_size())); 734 } 735 // Store this value in a local variable, for use when clearing 736 // position registers. 737 __ mov(Operand(ebp, kInputStartMinusOne), eax); 738 739 if (num_saved_registers_ > 0) { // Always is, if generated from a regexp. 740 // Fill saved registers with initial value = start offset - 1 741 // Fill in stack push order, to avoid accessing across an unwritten 742 // page (a problem on Windows). 743 __ mov(ecx, kRegisterZero); 744 Label init_loop; 745 __ bind(&init_loop); 746 __ mov(Operand(ebp, ecx, times_1, +0), eax); 747 __ sub(ecx, Immediate(kPointerSize)); 748 __ cmp(ecx, kRegisterZero - num_saved_registers_ * kPointerSize); 749 __ j(greater, &init_loop); 750 } 751 // Ensure that we have written to each stack page, in order. Skipping a page 752 // on Windows can cause segmentation faults. Assuming page size is 4k. 753 const int kPageSize = 4096; 754 const int kRegistersPerPage = kPageSize / kPointerSize; 755 for (int i = num_saved_registers_ + kRegistersPerPage - 1; 756 i < num_registers_; 757 i += kRegistersPerPage) { 758 __ mov(register_location(i), eax); // One write every page. 759 } 760 761 762 // Initialize backtrack stack pointer. 763 __ mov(backtrack_stackpointer(), Operand(ebp, kStackHighEnd)); 764 // Load previous char as initial value of current-character. 765 Label at_start; 766 __ cmp(Operand(ebp, kStartIndex), Immediate(0)); 767 __ j(equal, &at_start); 768 LoadCurrentCharacterUnchecked(-1, 1); // Load previous char. 769 __ jmp(&start_label_); 770 __ bind(&at_start); 771 __ mov(current_character(), '\n'); 772 __ jmp(&start_label_); 773 774 775 // Exit code: 776 if (success_label_.is_linked()) { 777 // Save captures when successful. 778 __ bind(&success_label_); 779 if (num_saved_registers_ > 0) { 780 // copy captures to output 781 __ mov(ebx, Operand(ebp, kRegisterOutput)); 782 __ mov(ecx, Operand(ebp, kInputEnd)); 783 __ mov(edx, Operand(ebp, kStartIndex)); 784 __ sub(ecx, Operand(ebp, kInputStart)); 785 if (mode_ == UC16) { 786 __ lea(ecx, Operand(ecx, edx, times_2, 0)); 787 } else { 788 __ add(ecx, edx); 789 } 790 for (int i = 0; i < num_saved_registers_; i++) { 791 __ mov(eax, register_location(i)); 792 // Convert to index from start of string, not end. 793 __ add(eax, ecx); 794 if (mode_ == UC16) { 795 __ sar(eax, 1); // Convert byte index to character index. 796 } 797 __ mov(Operand(ebx, i * kPointerSize), eax); 798 } 799 } 800 __ mov(eax, Immediate(SUCCESS)); 801 } 802 // Exit and return eax 803 __ bind(&exit_label_); 804 // Skip esp past regexp registers. 805 __ lea(esp, Operand(ebp, kBackup_ebx)); 806 // Restore callee-save registers. 807 __ pop(ebx); 808 __ pop(edi); 809 __ pop(esi); 810 // Exit function frame, restore previous one. 811 __ pop(ebp); 812 __ ret(0); 813 814 // Backtrack code (branch target for conditional backtracks). 815 if (backtrack_label_.is_linked()) { 816 __ bind(&backtrack_label_); 817 Backtrack(); 818 } 819 820 Label exit_with_exception; 821 822 // Preempt-code 823 if (check_preempt_label_.is_linked()) { 824 SafeCallTarget(&check_preempt_label_); 825 826 __ push(backtrack_stackpointer()); 827 __ push(edi); 828 829 CallCheckStackGuardState(ebx); 830 __ or_(eax, eax); 831 // If returning non-zero, we should end execution with the given 832 // result as return value. 833 __ j(not_zero, &exit_label_); 834 835 __ pop(edi); 836 __ pop(backtrack_stackpointer()); 837 // String might have moved: Reload esi from frame. 838 __ mov(esi, Operand(ebp, kInputEnd)); 839 SafeReturn(); 840 } 841 842 // Backtrack stack overflow code. 843 if (stack_overflow_label_.is_linked()) { 844 SafeCallTarget(&stack_overflow_label_); 845 // Reached if the backtrack-stack limit has been hit. 846 847 Label grow_failed; 848 // Save registers before calling C function 849 __ push(esi); 850 __ push(edi); 851 852 // Call GrowStack(backtrack_stackpointer()) 853 static const int num_arguments = 3; 854 __ PrepareCallCFunction(num_arguments, ebx); 855 __ mov(Operand(esp, 2 * kPointerSize), 856 Immediate(ExternalReference::isolate_address())); 857 __ lea(eax, Operand(ebp, kStackHighEnd)); 858 __ mov(Operand(esp, 1 * kPointerSize), eax); 859 __ mov(Operand(esp, 0 * kPointerSize), backtrack_stackpointer()); 860 ExternalReference grow_stack = 861 ExternalReference::re_grow_stack(masm_->isolate()); 862 __ CallCFunction(grow_stack, num_arguments); 863 // If return NULL, we have failed to grow the stack, and 864 // must exit with a stack-overflow exception. 865 __ or_(eax, eax); 866 __ j(equal, &exit_with_exception); 867 // Otherwise use return value as new stack pointer. 868 __ mov(backtrack_stackpointer(), eax); 869 // Restore saved registers and continue. 870 __ pop(edi); 871 __ pop(esi); 872 SafeReturn(); 873 } 874 875 if (exit_with_exception.is_linked()) { 876 // If any of the code above needed to exit with an exception. 877 __ bind(&exit_with_exception); 878 // Exit with Result EXCEPTION(-1) to signal thrown exception. 879 __ mov(eax, EXCEPTION); 880 __ jmp(&exit_label_); 881 } 882 883 CodeDesc code_desc; 884 masm_->GetCode(&code_desc); 885 Handle<Code> code = 886 masm_->isolate()->factory()->NewCode(code_desc, 887 Code::ComputeFlags(Code::REGEXP), 888 masm_->CodeObject()); 889 PROFILE(masm_->isolate(), RegExpCodeCreateEvent(*code, *source)); 890 return Handle<HeapObject>::cast(code); 891 } 892 893 894 void RegExpMacroAssemblerIA32::GoTo(Label* to) { 895 BranchOrBacktrack(no_condition, to); 896 } 897 898 899 void RegExpMacroAssemblerIA32::IfRegisterGE(int reg, 900 int comparand, 901 Label* if_ge) { 902 __ cmp(register_location(reg), Immediate(comparand)); 903 BranchOrBacktrack(greater_equal, if_ge); 904 } 905 906 907 void RegExpMacroAssemblerIA32::IfRegisterLT(int reg, 908 int comparand, 909 Label* if_lt) { 910 __ cmp(register_location(reg), Immediate(comparand)); 911 BranchOrBacktrack(less, if_lt); 912 } 913 914 915 void RegExpMacroAssemblerIA32::IfRegisterEqPos(int reg, 916 Label* if_eq) { 917 __ cmp(edi, register_location(reg)); 918 BranchOrBacktrack(equal, if_eq); 919 } 920 921 922 RegExpMacroAssembler::IrregexpImplementation 923 RegExpMacroAssemblerIA32::Implementation() { 924 return kIA32Implementation; 925 } 926 927 928 void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset, 929 Label* on_end_of_input, 930 bool check_bounds, 931 int characters) { 932 ASSERT(cp_offset >= -1); // ^ and \b can look behind one character. 933 ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works) 934 if (check_bounds) { 935 CheckPosition(cp_offset + characters - 1, on_end_of_input); 936 } 937 LoadCurrentCharacterUnchecked(cp_offset, characters); 938 } 939 940 941 void RegExpMacroAssemblerIA32::PopCurrentPosition() { 942 Pop(edi); 943 } 944 945 946 void RegExpMacroAssemblerIA32::PopRegister(int register_index) { 947 Pop(eax); 948 __ mov(register_location(register_index), eax); 949 } 950 951 952 void RegExpMacroAssemblerIA32::PushBacktrack(Label* label) { 953 Push(Immediate::CodeRelativeOffset(label)); 954 CheckStackLimit(); 955 } 956 957 958 void RegExpMacroAssemblerIA32::PushCurrentPosition() { 959 Push(edi); 960 } 961 962 963 void RegExpMacroAssemblerIA32::PushRegister(int register_index, 964 StackCheckFlag check_stack_limit) { 965 __ mov(eax, register_location(register_index)); 966 Push(eax); 967 if (check_stack_limit) CheckStackLimit(); 968 } 969 970 971 void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) { 972 __ mov(edi, register_location(reg)); 973 } 974 975 976 void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) { 977 __ mov(backtrack_stackpointer(), register_location(reg)); 978 __ add(backtrack_stackpointer(), Operand(ebp, kStackHighEnd)); 979 } 980 981 void RegExpMacroAssemblerIA32::SetCurrentPositionFromEnd(int by) { 982 Label after_position; 983 __ cmp(edi, -by * char_size()); 984 __ j(greater_equal, &after_position, Label::kNear); 985 __ mov(edi, -by * char_size()); 986 // On RegExp code entry (where this operation is used), the character before 987 // the current position is expected to be already loaded. 988 // We have advanced the position, so it's safe to read backwards. 989 LoadCurrentCharacterUnchecked(-1, 1); 990 __ bind(&after_position); 991 } 992 993 void RegExpMacroAssemblerIA32::SetRegister(int register_index, int to) { 994 ASSERT(register_index >= num_saved_registers_); // Reserved for positions! 995 __ mov(register_location(register_index), Immediate(to)); 996 } 997 998 999 void RegExpMacroAssemblerIA32::Succeed() { 1000 __ jmp(&success_label_); 1001 } 1002 1003 1004 void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(int reg, 1005 int cp_offset) { 1006 if (cp_offset == 0) { 1007 __ mov(register_location(reg), edi); 1008 } else { 1009 __ lea(eax, Operand(edi, cp_offset * char_size())); 1010 __ mov(register_location(reg), eax); 1011 } 1012 } 1013 1014 1015 void RegExpMacroAssemblerIA32::ClearRegisters(int reg_from, int reg_to) { 1016 ASSERT(reg_from <= reg_to); 1017 __ mov(eax, Operand(ebp, kInputStartMinusOne)); 1018 for (int reg = reg_from; reg <= reg_to; reg++) { 1019 __ mov(register_location(reg), eax); 1020 } 1021 } 1022 1023 1024 void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) { 1025 __ mov(eax, backtrack_stackpointer()); 1026 __ sub(eax, Operand(ebp, kStackHighEnd)); 1027 __ mov(register_location(reg), eax); 1028 } 1029 1030 1031 // Private methods: 1032 1033 void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) { 1034 static const int num_arguments = 3; 1035 __ PrepareCallCFunction(num_arguments, scratch); 1036 // RegExp code frame pointer. 1037 __ mov(Operand(esp, 2 * kPointerSize), ebp); 1038 // Code* of self. 1039 __ mov(Operand(esp, 1 * kPointerSize), Immediate(masm_->CodeObject())); 1040 // Next address on the stack (will be address of return address). 1041 __ lea(eax, Operand(esp, -kPointerSize)); 1042 __ mov(Operand(esp, 0 * kPointerSize), eax); 1043 ExternalReference check_stack_guard = 1044 ExternalReference::re_check_stack_guard_state(masm_->isolate()); 1045 __ CallCFunction(check_stack_guard, num_arguments); 1046 } 1047 1048 1049 // Helper function for reading a value out of a stack frame. 1050 template <typename T> 1051 static T& frame_entry(Address re_frame, int frame_offset) { 1052 return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset)); 1053 } 1054 1055 1056 int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address, 1057 Code* re_code, 1058 Address re_frame) { 1059 Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate); 1060 ASSERT(isolate == Isolate::Current()); 1061 if (isolate->stack_guard()->IsStackOverflow()) { 1062 isolate->StackOverflow(); 1063 return EXCEPTION; 1064 } 1065 1066 // If not real stack overflow the stack guard was used to interrupt 1067 // execution for another purpose. 1068 1069 // If this is a direct call from JavaScript retry the RegExp forcing the call 1070 // through the runtime system. Currently the direct call cannot handle a GC. 1071 if (frame_entry<int>(re_frame, kDirectCall) == 1) { 1072 return RETRY; 1073 } 1074 1075 // Prepare for possible GC. 1076 HandleScope handles(isolate); 1077 Handle<Code> code_handle(re_code); 1078 1079 Handle<String> subject(frame_entry<String*>(re_frame, kInputString)); 1080 1081 // Current string. 1082 bool is_ascii = subject->IsAsciiRepresentationUnderneath(); 1083 1084 ASSERT(re_code->instruction_start() <= *return_address); 1085 ASSERT(*return_address <= 1086 re_code->instruction_start() + re_code->instruction_size()); 1087 1088 MaybeObject* result = Execution::HandleStackGuardInterrupt(isolate); 1089 1090 if (*code_handle != re_code) { // Return address no longer valid 1091 int delta = code_handle->address() - re_code->address(); 1092 // Overwrite the return address on the stack. 1093 *return_address += delta; 1094 } 1095 1096 if (result->IsException()) { 1097 return EXCEPTION; 1098 } 1099 1100 Handle<String> subject_tmp = subject; 1101 int slice_offset = 0; 1102 1103 // Extract the underlying string and the slice offset. 1104 if (StringShape(*subject_tmp).IsCons()) { 1105 subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first()); 1106 } else if (StringShape(*subject_tmp).IsSliced()) { 1107 SlicedString* slice = SlicedString::cast(*subject_tmp); 1108 subject_tmp = Handle<String>(slice->parent()); 1109 slice_offset = slice->offset(); 1110 } 1111 1112 // String might have changed. 1113 if (subject_tmp->IsAsciiRepresentation() != is_ascii) { 1114 // If we changed between an ASCII and an UC16 string, the specialized 1115 // code cannot be used, and we need to restart regexp matching from 1116 // scratch (including, potentially, compiling a new version of the code). 1117 return RETRY; 1118 } 1119 1120 // Otherwise, the content of the string might have moved. It must still 1121 // be a sequential or external string with the same content. 1122 // Update the start and end pointers in the stack frame to the current 1123 // location (whether it has actually moved or not). 1124 ASSERT(StringShape(*subject_tmp).IsSequential() || 1125 StringShape(*subject_tmp).IsExternal()); 1126 1127 // The original start address of the characters to match. 1128 const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart); 1129 1130 // Find the current start address of the same character at the current string 1131 // position. 1132 int start_index = frame_entry<int>(re_frame, kStartIndex); 1133 const byte* new_address = StringCharacterPosition(*subject_tmp, 1134 start_index + slice_offset); 1135 1136 if (start_address != new_address) { 1137 // If there is a difference, update the object pointer and start and end 1138 // addresses in the RegExp stack frame to match the new value. 1139 const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd); 1140 int byte_length = static_cast<int>(end_address - start_address); 1141 frame_entry<const String*>(re_frame, kInputString) = *subject; 1142 frame_entry<const byte*>(re_frame, kInputStart) = new_address; 1143 frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length; 1144 } else if (frame_entry<const String*>(re_frame, kInputString) != *subject) { 1145 // Subject string might have been a ConsString that underwent 1146 // short-circuiting during GC. That will not change start_address but 1147 // will change pointer inside the subject handle. 1148 frame_entry<const String*>(re_frame, kInputString) = *subject; 1149 } 1150 1151 return 0; 1152 } 1153 1154 1155 Operand RegExpMacroAssemblerIA32::register_location(int register_index) { 1156 ASSERT(register_index < (1<<30)); 1157 if (num_registers_ <= register_index) { 1158 num_registers_ = register_index + 1; 1159 } 1160 return Operand(ebp, kRegisterZero - register_index * kPointerSize); 1161 } 1162 1163 1164 void RegExpMacroAssemblerIA32::CheckPosition(int cp_offset, 1165 Label* on_outside_input) { 1166 __ cmp(edi, -cp_offset * char_size()); 1167 BranchOrBacktrack(greater_equal, on_outside_input); 1168 } 1169 1170 1171 void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition, 1172 Label* to) { 1173 if (condition < 0) { // No condition 1174 if (to == NULL) { 1175 Backtrack(); 1176 return; 1177 } 1178 __ jmp(to); 1179 return; 1180 } 1181 if (to == NULL) { 1182 __ j(condition, &backtrack_label_); 1183 return; 1184 } 1185 __ j(condition, to); 1186 } 1187 1188 1189 void RegExpMacroAssemblerIA32::SafeCall(Label* to) { 1190 Label return_to; 1191 __ push(Immediate::CodeRelativeOffset(&return_to)); 1192 __ jmp(to); 1193 __ bind(&return_to); 1194 } 1195 1196 1197 void RegExpMacroAssemblerIA32::SafeReturn() { 1198 __ pop(ebx); 1199 __ add(ebx, Immediate(masm_->CodeObject())); 1200 __ jmp(ebx); 1201 } 1202 1203 1204 void RegExpMacroAssemblerIA32::SafeCallTarget(Label* name) { 1205 __ bind(name); 1206 } 1207 1208 1209 void RegExpMacroAssemblerIA32::Push(Register source) { 1210 ASSERT(!source.is(backtrack_stackpointer())); 1211 // Notice: This updates flags, unlike normal Push. 1212 __ sub(backtrack_stackpointer(), Immediate(kPointerSize)); 1213 __ mov(Operand(backtrack_stackpointer(), 0), source); 1214 } 1215 1216 1217 void RegExpMacroAssemblerIA32::Push(Immediate value) { 1218 // Notice: This updates flags, unlike normal Push. 1219 __ sub(backtrack_stackpointer(), Immediate(kPointerSize)); 1220 __ mov(Operand(backtrack_stackpointer(), 0), value); 1221 } 1222 1223 1224 void RegExpMacroAssemblerIA32::Pop(Register target) { 1225 ASSERT(!target.is(backtrack_stackpointer())); 1226 __ mov(target, Operand(backtrack_stackpointer(), 0)); 1227 // Notice: This updates flags, unlike normal Pop. 1228 __ add(backtrack_stackpointer(), Immediate(kPointerSize)); 1229 } 1230 1231 1232 void RegExpMacroAssemblerIA32::CheckPreemption() { 1233 // Check for preemption. 1234 Label no_preempt; 1235 ExternalReference stack_limit = 1236 ExternalReference::address_of_stack_limit(masm_->isolate()); 1237 __ cmp(esp, Operand::StaticVariable(stack_limit)); 1238 __ j(above, &no_preempt); 1239 1240 SafeCall(&check_preempt_label_); 1241 1242 __ bind(&no_preempt); 1243 } 1244 1245 1246 void RegExpMacroAssemblerIA32::CheckStackLimit() { 1247 Label no_stack_overflow; 1248 ExternalReference stack_limit = 1249 ExternalReference::address_of_regexp_stack_limit(masm_->isolate()); 1250 __ cmp(backtrack_stackpointer(), Operand::StaticVariable(stack_limit)); 1251 __ j(above, &no_stack_overflow); 1252 1253 SafeCall(&stack_overflow_label_); 1254 1255 __ bind(&no_stack_overflow); 1256 } 1257 1258 1259 void RegExpMacroAssemblerIA32::LoadCurrentCharacterUnchecked(int cp_offset, 1260 int characters) { 1261 if (mode_ == ASCII) { 1262 if (characters == 4) { 1263 __ mov(current_character(), Operand(esi, edi, times_1, cp_offset)); 1264 } else if (characters == 2) { 1265 __ movzx_w(current_character(), Operand(esi, edi, times_1, cp_offset)); 1266 } else { 1267 ASSERT(characters == 1); 1268 __ movzx_b(current_character(), Operand(esi, edi, times_1, cp_offset)); 1269 } 1270 } else { 1271 ASSERT(mode_ == UC16); 1272 if (characters == 2) { 1273 __ mov(current_character(), 1274 Operand(esi, edi, times_1, cp_offset * sizeof(uc16))); 1275 } else { 1276 ASSERT(characters == 1); 1277 __ movzx_w(current_character(), 1278 Operand(esi, edi, times_1, cp_offset * sizeof(uc16))); 1279 } 1280 } 1281 } 1282 1283 1284 #undef __ 1285 1286 #endif // V8_INTERPRETED_REGEXP 1287 1288 }} // namespace v8::internal 1289 1290 #endif // V8_TARGET_ARCH_IA32 1291