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