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