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