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