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