1 // Copyright 2012 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 V8_TARGET_ARCH_MIPS 31 32 #include "unicode.h" 33 #include "log.h" 34 #include "code-stubs.h" 35 #include "regexp-stack.h" 36 #include "macro-assembler.h" 37 #include "regexp-macro-assembler.h" 38 #include "mips/regexp-macro-assembler-mips.h" 39 40 namespace v8 { 41 namespace internal { 42 43 #ifndef V8_INTERPRETED_REGEXP 44 /* 45 * This assembler uses the following register assignment convention 46 * - t7 : Temporarily stores the index of capture start after a matching pass 47 * for a global regexp. 48 * - t1 : Pointer to current code object (Code*) including heap object tag. 49 * - t2 : Current position in input, as negative offset from end of string. 50 * Please notice that this is the byte offset, not the character offset! 51 * - t3 : Currently loaded character. Must be loaded using 52 * LoadCurrentCharacter before using any of the dispatch methods. 53 * - t4 : Points to tip of backtrack stack 54 * - t5 : Unused. 55 * - t6 : End of input (points to byte after last character in input). 56 * - fp : Frame pointer. Used to access arguments, local variables and 57 * RegExp registers. 58 * - sp : Points to tip of C stack. 59 * 60 * The remaining registers are free for computations. 61 * Each call to a public method should retain this convention. 62 * 63 * The stack will have the following structure: 64 * 65 * - fp[64] Isolate* isolate (address of the current isolate) 66 * - fp[60] direct_call (if 1, direct call from JavaScript code, 67 * if 0, call through the runtime system). 68 * - fp[56] stack_area_base (High end of the memory area to use as 69 * backtracking stack). 70 * - fp[52] capture array size (may fit multiple sets of matches) 71 * - fp[48] int* capture_array (int[num_saved_registers_], for output). 72 * - fp[44] secondary link/return address used by native call. 73 * --- sp when called --- 74 * - fp[40] return address (lr). 75 * - fp[36] old frame pointer (r11). 76 * - fp[0..32] backup of registers s0..s7. 77 * --- frame pointer ---- 78 * - fp[-4] end of input (address of end of string). 79 * - fp[-8] start of input (address of first character in string). 80 * - fp[-12] start index (character index of start). 81 * - fp[-16] void* input_string (location of a handle containing the string). 82 * - fp[-20] success counter (only for global regexps to count matches). 83 * - fp[-24] Offset of location before start of input (effectively character 84 * position -1). Used to initialize capture registers to a 85 * non-position. 86 * - fp[-28] At start (if 1, we are starting at the start of the 87 * string, otherwise 0) 88 * - fp[-32] register 0 (Only positions must be stored in the first 89 * - register 1 num_saved_registers_ registers) 90 * - ... 91 * - register num_registers-1 92 * --- sp --- 93 * 94 * The first num_saved_registers_ registers are initialized to point to 95 * "character -1" in the string (i.e., char_size() bytes before the first 96 * character of the string). The remaining registers start out as garbage. 97 * 98 * The data up to the return address must be placed there by the calling 99 * code and the remaining arguments are passed in registers, e.g. by calling the 100 * code entry as cast to a function with the signature: 101 * int (*match)(String* input_string, 102 * int start_index, 103 * Address start, 104 * Address end, 105 * Address secondary_return_address, // Only used by native call. 106 * int* capture_output_array, 107 * byte* stack_area_base, 108 * bool direct_call = false) 109 * The call is performed by NativeRegExpMacroAssembler::Execute() 110 * (in regexp-macro-assembler.cc) via the CALL_GENERATED_REGEXP_CODE macro 111 * in mips/simulator-mips.h. 112 * When calling as a non-direct call (i.e., from C++ code), the return address 113 * area is overwritten with the ra register by the RegExp code. When doing a 114 * direct call from generated code, the return address is placed there by 115 * the calling code, as in a normal exit frame. 116 */ 117 118 #define __ ACCESS_MASM(masm_) 119 120 RegExpMacroAssemblerMIPS::RegExpMacroAssemblerMIPS( 121 Mode mode, 122 int registers_to_save, 123 Zone* zone) 124 : NativeRegExpMacroAssembler(zone), 125 masm_(new MacroAssembler(zone->isolate(), NULL, kRegExpCodeSize)), 126 mode_(mode), 127 num_registers_(registers_to_save), 128 num_saved_registers_(registers_to_save), 129 entry_label_(), 130 start_label_(), 131 success_label_(), 132 backtrack_label_(), 133 exit_label_(), 134 internal_failure_label_() { 135 ASSERT_EQ(0, registers_to_save % 2); 136 __ jmp(&entry_label_); // We'll write the entry code later. 137 // If the code gets too big or corrupted, an internal exception will be 138 // raised, and we will exit right away. 139 __ bind(&internal_failure_label_); 140 __ li(v0, Operand(FAILURE)); 141 __ Ret(); 142 __ bind(&start_label_); // And then continue from here. 143 } 144 145 146 RegExpMacroAssemblerMIPS::~RegExpMacroAssemblerMIPS() { 147 delete masm_; 148 // Unuse labels in case we throw away the assembler without calling GetCode. 149 entry_label_.Unuse(); 150 start_label_.Unuse(); 151 success_label_.Unuse(); 152 backtrack_label_.Unuse(); 153 exit_label_.Unuse(); 154 check_preempt_label_.Unuse(); 155 stack_overflow_label_.Unuse(); 156 internal_failure_label_.Unuse(); 157 } 158 159 160 int RegExpMacroAssemblerMIPS::stack_limit_slack() { 161 return RegExpStack::kStackLimitSlack; 162 } 163 164 165 void RegExpMacroAssemblerMIPS::AdvanceCurrentPosition(int by) { 166 if (by != 0) { 167 __ Addu(current_input_offset(), 168 current_input_offset(), Operand(by * char_size())); 169 } 170 } 171 172 173 void RegExpMacroAssemblerMIPS::AdvanceRegister(int reg, int by) { 174 ASSERT(reg >= 0); 175 ASSERT(reg < num_registers_); 176 if (by != 0) { 177 __ lw(a0, register_location(reg)); 178 __ Addu(a0, a0, Operand(by)); 179 __ sw(a0, register_location(reg)); 180 } 181 } 182 183 184 void RegExpMacroAssemblerMIPS::Backtrack() { 185 CheckPreemption(); 186 // Pop Code* offset from backtrack stack, add Code* and jump to location. 187 Pop(a0); 188 __ Addu(a0, a0, code_pointer()); 189 __ Jump(a0); 190 } 191 192 193 void RegExpMacroAssemblerMIPS::Bind(Label* label) { 194 __ bind(label); 195 } 196 197 198 void RegExpMacroAssemblerMIPS::CheckCharacter(uint32_t c, Label* on_equal) { 199 BranchOrBacktrack(on_equal, eq, current_character(), Operand(c)); 200 } 201 202 203 void RegExpMacroAssemblerMIPS::CheckCharacterGT(uc16 limit, Label* on_greater) { 204 BranchOrBacktrack(on_greater, gt, current_character(), Operand(limit)); 205 } 206 207 208 void RegExpMacroAssemblerMIPS::CheckAtStart(Label* on_at_start) { 209 Label not_at_start; 210 // Did we start the match at the start of the string at all? 211 __ lw(a0, MemOperand(frame_pointer(), kStartIndex)); 212 BranchOrBacktrack(¬_at_start, ne, a0, Operand(zero_reg)); 213 214 // If we did, are we still at the start of the input? 215 __ lw(a1, MemOperand(frame_pointer(), kInputStart)); 216 __ Addu(a0, end_of_input_address(), Operand(current_input_offset())); 217 BranchOrBacktrack(on_at_start, eq, a0, Operand(a1)); 218 __ bind(¬_at_start); 219 } 220 221 222 void RegExpMacroAssemblerMIPS::CheckNotAtStart(Label* on_not_at_start) { 223 // Did we start the match at the start of the string at all? 224 __ lw(a0, MemOperand(frame_pointer(), kStartIndex)); 225 BranchOrBacktrack(on_not_at_start, ne, a0, Operand(zero_reg)); 226 // If we did, are we still at the start of the input? 227 __ lw(a1, MemOperand(frame_pointer(), kInputStart)); 228 __ Addu(a0, end_of_input_address(), Operand(current_input_offset())); 229 BranchOrBacktrack(on_not_at_start, ne, a0, Operand(a1)); 230 } 231 232 233 void RegExpMacroAssemblerMIPS::CheckCharacterLT(uc16 limit, Label* on_less) { 234 BranchOrBacktrack(on_less, lt, current_character(), Operand(limit)); 235 } 236 237 238 void RegExpMacroAssemblerMIPS::CheckGreedyLoop(Label* on_equal) { 239 Label backtrack_non_equal; 240 __ lw(a0, MemOperand(backtrack_stackpointer(), 0)); 241 __ Branch(&backtrack_non_equal, ne, current_input_offset(), Operand(a0)); 242 __ Addu(backtrack_stackpointer(), 243 backtrack_stackpointer(), 244 Operand(kPointerSize)); 245 __ bind(&backtrack_non_equal); 246 BranchOrBacktrack(on_equal, eq, current_input_offset(), Operand(a0)); 247 } 248 249 250 void RegExpMacroAssemblerMIPS::CheckNotBackReferenceIgnoreCase( 251 int start_reg, 252 Label* on_no_match) { 253 Label fallthrough; 254 __ lw(a0, register_location(start_reg)); // Index of start of capture. 255 __ lw(a1, register_location(start_reg + 1)); // Index of end of capture. 256 __ Subu(a1, a1, a0); // Length of capture. 257 258 // If length is zero, either the capture is empty or it is not participating. 259 // In either case succeed immediately. 260 __ Branch(&fallthrough, eq, a1, Operand(zero_reg)); 261 262 __ Addu(t5, a1, current_input_offset()); 263 // Check that there are enough characters left in the input. 264 BranchOrBacktrack(on_no_match, gt, t5, Operand(zero_reg)); 265 266 if (mode_ == ASCII) { 267 Label success; 268 Label fail; 269 Label loop_check; 270 271 // a0 - offset of start of capture. 272 // a1 - length of capture. 273 __ Addu(a0, a0, Operand(end_of_input_address())); 274 __ Addu(a2, end_of_input_address(), Operand(current_input_offset())); 275 __ Addu(a1, a0, Operand(a1)); 276 277 // a0 - Address of start of capture. 278 // a1 - Address of end of capture. 279 // a2 - Address of current input position. 280 281 Label loop; 282 __ bind(&loop); 283 __ lbu(a3, MemOperand(a0, 0)); 284 __ addiu(a0, a0, char_size()); 285 __ lbu(t0, MemOperand(a2, 0)); 286 __ addiu(a2, a2, char_size()); 287 288 __ Branch(&loop_check, eq, t0, Operand(a3)); 289 290 // Mismatch, try case-insensitive match (converting letters to lower-case). 291 __ Or(a3, a3, Operand(0x20)); // Convert capture character to lower-case. 292 __ Or(t0, t0, Operand(0x20)); // Also convert input character. 293 __ Branch(&fail, ne, t0, Operand(a3)); 294 __ Subu(a3, a3, Operand('a')); 295 __ Branch(&loop_check, ls, a3, Operand('z' - 'a')); 296 // Latin-1: Check for values in range [224,254] but not 247. 297 __ Subu(a3, a3, Operand(224 - 'a')); 298 // Weren't Latin-1 letters. 299 __ Branch(&fail, hi, a3, Operand(254 - 224)); 300 // Check for 247. 301 __ Branch(&fail, eq, a3, Operand(247 - 224)); 302 303 __ bind(&loop_check); 304 __ Branch(&loop, lt, a0, Operand(a1)); 305 __ jmp(&success); 306 307 __ bind(&fail); 308 GoTo(on_no_match); 309 310 __ bind(&success); 311 // Compute new value of character position after the matched part. 312 __ Subu(current_input_offset(), a2, end_of_input_address()); 313 } else { 314 ASSERT(mode_ == UC16); 315 // Put regexp engine registers on stack. 316 RegList regexp_registers_to_retain = current_input_offset().bit() | 317 current_character().bit() | backtrack_stackpointer().bit(); 318 __ MultiPush(regexp_registers_to_retain); 319 320 int argument_count = 4; 321 __ PrepareCallCFunction(argument_count, a2); 322 323 // a0 - offset of start of capture. 324 // a1 - length of capture. 325 326 // Put arguments into arguments registers. 327 // Parameters are 328 // a0: Address byte_offset1 - Address captured substring's start. 329 // a1: Address byte_offset2 - Address of current character position. 330 // a2: size_t byte_length - length of capture in bytes(!). 331 // a3: Isolate* isolate. 332 333 // Address of start of capture. 334 __ Addu(a0, a0, Operand(end_of_input_address())); 335 // Length of capture. 336 __ mov(a2, a1); 337 // Save length in callee-save register for use on return. 338 __ mov(s3, a1); 339 // Address of current input position. 340 __ Addu(a1, current_input_offset(), Operand(end_of_input_address())); 341 // Isolate. 342 __ li(a3, Operand(ExternalReference::isolate_address(masm_->isolate()))); 343 344 { 345 AllowExternalCallThatCantCauseGC scope(masm_); 346 ExternalReference function = 347 ExternalReference::re_case_insensitive_compare_uc16(masm_->isolate()); 348 __ CallCFunction(function, argument_count); 349 } 350 351 // Restore regexp engine registers. 352 __ MultiPop(regexp_registers_to_retain); 353 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE); 354 __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd)); 355 356 // Check if function returned non-zero for success or zero for failure. 357 BranchOrBacktrack(on_no_match, eq, v0, Operand(zero_reg)); 358 // On success, increment position by length of capture. 359 __ Addu(current_input_offset(), current_input_offset(), Operand(s3)); 360 } 361 362 __ bind(&fallthrough); 363 } 364 365 366 void RegExpMacroAssemblerMIPS::CheckNotBackReference( 367 int start_reg, 368 Label* on_no_match) { 369 Label fallthrough; 370 Label success; 371 372 // Find length of back-referenced capture. 373 __ lw(a0, register_location(start_reg)); 374 __ lw(a1, register_location(start_reg + 1)); 375 __ Subu(a1, a1, a0); // Length to check. 376 // Succeed on empty capture (including no capture). 377 __ Branch(&fallthrough, eq, a1, Operand(zero_reg)); 378 379 __ Addu(t5, a1, current_input_offset()); 380 // Check that there are enough characters left in the input. 381 BranchOrBacktrack(on_no_match, gt, t5, Operand(zero_reg)); 382 383 // Compute pointers to match string and capture string. 384 __ Addu(a0, a0, Operand(end_of_input_address())); 385 __ Addu(a2, end_of_input_address(), Operand(current_input_offset())); 386 __ Addu(a1, a1, Operand(a0)); 387 388 Label loop; 389 __ bind(&loop); 390 if (mode_ == ASCII) { 391 __ lbu(a3, MemOperand(a0, 0)); 392 __ addiu(a0, a0, char_size()); 393 __ lbu(t0, MemOperand(a2, 0)); 394 __ addiu(a2, a2, char_size()); 395 } else { 396 ASSERT(mode_ == UC16); 397 __ lhu(a3, MemOperand(a0, 0)); 398 __ addiu(a0, a0, char_size()); 399 __ lhu(t0, MemOperand(a2, 0)); 400 __ addiu(a2, a2, char_size()); 401 } 402 BranchOrBacktrack(on_no_match, ne, a3, Operand(t0)); 403 __ Branch(&loop, lt, a0, Operand(a1)); 404 405 // Move current character position to position after match. 406 __ Subu(current_input_offset(), a2, end_of_input_address()); 407 __ bind(&fallthrough); 408 } 409 410 411 void RegExpMacroAssemblerMIPS::CheckNotCharacter(uint32_t c, 412 Label* on_not_equal) { 413 BranchOrBacktrack(on_not_equal, ne, current_character(), Operand(c)); 414 } 415 416 417 void RegExpMacroAssemblerMIPS::CheckCharacterAfterAnd(uint32_t c, 418 uint32_t mask, 419 Label* on_equal) { 420 __ And(a0, current_character(), Operand(mask)); 421 Operand rhs = (c == 0) ? Operand(zero_reg) : Operand(c); 422 BranchOrBacktrack(on_equal, eq, a0, rhs); 423 } 424 425 426 void RegExpMacroAssemblerMIPS::CheckNotCharacterAfterAnd(uint32_t c, 427 uint32_t mask, 428 Label* on_not_equal) { 429 __ And(a0, current_character(), Operand(mask)); 430 Operand rhs = (c == 0) ? Operand(zero_reg) : Operand(c); 431 BranchOrBacktrack(on_not_equal, ne, a0, rhs); 432 } 433 434 435 void RegExpMacroAssemblerMIPS::CheckNotCharacterAfterMinusAnd( 436 uc16 c, 437 uc16 minus, 438 uc16 mask, 439 Label* on_not_equal) { 440 ASSERT(minus < String::kMaxUtf16CodeUnit); 441 __ Subu(a0, current_character(), Operand(minus)); 442 __ And(a0, a0, Operand(mask)); 443 BranchOrBacktrack(on_not_equal, ne, a0, Operand(c)); 444 } 445 446 447 void RegExpMacroAssemblerMIPS::CheckCharacterInRange( 448 uc16 from, 449 uc16 to, 450 Label* on_in_range) { 451 __ Subu(a0, current_character(), Operand(from)); 452 // Unsigned lower-or-same condition. 453 BranchOrBacktrack(on_in_range, ls, a0, Operand(to - from)); 454 } 455 456 457 void RegExpMacroAssemblerMIPS::CheckCharacterNotInRange( 458 uc16 from, 459 uc16 to, 460 Label* on_not_in_range) { 461 __ Subu(a0, current_character(), Operand(from)); 462 // Unsigned higher condition. 463 BranchOrBacktrack(on_not_in_range, hi, a0, Operand(to - from)); 464 } 465 466 467 void RegExpMacroAssemblerMIPS::CheckBitInTable( 468 Handle<ByteArray> table, 469 Label* on_bit_set) { 470 __ li(a0, Operand(table)); 471 if (mode_ != ASCII || kTableMask != String::kMaxOneByteCharCode) { 472 __ And(a1, current_character(), Operand(kTableSize - 1)); 473 __ Addu(a0, a0, a1); 474 } else { 475 __ Addu(a0, a0, current_character()); 476 } 477 478 __ lbu(a0, FieldMemOperand(a0, ByteArray::kHeaderSize)); 479 BranchOrBacktrack(on_bit_set, ne, a0, Operand(zero_reg)); 480 } 481 482 483 bool RegExpMacroAssemblerMIPS::CheckSpecialCharacterClass(uc16 type, 484 Label* on_no_match) { 485 // Range checks (c in min..max) are generally implemented by an unsigned 486 // (c - min) <= (max - min) check. 487 switch (type) { 488 case 's': 489 // Match space-characters. 490 if (mode_ == ASCII) { 491 // One byte space characters are '\t'..'\r', ' ' and \u00a0. 492 Label success; 493 __ Branch(&success, eq, current_character(), Operand(' ')); 494 // Check range 0x09..0x0d. 495 __ Subu(a0, current_character(), Operand('\t')); 496 __ Branch(&success, ls, a0, Operand('\r' - '\t')); 497 // \u00a0 (NBSP). 498 BranchOrBacktrack(on_no_match, ne, a0, Operand(0x00a0 - '\t')); 499 __ bind(&success); 500 return true; 501 } 502 return false; 503 case 'S': 504 // The emitted code for generic character classes is good enough. 505 return false; 506 case 'd': 507 // Match ASCII digits ('0'..'9'). 508 __ Subu(a0, current_character(), Operand('0')); 509 BranchOrBacktrack(on_no_match, hi, a0, Operand('9' - '0')); 510 return true; 511 case 'D': 512 // Match non ASCII-digits. 513 __ Subu(a0, current_character(), Operand('0')); 514 BranchOrBacktrack(on_no_match, ls, a0, Operand('9' - '0')); 515 return true; 516 case '.': { 517 // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029). 518 __ Xor(a0, current_character(), Operand(0x01)); 519 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c. 520 __ Subu(a0, a0, Operand(0x0b)); 521 BranchOrBacktrack(on_no_match, ls, a0, Operand(0x0c - 0x0b)); 522 if (mode_ == UC16) { 523 // Compare original value to 0x2028 and 0x2029, using the already 524 // computed (current_char ^ 0x01 - 0x0b). I.e., check for 525 // 0x201d (0x2028 - 0x0b) or 0x201e. 526 __ Subu(a0, a0, Operand(0x2028 - 0x0b)); 527 BranchOrBacktrack(on_no_match, ls, a0, Operand(1)); 528 } 529 return true; 530 } 531 case 'n': { 532 // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029). 533 __ Xor(a0, current_character(), Operand(0x01)); 534 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c. 535 __ Subu(a0, a0, Operand(0x0b)); 536 if (mode_ == ASCII) { 537 BranchOrBacktrack(on_no_match, hi, a0, Operand(0x0c - 0x0b)); 538 } else { 539 Label done; 540 BranchOrBacktrack(&done, ls, a0, Operand(0x0c - 0x0b)); 541 // Compare original value to 0x2028 and 0x2029, using the already 542 // computed (current_char ^ 0x01 - 0x0b). I.e., check for 543 // 0x201d (0x2028 - 0x0b) or 0x201e. 544 __ Subu(a0, a0, Operand(0x2028 - 0x0b)); 545 BranchOrBacktrack(on_no_match, hi, a0, Operand(1)); 546 __ bind(&done); 547 } 548 return true; 549 } 550 case 'w': { 551 if (mode_ != ASCII) { 552 // Table is 128 entries, so all ASCII characters can be tested. 553 BranchOrBacktrack(on_no_match, hi, current_character(), Operand('z')); 554 } 555 ExternalReference map = ExternalReference::re_word_character_map(); 556 __ li(a0, Operand(map)); 557 __ Addu(a0, a0, current_character()); 558 __ lbu(a0, MemOperand(a0, 0)); 559 BranchOrBacktrack(on_no_match, eq, a0, Operand(zero_reg)); 560 return true; 561 } 562 case 'W': { 563 Label done; 564 if (mode_ != ASCII) { 565 // Table is 128 entries, so all ASCII characters can be tested. 566 __ Branch(&done, hi, current_character(), Operand('z')); 567 } 568 ExternalReference map = ExternalReference::re_word_character_map(); 569 __ li(a0, Operand(map)); 570 __ Addu(a0, a0, current_character()); 571 __ lbu(a0, MemOperand(a0, 0)); 572 BranchOrBacktrack(on_no_match, ne, a0, Operand(zero_reg)); 573 if (mode_ != ASCII) { 574 __ bind(&done); 575 } 576 return true; 577 } 578 case '*': 579 // Match any character. 580 return true; 581 // No custom implementation (yet): s(UC16), S(UC16). 582 default: 583 return false; 584 } 585 } 586 587 588 void RegExpMacroAssemblerMIPS::Fail() { 589 __ li(v0, Operand(FAILURE)); 590 __ jmp(&exit_label_); 591 } 592 593 594 Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) { 595 Label return_v0; 596 if (masm_->has_exception()) { 597 // If the code gets corrupted due to long regular expressions and lack of 598 // space on trampolines, an internal exception flag is set. If this case 599 // is detected, we will jump into exit sequence right away. 600 __ bind_to(&entry_label_, internal_failure_label_.pos()); 601 } else { 602 // Finalize code - write the entry point code now we know how many 603 // registers we need. 604 605 // Entry code: 606 __ bind(&entry_label_); 607 608 // Tell the system that we have a stack frame. Because the type is MANUAL, 609 // no is generated. 610 FrameScope scope(masm_, StackFrame::MANUAL); 611 612 // Actually emit code to start a new stack frame. 613 // Push arguments 614 // Save callee-save registers. 615 // Start new stack frame. 616 // Store link register in existing stack-cell. 617 // Order here should correspond to order of offset constants in header file. 618 RegList registers_to_retain = s0.bit() | s1.bit() | s2.bit() | 619 s3.bit() | s4.bit() | s5.bit() | s6.bit() | s7.bit() | fp.bit(); 620 RegList argument_registers = a0.bit() | a1.bit() | a2.bit() | a3.bit(); 621 __ MultiPush(argument_registers | registers_to_retain | ra.bit()); 622 // Set frame pointer in space for it if this is not a direct call 623 // from generated code. 624 __ Addu(frame_pointer(), sp, Operand(4 * kPointerSize)); 625 __ mov(a0, zero_reg); 626 __ push(a0); // Make room for success counter and initialize it to 0. 627 __ push(a0); // Make room for "position - 1" constant (value irrelevant). 628 629 // Check if we have space on the stack for registers. 630 Label stack_limit_hit; 631 Label stack_ok; 632 633 ExternalReference stack_limit = 634 ExternalReference::address_of_stack_limit(masm_->isolate()); 635 __ li(a0, Operand(stack_limit)); 636 __ lw(a0, MemOperand(a0)); 637 __ Subu(a0, sp, a0); 638 // Handle it if the stack pointer is already below the stack limit. 639 __ Branch(&stack_limit_hit, le, a0, Operand(zero_reg)); 640 // Check if there is room for the variable number of registers above 641 // the stack limit. 642 __ Branch(&stack_ok, hs, a0, Operand(num_registers_ * kPointerSize)); 643 // Exit with OutOfMemory exception. There is not enough space on the stack 644 // for our working registers. 645 __ li(v0, Operand(EXCEPTION)); 646 __ jmp(&return_v0); 647 648 __ bind(&stack_limit_hit); 649 CallCheckStackGuardState(a0); 650 // If returned value is non-zero, we exit with the returned value as result. 651 __ Branch(&return_v0, ne, v0, Operand(zero_reg)); 652 653 __ bind(&stack_ok); 654 // Allocate space on stack for registers. 655 __ Subu(sp, sp, Operand(num_registers_ * kPointerSize)); 656 // Load string end. 657 __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd)); 658 // Load input start. 659 __ lw(a0, MemOperand(frame_pointer(), kInputStart)); 660 // Find negative length (offset of start relative to end). 661 __ Subu(current_input_offset(), a0, end_of_input_address()); 662 // Set a0 to address of char before start of the input string 663 // (effectively string position -1). 664 __ lw(a1, MemOperand(frame_pointer(), kStartIndex)); 665 __ Subu(a0, current_input_offset(), Operand(char_size())); 666 __ sll(t5, a1, (mode_ == UC16) ? 1 : 0); 667 __ Subu(a0, a0, t5); 668 // Store this value in a local variable, for use when clearing 669 // position registers. 670 __ sw(a0, MemOperand(frame_pointer(), kInputStartMinusOne)); 671 672 // Initialize code pointer register 673 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE); 674 675 Label load_char_start_regexp, start_regexp; 676 // Load newline if index is at start, previous character otherwise. 677 __ Branch(&load_char_start_regexp, ne, a1, Operand(zero_reg)); 678 __ li(current_character(), Operand('\n')); 679 __ jmp(&start_regexp); 680 681 // Global regexp restarts matching here. 682 __ bind(&load_char_start_regexp); 683 // Load previous char as initial value of current character register. 684 LoadCurrentCharacterUnchecked(-1, 1); 685 __ bind(&start_regexp); 686 687 // Initialize on-stack registers. 688 if (num_saved_registers_ > 0) { // Always is, if generated from a regexp. 689 // Fill saved registers with initial value = start offset - 1. 690 if (num_saved_registers_ > 8) { 691 // Address of register 0. 692 __ Addu(a1, frame_pointer(), Operand(kRegisterZero)); 693 __ li(a2, Operand(num_saved_registers_)); 694 Label init_loop; 695 __ bind(&init_loop); 696 __ sw(a0, MemOperand(a1)); 697 __ Addu(a1, a1, Operand(-kPointerSize)); 698 __ Subu(a2, a2, Operand(1)); 699 __ Branch(&init_loop, ne, a2, Operand(zero_reg)); 700 } else { 701 for (int i = 0; i < num_saved_registers_; i++) { 702 __ sw(a0, register_location(i)); 703 } 704 } 705 } 706 707 // Initialize backtrack stack pointer. 708 __ lw(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackHighEnd)); 709 710 __ jmp(&start_label_); 711 712 713 // Exit code: 714 if (success_label_.is_linked()) { 715 // Save captures when successful. 716 __ bind(&success_label_); 717 if (num_saved_registers_ > 0) { 718 // Copy captures to output. 719 __ lw(a1, MemOperand(frame_pointer(), kInputStart)); 720 __ lw(a0, MemOperand(frame_pointer(), kRegisterOutput)); 721 __ lw(a2, MemOperand(frame_pointer(), kStartIndex)); 722 __ Subu(a1, end_of_input_address(), a1); 723 // a1 is length of input in bytes. 724 if (mode_ == UC16) { 725 __ srl(a1, a1, 1); 726 } 727 // a1 is length of input in characters. 728 __ Addu(a1, a1, Operand(a2)); 729 // a1 is length of string in characters. 730 731 ASSERT_EQ(0, num_saved_registers_ % 2); 732 // Always an even number of capture registers. This allows us to 733 // unroll the loop once to add an operation between a load of a register 734 // and the following use of that register. 735 for (int i = 0; i < num_saved_registers_; i += 2) { 736 __ lw(a2, register_location(i)); 737 __ lw(a3, register_location(i + 1)); 738 if (i == 0 && global_with_zero_length_check()) { 739 // Keep capture start in a4 for the zero-length check later. 740 __ mov(t7, a2); 741 } 742 if (mode_ == UC16) { 743 __ sra(a2, a2, 1); 744 __ Addu(a2, a2, a1); 745 __ sra(a3, a3, 1); 746 __ Addu(a3, a3, a1); 747 } else { 748 __ Addu(a2, a1, Operand(a2)); 749 __ Addu(a3, a1, Operand(a3)); 750 } 751 __ sw(a2, MemOperand(a0)); 752 __ Addu(a0, a0, kPointerSize); 753 __ sw(a3, MemOperand(a0)); 754 __ Addu(a0, a0, kPointerSize); 755 } 756 } 757 758 if (global()) { 759 // Restart matching if the regular expression is flagged as global. 760 __ lw(a0, MemOperand(frame_pointer(), kSuccessfulCaptures)); 761 __ lw(a1, MemOperand(frame_pointer(), kNumOutputRegisters)); 762 __ lw(a2, MemOperand(frame_pointer(), kRegisterOutput)); 763 // Increment success counter. 764 __ Addu(a0, a0, 1); 765 __ sw(a0, MemOperand(frame_pointer(), kSuccessfulCaptures)); 766 // Capture results have been stored, so the number of remaining global 767 // output registers is reduced by the number of stored captures. 768 __ Subu(a1, a1, num_saved_registers_); 769 // Check whether we have enough room for another set of capture results. 770 __ mov(v0, a0); 771 __ Branch(&return_v0, lt, a1, Operand(num_saved_registers_)); 772 773 __ sw(a1, MemOperand(frame_pointer(), kNumOutputRegisters)); 774 // Advance the location for output. 775 __ Addu(a2, a2, num_saved_registers_ * kPointerSize); 776 __ sw(a2, MemOperand(frame_pointer(), kRegisterOutput)); 777 778 // Prepare a0 to initialize registers with its value in the next run. 779 __ lw(a0, MemOperand(frame_pointer(), kInputStartMinusOne)); 780 781 if (global_with_zero_length_check()) { 782 // Special case for zero-length matches. 783 // t7: capture start index 784 // Not a zero-length match, restart. 785 __ Branch( 786 &load_char_start_regexp, ne, current_input_offset(), Operand(t7)); 787 // Offset from the end is zero if we already reached the end. 788 __ Branch(&exit_label_, eq, current_input_offset(), 789 Operand(zero_reg)); 790 // Advance current position after a zero-length match. 791 __ Addu(current_input_offset(), 792 current_input_offset(), 793 Operand((mode_ == UC16) ? 2 : 1)); 794 } 795 796 __ Branch(&load_char_start_regexp); 797 } else { 798 __ li(v0, Operand(SUCCESS)); 799 } 800 } 801 // Exit and return v0. 802 __ bind(&exit_label_); 803 if (global()) { 804 __ lw(v0, MemOperand(frame_pointer(), kSuccessfulCaptures)); 805 } 806 807 __ bind(&return_v0); 808 // Skip sp past regexp registers and local variables.. 809 __ mov(sp, frame_pointer()); 810 // Restore registers s0..s7 and return (restoring ra to pc). 811 __ MultiPop(registers_to_retain | ra.bit()); 812 __ Ret(); 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 // Put regexp engine registers on stack. 826 RegList regexp_registers_to_retain = current_input_offset().bit() | 827 current_character().bit() | backtrack_stackpointer().bit(); 828 __ MultiPush(regexp_registers_to_retain); 829 CallCheckStackGuardState(a0); 830 __ MultiPop(regexp_registers_to_retain); 831 // If returning non-zero, we should end execution with the given 832 // result as return value. 833 __ Branch(&return_v0, ne, v0, Operand(zero_reg)); 834 835 // String might have moved: Reload end of string from frame. 836 __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd)); 837 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE); 838 SafeReturn(); 839 } 840 841 // Backtrack stack overflow code. 842 if (stack_overflow_label_.is_linked()) { 843 SafeCallTarget(&stack_overflow_label_); 844 // Reached if the backtrack-stack limit has been hit. 845 // Put regexp engine registers on stack first. 846 RegList regexp_registers = current_input_offset().bit() | 847 current_character().bit(); 848 __ MultiPush(regexp_registers); 849 Label grow_failed; 850 // Call GrowStack(backtrack_stackpointer(), &stack_base) 851 static const int num_arguments = 3; 852 __ PrepareCallCFunction(num_arguments, a0); 853 __ mov(a0, backtrack_stackpointer()); 854 __ Addu(a1, frame_pointer(), Operand(kStackHighEnd)); 855 __ li(a2, Operand(ExternalReference::isolate_address(masm_->isolate()))); 856 ExternalReference grow_stack = 857 ExternalReference::re_grow_stack(masm_->isolate()); 858 __ CallCFunction(grow_stack, num_arguments); 859 // Restore regexp registers. 860 __ MultiPop(regexp_registers); 861 // If return NULL, we have failed to grow the stack, and 862 // must exit with a stack-overflow exception. 863 __ Branch(&exit_with_exception, eq, v0, Operand(zero_reg)); 864 // Otherwise use return value as new stack pointer. 865 __ mov(backtrack_stackpointer(), v0); 866 // Restore saved registers and continue. 867 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE); 868 __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd)); 869 SafeReturn(); 870 } 871 872 if (exit_with_exception.is_linked()) { 873 // If any of the code above needed to exit with an exception. 874 __ bind(&exit_with_exception); 875 // Exit with Result EXCEPTION(-1) to signal thrown exception. 876 __ li(v0, Operand(EXCEPTION)); 877 __ jmp(&return_v0); 878 } 879 } 880 881 CodeDesc code_desc; 882 masm_->GetCode(&code_desc); 883 Handle<Code> code = isolate()->factory()->NewCode( 884 code_desc, Code::ComputeFlags(Code::REGEXP), masm_->CodeObject()); 885 LOG(masm_->isolate(), RegExpCodeCreateEvent(*code, *source)); 886 return Handle<HeapObject>::cast(code); 887 } 888 889 890 void RegExpMacroAssemblerMIPS::GoTo(Label* to) { 891 if (to == NULL) { 892 Backtrack(); 893 return; 894 } 895 __ jmp(to); 896 return; 897 } 898 899 900 void RegExpMacroAssemblerMIPS::IfRegisterGE(int reg, 901 int comparand, 902 Label* if_ge) { 903 __ lw(a0, register_location(reg)); 904 BranchOrBacktrack(if_ge, ge, a0, Operand(comparand)); 905 } 906 907 908 void RegExpMacroAssemblerMIPS::IfRegisterLT(int reg, 909 int comparand, 910 Label* if_lt) { 911 __ lw(a0, register_location(reg)); 912 BranchOrBacktrack(if_lt, lt, a0, Operand(comparand)); 913 } 914 915 916 void RegExpMacroAssemblerMIPS::IfRegisterEqPos(int reg, 917 Label* if_eq) { 918 __ lw(a0, register_location(reg)); 919 BranchOrBacktrack(if_eq, eq, a0, Operand(current_input_offset())); 920 } 921 922 923 RegExpMacroAssembler::IrregexpImplementation 924 RegExpMacroAssemblerMIPS::Implementation() { 925 return kMIPSImplementation; 926 } 927 928 929 void RegExpMacroAssemblerMIPS::LoadCurrentCharacter(int cp_offset, 930 Label* on_end_of_input, 931 bool check_bounds, 932 int characters) { 933 ASSERT(cp_offset >= -1); // ^ and \b can look behind one character. 934 ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works). 935 if (check_bounds) { 936 CheckPosition(cp_offset + characters - 1, on_end_of_input); 937 } 938 LoadCurrentCharacterUnchecked(cp_offset, characters); 939 } 940 941 942 void RegExpMacroAssemblerMIPS::PopCurrentPosition() { 943 Pop(current_input_offset()); 944 } 945 946 947 void RegExpMacroAssemblerMIPS::PopRegister(int register_index) { 948 Pop(a0); 949 __ sw(a0, register_location(register_index)); 950 } 951 952 953 void RegExpMacroAssemblerMIPS::PushBacktrack(Label* label) { 954 if (label->is_bound()) { 955 int target = label->pos(); 956 __ li(a0, Operand(target + Code::kHeaderSize - kHeapObjectTag)); 957 } else { 958 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); 959 Label after_constant; 960 __ Branch(&after_constant); 961 int offset = masm_->pc_offset(); 962 int cp_offset = offset + Code::kHeaderSize - kHeapObjectTag; 963 __ emit(0); 964 masm_->label_at_put(label, offset); 965 __ bind(&after_constant); 966 if (is_int16(cp_offset)) { 967 __ lw(a0, MemOperand(code_pointer(), cp_offset)); 968 } else { 969 __ Addu(a0, code_pointer(), cp_offset); 970 __ lw(a0, MemOperand(a0, 0)); 971 } 972 } 973 Push(a0); 974 CheckStackLimit(); 975 } 976 977 978 void RegExpMacroAssemblerMIPS::PushCurrentPosition() { 979 Push(current_input_offset()); 980 } 981 982 983 void RegExpMacroAssemblerMIPS::PushRegister(int register_index, 984 StackCheckFlag check_stack_limit) { 985 __ lw(a0, register_location(register_index)); 986 Push(a0); 987 if (check_stack_limit) CheckStackLimit(); 988 } 989 990 991 void RegExpMacroAssemblerMIPS::ReadCurrentPositionFromRegister(int reg) { 992 __ lw(current_input_offset(), register_location(reg)); 993 } 994 995 996 void RegExpMacroAssemblerMIPS::ReadStackPointerFromRegister(int reg) { 997 __ lw(backtrack_stackpointer(), register_location(reg)); 998 __ lw(a0, MemOperand(frame_pointer(), kStackHighEnd)); 999 __ Addu(backtrack_stackpointer(), backtrack_stackpointer(), Operand(a0)); 1000 } 1001 1002 1003 void RegExpMacroAssemblerMIPS::SetCurrentPositionFromEnd(int by) { 1004 Label after_position; 1005 __ Branch(&after_position, 1006 ge, 1007 current_input_offset(), 1008 Operand(-by * char_size())); 1009 __ li(current_input_offset(), -by * char_size()); 1010 // On RegExp code entry (where this operation is used), the character before 1011 // the current position is expected to be already loaded. 1012 // We have advanced the position, so it's safe to read backwards. 1013 LoadCurrentCharacterUnchecked(-1, 1); 1014 __ bind(&after_position); 1015 } 1016 1017 1018 void RegExpMacroAssemblerMIPS::SetRegister(int register_index, int to) { 1019 ASSERT(register_index >= num_saved_registers_); // Reserved for positions! 1020 __ li(a0, Operand(to)); 1021 __ sw(a0, register_location(register_index)); 1022 } 1023 1024 1025 bool RegExpMacroAssemblerMIPS::Succeed() { 1026 __ jmp(&success_label_); 1027 return global(); 1028 } 1029 1030 1031 void RegExpMacroAssemblerMIPS::WriteCurrentPositionToRegister(int reg, 1032 int cp_offset) { 1033 if (cp_offset == 0) { 1034 __ sw(current_input_offset(), register_location(reg)); 1035 } else { 1036 __ Addu(a0, current_input_offset(), Operand(cp_offset * char_size())); 1037 __ sw(a0, register_location(reg)); 1038 } 1039 } 1040 1041 1042 void RegExpMacroAssemblerMIPS::ClearRegisters(int reg_from, int reg_to) { 1043 ASSERT(reg_from <= reg_to); 1044 __ lw(a0, MemOperand(frame_pointer(), kInputStartMinusOne)); 1045 for (int reg = reg_from; reg <= reg_to; reg++) { 1046 __ sw(a0, register_location(reg)); 1047 } 1048 } 1049 1050 1051 void RegExpMacroAssemblerMIPS::WriteStackPointerToRegister(int reg) { 1052 __ lw(a1, MemOperand(frame_pointer(), kStackHighEnd)); 1053 __ Subu(a0, backtrack_stackpointer(), a1); 1054 __ sw(a0, register_location(reg)); 1055 } 1056 1057 1058 bool RegExpMacroAssemblerMIPS::CanReadUnaligned() { 1059 return false; 1060 } 1061 1062 1063 // Private methods: 1064 1065 void RegExpMacroAssemblerMIPS::CallCheckStackGuardState(Register scratch) { 1066 int stack_alignment = OS::ActivationFrameAlignment(); 1067 1068 // Align the stack pointer and save the original sp value on the stack. 1069 __ mov(scratch, sp); 1070 __ Subu(sp, sp, Operand(kPointerSize)); 1071 ASSERT(IsPowerOf2(stack_alignment)); 1072 __ And(sp, sp, Operand(-stack_alignment)); 1073 __ sw(scratch, MemOperand(sp)); 1074 1075 __ mov(a2, frame_pointer()); 1076 // Code* of self. 1077 __ li(a1, Operand(masm_->CodeObject()), CONSTANT_SIZE); 1078 1079 // We need to make room for the return address on the stack. 1080 ASSERT(IsAligned(stack_alignment, kPointerSize)); 1081 __ Subu(sp, sp, Operand(stack_alignment)); 1082 1083 // Stack pointer now points to cell where return address is to be written. 1084 // Arguments are in registers, meaning we teat the return address as 1085 // argument 5. Since DirectCEntryStub will handleallocating space for the C 1086 // argument slots, we don't need to care about that here. This is how the 1087 // stack will look (sp meaning the value of sp at this moment): 1088 // [sp + 3] - empty slot if needed for alignment. 1089 // [sp + 2] - saved sp. 1090 // [sp + 1] - second word reserved for return value. 1091 // [sp + 0] - first word reserved for return value. 1092 1093 // a0 will point to the return address, placed by DirectCEntry. 1094 __ mov(a0, sp); 1095 1096 ExternalReference stack_guard_check = 1097 ExternalReference::re_check_stack_guard_state(masm_->isolate()); 1098 __ li(t9, Operand(stack_guard_check)); 1099 DirectCEntryStub stub; 1100 stub.GenerateCall(masm_, t9); 1101 1102 // DirectCEntryStub allocated space for the C argument slots so we have to 1103 // drop them with the return address from the stack with loading saved sp. 1104 // At this point stack must look: 1105 // [sp + 7] - empty slot if needed for alignment. 1106 // [sp + 6] - saved sp. 1107 // [sp + 5] - second word reserved for return value. 1108 // [sp + 4] - first word reserved for return value. 1109 // [sp + 3] - C argument slot. 1110 // [sp + 2] - C argument slot. 1111 // [sp + 1] - C argument slot. 1112 // [sp + 0] - C argument slot. 1113 __ lw(sp, MemOperand(sp, stack_alignment + kCArgsSlotsSize)); 1114 1115 __ li(code_pointer(), Operand(masm_->CodeObject())); 1116 } 1117 1118 1119 // Helper function for reading a value out of a stack frame. 1120 template <typename T> 1121 static T& frame_entry(Address re_frame, int frame_offset) { 1122 return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset)); 1123 } 1124 1125 1126 int RegExpMacroAssemblerMIPS::CheckStackGuardState(Address* return_address, 1127 Code* re_code, 1128 Address re_frame) { 1129 Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate); 1130 if (isolate->stack_guard()->IsStackOverflow()) { 1131 isolate->StackOverflow(); 1132 return EXCEPTION; 1133 } 1134 1135 // If not real stack overflow the stack guard was used to interrupt 1136 // execution for another purpose. 1137 1138 // If this is a direct call from JavaScript retry the RegExp forcing the call 1139 // through the runtime system. Currently the direct call cannot handle a GC. 1140 if (frame_entry<int>(re_frame, kDirectCall) == 1) { 1141 return RETRY; 1142 } 1143 1144 // Prepare for possible GC. 1145 HandleScope handles(isolate); 1146 Handle<Code> code_handle(re_code); 1147 1148 Handle<String> subject(frame_entry<String*>(re_frame, kInputString)); 1149 // Current string. 1150 bool is_ascii = subject->IsOneByteRepresentationUnderneath(); 1151 1152 ASSERT(re_code->instruction_start() <= *return_address); 1153 ASSERT(*return_address <= 1154 re_code->instruction_start() + re_code->instruction_size()); 1155 1156 MaybeObject* result = Execution::HandleStackGuardInterrupt(isolate); 1157 1158 if (*code_handle != re_code) { // Return address no longer valid. 1159 int delta = code_handle->address() - re_code->address(); 1160 // Overwrite the return address on the stack. 1161 *return_address += delta; 1162 } 1163 1164 if (result->IsException()) { 1165 return EXCEPTION; 1166 } 1167 1168 Handle<String> subject_tmp = subject; 1169 int slice_offset = 0; 1170 1171 // Extract the underlying string and the slice offset. 1172 if (StringShape(*subject_tmp).IsCons()) { 1173 subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first()); 1174 } else if (StringShape(*subject_tmp).IsSliced()) { 1175 SlicedString* slice = SlicedString::cast(*subject_tmp); 1176 subject_tmp = Handle<String>(slice->parent()); 1177 slice_offset = slice->offset(); 1178 } 1179 1180 // String might have changed. 1181 if (subject_tmp->IsOneByteRepresentation() != is_ascii) { 1182 // If we changed between an ASCII and an UC16 string, the specialized 1183 // code cannot be used, and we need to restart regexp matching from 1184 // scratch (including, potentially, compiling a new version of the code). 1185 return RETRY; 1186 } 1187 1188 // Otherwise, the content of the string might have moved. It must still 1189 // be a sequential or external string with the same content. 1190 // Update the start and end pointers in the stack frame to the current 1191 // location (whether it has actually moved or not). 1192 ASSERT(StringShape(*subject_tmp).IsSequential() || 1193 StringShape(*subject_tmp).IsExternal()); 1194 1195 // The original start address of the characters to match. 1196 const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart); 1197 1198 // Find the current start address of the same character at the current string 1199 // position. 1200 int start_index = frame_entry<int>(re_frame, kStartIndex); 1201 const byte* new_address = StringCharacterPosition(*subject_tmp, 1202 start_index + slice_offset); 1203 1204 if (start_address != new_address) { 1205 // If there is a difference, update the object pointer and start and end 1206 // addresses in the RegExp stack frame to match the new value. 1207 const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd); 1208 int byte_length = static_cast<int>(end_address - start_address); 1209 frame_entry<const String*>(re_frame, kInputString) = *subject; 1210 frame_entry<const byte*>(re_frame, kInputStart) = new_address; 1211 frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length; 1212 } else if (frame_entry<const String*>(re_frame, kInputString) != *subject) { 1213 // Subject string might have been a ConsString that underwent 1214 // short-circuiting during GC. That will not change start_address but 1215 // will change pointer inside the subject handle. 1216 frame_entry<const String*>(re_frame, kInputString) = *subject; 1217 } 1218 1219 return 0; 1220 } 1221 1222 1223 MemOperand RegExpMacroAssemblerMIPS::register_location(int register_index) { 1224 ASSERT(register_index < (1<<30)); 1225 if (num_registers_ <= register_index) { 1226 num_registers_ = register_index + 1; 1227 } 1228 return MemOperand(frame_pointer(), 1229 kRegisterZero - register_index * kPointerSize); 1230 } 1231 1232 1233 void RegExpMacroAssemblerMIPS::CheckPosition(int cp_offset, 1234 Label* on_outside_input) { 1235 BranchOrBacktrack(on_outside_input, 1236 ge, 1237 current_input_offset(), 1238 Operand(-cp_offset * char_size())); 1239 } 1240 1241 1242 void RegExpMacroAssemblerMIPS::BranchOrBacktrack(Label* to, 1243 Condition condition, 1244 Register rs, 1245 const Operand& rt) { 1246 if (condition == al) { // Unconditional. 1247 if (to == NULL) { 1248 Backtrack(); 1249 return; 1250 } 1251 __ jmp(to); 1252 return; 1253 } 1254 if (to == NULL) { 1255 __ Branch(&backtrack_label_, condition, rs, rt); 1256 return; 1257 } 1258 __ Branch(to, condition, rs, rt); 1259 } 1260 1261 1262 void RegExpMacroAssemblerMIPS::SafeCall(Label* to, 1263 Condition cond, 1264 Register rs, 1265 const Operand& rt) { 1266 __ BranchAndLink(to, cond, rs, rt); 1267 } 1268 1269 1270 void RegExpMacroAssemblerMIPS::SafeReturn() { 1271 __ pop(ra); 1272 __ Addu(t5, ra, Operand(masm_->CodeObject())); 1273 __ Jump(t5); 1274 } 1275 1276 1277 void RegExpMacroAssemblerMIPS::SafeCallTarget(Label* name) { 1278 __ bind(name); 1279 __ Subu(ra, ra, Operand(masm_->CodeObject())); 1280 __ push(ra); 1281 } 1282 1283 1284 void RegExpMacroAssemblerMIPS::Push(Register source) { 1285 ASSERT(!source.is(backtrack_stackpointer())); 1286 __ Addu(backtrack_stackpointer(), 1287 backtrack_stackpointer(), 1288 Operand(-kPointerSize)); 1289 __ sw(source, MemOperand(backtrack_stackpointer())); 1290 } 1291 1292 1293 void RegExpMacroAssemblerMIPS::Pop(Register target) { 1294 ASSERT(!target.is(backtrack_stackpointer())); 1295 __ lw(target, MemOperand(backtrack_stackpointer())); 1296 __ Addu(backtrack_stackpointer(), backtrack_stackpointer(), kPointerSize); 1297 } 1298 1299 1300 void RegExpMacroAssemblerMIPS::CheckPreemption() { 1301 // Check for preemption. 1302 ExternalReference stack_limit = 1303 ExternalReference::address_of_stack_limit(masm_->isolate()); 1304 __ li(a0, Operand(stack_limit)); 1305 __ lw(a0, MemOperand(a0)); 1306 SafeCall(&check_preempt_label_, ls, sp, Operand(a0)); 1307 } 1308 1309 1310 void RegExpMacroAssemblerMIPS::CheckStackLimit() { 1311 ExternalReference stack_limit = 1312 ExternalReference::address_of_regexp_stack_limit(masm_->isolate()); 1313 1314 __ li(a0, Operand(stack_limit)); 1315 __ lw(a0, MemOperand(a0)); 1316 SafeCall(&stack_overflow_label_, ls, backtrack_stackpointer(), Operand(a0)); 1317 } 1318 1319 1320 void RegExpMacroAssemblerMIPS::LoadCurrentCharacterUnchecked(int cp_offset, 1321 int characters) { 1322 Register offset = current_input_offset(); 1323 if (cp_offset != 0) { 1324 // t7 is not being used to store the capture start index at this point. 1325 __ Addu(t7, current_input_offset(), Operand(cp_offset * char_size())); 1326 offset = t7; 1327 } 1328 // We assume that we cannot do unaligned loads on MIPS, so this function 1329 // must only be used to load a single character at a time. 1330 ASSERT(characters == 1); 1331 __ Addu(t5, end_of_input_address(), Operand(offset)); 1332 if (mode_ == ASCII) { 1333 __ lbu(current_character(), MemOperand(t5, 0)); 1334 } else { 1335 ASSERT(mode_ == UC16); 1336 __ lhu(current_character(), MemOperand(t5, 0)); 1337 } 1338 } 1339 1340 1341 #undef __ 1342 1343 #endif // V8_INTERPRETED_REGEXP 1344 1345 }} // namespace v8::internal 1346 1347 #endif // V8_TARGET_ARCH_MIPS 1348