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(Isolate::Current(), 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 static const int num_arguments = 3; 1067 __ PrepareCallCFunction(num_arguments, scratch); 1068 __ mov(a2, frame_pointer()); 1069 // Code* of self. 1070 __ li(a1, Operand(masm_->CodeObject()), CONSTANT_SIZE); 1071 // a0 becomes return address pointer. 1072 ExternalReference stack_guard_check = 1073 ExternalReference::re_check_stack_guard_state(masm_->isolate()); 1074 CallCFunctionUsingStub(stack_guard_check, num_arguments); 1075 } 1076 1077 1078 // Helper function for reading a value out of a stack frame. 1079 template <typename T> 1080 static T& frame_entry(Address re_frame, int frame_offset) { 1081 return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset)); 1082 } 1083 1084 1085 int RegExpMacroAssemblerMIPS::CheckStackGuardState(Address* return_address, 1086 Code* re_code, 1087 Address re_frame) { 1088 Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate); 1089 ASSERT(isolate == Isolate::Current()); 1090 if (isolate->stack_guard()->IsStackOverflow()) { 1091 isolate->StackOverflow(); 1092 return EXCEPTION; 1093 } 1094 1095 // If not real stack overflow the stack guard was used to interrupt 1096 // execution for another purpose. 1097 1098 // If this is a direct call from JavaScript retry the RegExp forcing the call 1099 // through the runtime system. Currently the direct call cannot handle a GC. 1100 if (frame_entry<int>(re_frame, kDirectCall) == 1) { 1101 return RETRY; 1102 } 1103 1104 // Prepare for possible GC. 1105 HandleScope handles(isolate); 1106 Handle<Code> code_handle(re_code); 1107 1108 Handle<String> subject(frame_entry<String*>(re_frame, kInputString)); 1109 // Current string. 1110 bool is_ascii = subject->IsOneByteRepresentationUnderneath(); 1111 1112 ASSERT(re_code->instruction_start() <= *return_address); 1113 ASSERT(*return_address <= 1114 re_code->instruction_start() + re_code->instruction_size()); 1115 1116 MaybeObject* result = Execution::HandleStackGuardInterrupt(isolate); 1117 1118 if (*code_handle != re_code) { // Return address no longer valid. 1119 int delta = code_handle->address() - re_code->address(); 1120 // Overwrite the return address on the stack. 1121 *return_address += delta; 1122 } 1123 1124 if (result->IsException()) { 1125 return EXCEPTION; 1126 } 1127 1128 Handle<String> subject_tmp = subject; 1129 int slice_offset = 0; 1130 1131 // Extract the underlying string and the slice offset. 1132 if (StringShape(*subject_tmp).IsCons()) { 1133 subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first()); 1134 } else if (StringShape(*subject_tmp).IsSliced()) { 1135 SlicedString* slice = SlicedString::cast(*subject_tmp); 1136 subject_tmp = Handle<String>(slice->parent()); 1137 slice_offset = slice->offset(); 1138 } 1139 1140 // String might have changed. 1141 if (subject_tmp->IsOneByteRepresentation() != is_ascii) { 1142 // If we changed between an ASCII and an UC16 string, the specialized 1143 // code cannot be used, and we need to restart regexp matching from 1144 // scratch (including, potentially, compiling a new version of the code). 1145 return RETRY; 1146 } 1147 1148 // Otherwise, the content of the string might have moved. It must still 1149 // be a sequential or external string with the same content. 1150 // Update the start and end pointers in the stack frame to the current 1151 // location (whether it has actually moved or not). 1152 ASSERT(StringShape(*subject_tmp).IsSequential() || 1153 StringShape(*subject_tmp).IsExternal()); 1154 1155 // The original start address of the characters to match. 1156 const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart); 1157 1158 // Find the current start address of the same character at the current string 1159 // position. 1160 int start_index = frame_entry<int>(re_frame, kStartIndex); 1161 const byte* new_address = StringCharacterPosition(*subject_tmp, 1162 start_index + slice_offset); 1163 1164 if (start_address != new_address) { 1165 // If there is a difference, update the object pointer and start and end 1166 // addresses in the RegExp stack frame to match the new value. 1167 const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd); 1168 int byte_length = static_cast<int>(end_address - start_address); 1169 frame_entry<const String*>(re_frame, kInputString) = *subject; 1170 frame_entry<const byte*>(re_frame, kInputStart) = new_address; 1171 frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length; 1172 } else if (frame_entry<const String*>(re_frame, kInputString) != *subject) { 1173 // Subject string might have been a ConsString that underwent 1174 // short-circuiting during GC. That will not change start_address but 1175 // will change pointer inside the subject handle. 1176 frame_entry<const String*>(re_frame, kInputString) = *subject; 1177 } 1178 1179 return 0; 1180 } 1181 1182 1183 MemOperand RegExpMacroAssemblerMIPS::register_location(int register_index) { 1184 ASSERT(register_index < (1<<30)); 1185 if (num_registers_ <= register_index) { 1186 num_registers_ = register_index + 1; 1187 } 1188 return MemOperand(frame_pointer(), 1189 kRegisterZero - register_index * kPointerSize); 1190 } 1191 1192 1193 void RegExpMacroAssemblerMIPS::CheckPosition(int cp_offset, 1194 Label* on_outside_input) { 1195 BranchOrBacktrack(on_outside_input, 1196 ge, 1197 current_input_offset(), 1198 Operand(-cp_offset * char_size())); 1199 } 1200 1201 1202 void RegExpMacroAssemblerMIPS::BranchOrBacktrack(Label* to, 1203 Condition condition, 1204 Register rs, 1205 const Operand& rt) { 1206 if (condition == al) { // Unconditional. 1207 if (to == NULL) { 1208 Backtrack(); 1209 return; 1210 } 1211 __ jmp(to); 1212 return; 1213 } 1214 if (to == NULL) { 1215 __ Branch(&backtrack_label_, condition, rs, rt); 1216 return; 1217 } 1218 __ Branch(to, condition, rs, rt); 1219 } 1220 1221 1222 void RegExpMacroAssemblerMIPS::SafeCall(Label* to, 1223 Condition cond, 1224 Register rs, 1225 const Operand& rt) { 1226 __ BranchAndLink(to, cond, rs, rt); 1227 } 1228 1229 1230 void RegExpMacroAssemblerMIPS::SafeReturn() { 1231 __ pop(ra); 1232 __ Addu(t5, ra, Operand(masm_->CodeObject())); 1233 __ Jump(t5); 1234 } 1235 1236 1237 void RegExpMacroAssemblerMIPS::SafeCallTarget(Label* name) { 1238 __ bind(name); 1239 __ Subu(ra, ra, Operand(masm_->CodeObject())); 1240 __ push(ra); 1241 } 1242 1243 1244 void RegExpMacroAssemblerMIPS::Push(Register source) { 1245 ASSERT(!source.is(backtrack_stackpointer())); 1246 __ Addu(backtrack_stackpointer(), 1247 backtrack_stackpointer(), 1248 Operand(-kPointerSize)); 1249 __ sw(source, MemOperand(backtrack_stackpointer())); 1250 } 1251 1252 1253 void RegExpMacroAssemblerMIPS::Pop(Register target) { 1254 ASSERT(!target.is(backtrack_stackpointer())); 1255 __ lw(target, MemOperand(backtrack_stackpointer())); 1256 __ Addu(backtrack_stackpointer(), backtrack_stackpointer(), kPointerSize); 1257 } 1258 1259 1260 void RegExpMacroAssemblerMIPS::CheckPreemption() { 1261 // Check for preemption. 1262 ExternalReference stack_limit = 1263 ExternalReference::address_of_stack_limit(masm_->isolate()); 1264 __ li(a0, Operand(stack_limit)); 1265 __ lw(a0, MemOperand(a0)); 1266 SafeCall(&check_preempt_label_, ls, sp, Operand(a0)); 1267 } 1268 1269 1270 void RegExpMacroAssemblerMIPS::CheckStackLimit() { 1271 ExternalReference stack_limit = 1272 ExternalReference::address_of_regexp_stack_limit(masm_->isolate()); 1273 1274 __ li(a0, Operand(stack_limit)); 1275 __ lw(a0, MemOperand(a0)); 1276 SafeCall(&stack_overflow_label_, ls, backtrack_stackpointer(), Operand(a0)); 1277 } 1278 1279 1280 void RegExpMacroAssemblerMIPS::CallCFunctionUsingStub( 1281 ExternalReference function, 1282 int num_arguments) { 1283 // Must pass all arguments in registers. The stub pushes on the stack. 1284 ASSERT(num_arguments <= 4); 1285 __ li(code_pointer(), Operand(function)); 1286 RegExpCEntryStub stub; 1287 __ CallStub(&stub); 1288 if (OS::ActivationFrameAlignment() != 0) { 1289 __ lw(sp, MemOperand(sp, 16)); 1290 } 1291 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE); 1292 } 1293 1294 1295 void RegExpMacroAssemblerMIPS::LoadCurrentCharacterUnchecked(int cp_offset, 1296 int characters) { 1297 Register offset = current_input_offset(); 1298 if (cp_offset != 0) { 1299 // t7 is not being used to store the capture start index at this point. 1300 __ Addu(t7, current_input_offset(), Operand(cp_offset * char_size())); 1301 offset = t7; 1302 } 1303 // We assume that we cannot do unaligned loads on MIPS, so this function 1304 // must only be used to load a single character at a time. 1305 ASSERT(characters == 1); 1306 __ Addu(t5, end_of_input_address(), Operand(offset)); 1307 if (mode_ == ASCII) { 1308 __ lbu(current_character(), MemOperand(t5, 0)); 1309 } else { 1310 ASSERT(mode_ == UC16); 1311 __ lhu(current_character(), MemOperand(t5, 0)); 1312 } 1313 } 1314 1315 1316 void RegExpCEntryStub::Generate(MacroAssembler* masm_) { 1317 int stack_alignment = OS::ActivationFrameAlignment(); 1318 if (stack_alignment < kPointerSize) stack_alignment = kPointerSize; 1319 // Stack is already aligned for call, so decrement by alignment 1320 // to make room for storing the return address. 1321 __ Subu(sp, sp, Operand(stack_alignment + kCArgsSlotsSize)); 1322 const int return_address_offset = kCArgsSlotsSize; 1323 __ Addu(a0, sp, return_address_offset); 1324 __ sw(ra, MemOperand(a0, 0)); 1325 __ mov(t9, t1); 1326 __ Call(t9); 1327 __ lw(ra, MemOperand(sp, return_address_offset)); 1328 __ Addu(sp, sp, Operand(stack_alignment + kCArgsSlotsSize)); 1329 __ Jump(ra); 1330 } 1331 1332 1333 #undef __ 1334 1335 #endif // V8_INTERPRETED_REGEXP 1336 1337 }} // namespace v8::internal 1338 1339 #endif // V8_TARGET_ARCH_MIPS 1340