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