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