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