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