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