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