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