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