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