1// Copyright 2013 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#ifndef V8_REGEXP_ARM64_REGEXP_MACRO_ASSEMBLER_ARM64_H_ 6#define V8_REGEXP_ARM64_REGEXP_MACRO_ASSEMBLER_ARM64_H_ 7 8#include "src/base/strings.h" 9#include "src/codegen/arm64/assembler-arm64.h" 10#include "src/codegen/macro-assembler.h" 11#include "src/regexp/regexp-macro-assembler.h" 12 13namespace v8 { 14namespace internal { 15 16class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64 17 : public NativeRegExpMacroAssembler { 18 public: 19 RegExpMacroAssemblerARM64(Isolate* isolate, Zone* zone, Mode mode, 20 int registers_to_save); 21 ~RegExpMacroAssemblerARM64() override; 22 void AbortedCodeGeneration() override; 23 int stack_limit_slack() override; 24 void AdvanceCurrentPosition(int by) override; 25 void AdvanceRegister(int reg, int by) override; 26 void Backtrack() override; 27 void Bind(Label* label) override; 28 void CheckAtStart(int cp_offset, Label* on_at_start) override; 29 void CheckCharacter(unsigned c, Label* on_equal) override; 30 void CheckCharacterAfterAnd(unsigned c, unsigned mask, 31 Label* on_equal) override; 32 void CheckCharacterGT(base::uc16 limit, Label* on_greater) override; 33 void CheckCharacterLT(base::uc16 limit, Label* on_less) override; 34 void CheckCharacters(base::Vector<const base::uc16> str, int cp_offset, 35 Label* on_failure, bool check_end_of_string); 36 // A "greedy loop" is a loop that is both greedy and with a simple 37 // body. It has a particularly simple implementation. 38 void CheckGreedyLoop(Label* on_tos_equals_current_position) override; 39 void CheckNotAtStart(int cp_offset, Label* on_not_at_start) override; 40 void CheckNotBackReference(int start_reg, bool read_backward, 41 Label* on_no_match) override; 42 void CheckNotBackReferenceIgnoreCase(int start_reg, bool read_backward, 43 bool unicode, 44 Label* on_no_match) override; 45 void CheckNotCharacter(unsigned c, Label* on_not_equal) override; 46 void CheckNotCharacterAfterAnd(unsigned c, unsigned mask, 47 Label* on_not_equal) override; 48 void CheckNotCharacterAfterMinusAnd(base::uc16 c, base::uc16 minus, 49 base::uc16 mask, 50 Label* on_not_equal) override; 51 void CheckCharacterInRange(base::uc16 from, base::uc16 to, 52 Label* on_in_range) override; 53 void CheckCharacterNotInRange(base::uc16 from, base::uc16 to, 54 Label* on_not_in_range) override; 55 bool CheckCharacterInRangeArray(const ZoneList<CharacterRange>* ranges, 56 Label* on_in_range) override; 57 bool CheckCharacterNotInRangeArray(const ZoneList<CharacterRange>* ranges, 58 Label* on_not_in_range) override; 59 void CheckBitInTable(Handle<ByteArray> table, Label* on_bit_set) override; 60 61 // Checks whether the given offset from the current position is before 62 // the end of the string. 63 void CheckPosition(int cp_offset, Label* on_outside_input) override; 64 bool CheckSpecialCharacterClass(StandardCharacterSet type, 65 Label* on_no_match) override; 66 void BindJumpTarget(Label* label = nullptr) override; 67 void Fail() override; 68 Handle<HeapObject> GetCode(Handle<String> source) override; 69 void GoTo(Label* label) override; 70 void IfRegisterGE(int reg, int comparand, Label* if_ge) override; 71 void IfRegisterLT(int reg, int comparand, Label* if_lt) override; 72 void IfRegisterEqPos(int reg, Label* if_eq) override; 73 IrregexpImplementation Implementation() override; 74 void LoadCurrentCharacterUnchecked(int cp_offset, 75 int character_count) override; 76 void PopCurrentPosition() override; 77 void PopRegister(int register_index) override; 78 void PushBacktrack(Label* label) override; 79 void PushCurrentPosition() override; 80 void PushRegister(int register_index, 81 StackCheckFlag check_stack_limit) override; 82 void ReadCurrentPositionFromRegister(int reg) override; 83 void ReadStackPointerFromRegister(int reg) override; 84 void SetCurrentPositionFromEnd(int by) override; 85 void SetRegister(int register_index, int to) override; 86 bool Succeed() override; 87 void WriteCurrentPositionToRegister(int reg, int cp_offset) override; 88 void ClearRegisters(int reg_from, int reg_to) override; 89 void WriteStackPointerToRegister(int reg) override; 90 91 // Called from RegExp if the stack-guard is triggered. 92 // If the code object is relocated, the return address is fixed before 93 // returning. 94 // {raw_code} is an Address because this is called via ExternalReference. 95 static int CheckStackGuardState(Address* return_address, Address raw_code, 96 Address re_frame, int start_offset, 97 const byte** input_start, 98 const byte** input_end); 99 100 private: 101 // Above the frame pointer - Stored registers and stack passed parameters. 102 static const int kFramePointer = 0; 103 static const int kReturnAddress = kFramePointer + kSystemPointerSize; 104 // Callee-saved registers (x19-x28). 105 static const int kNumCalleeSavedRegisters = 10; 106 static const int kCalleeSavedRegisters = kReturnAddress + kSystemPointerSize; 107 108 // Below the frame pointer. 109 // Register parameters stored by setup code. 110 static const int kIsolate = -kSystemPointerSize; 111 static const int kDirectCall = kIsolate - kSystemPointerSize; 112 static const int kOutputSize = kDirectCall - kSystemPointerSize; 113 static const int kInput = kOutputSize - kSystemPointerSize; 114 // When adding local variables remember to push space for them in 115 // the frame in GetCode. 116 static const int kSuccessCounter = kInput - kSystemPointerSize; 117 static const int kBacktrackCount = kSuccessCounter - kSystemPointerSize; 118 // Stores the initial value of the regexp stack pointer in a 119 // position-independent representation (in case the regexp stack grows and 120 // thus moves). 121 static const int kRegExpStackBasePointer = 122 kBacktrackCount - kSystemPointerSize; 123 // A padding slot to preserve alignment. 124 static const int kStackLocalPadding = 125 kRegExpStackBasePointer - kSystemPointerSize; 126 static constexpr int kNumberOfStackLocals = 4; 127 128 // First position register address on the stack. Following positions are 129 // below it. A position is a 32 bit value. 130 static const int kFirstRegisterOnStack = kStackLocalPadding - kWRegSize; 131 // A capture is a 64 bit value holding two position. 132 static const int kFirstCaptureOnStack = kStackLocalPadding - kXRegSize; 133 134 // Initial size of code buffer. 135 static const int kRegExpCodeSize = 1024; 136 137 // Registers x0 to x7 are used to store the first captures, they need to be 138 // retained over calls to C++ code. 139 void PushCachedRegisters(); 140 void PopCachedRegisters(); 141 142 // When initializing registers to a non-position value we can unroll 143 // the loop. Set the limit of registers to unroll. 144 static const int kNumRegistersToUnroll = 16; 145 146 // We are using x0 to x7 as a register cache. Each hardware register must 147 // contain one capture, that is two 32 bit registers. We can cache at most 148 // 16 registers. 149 static const int kNumCachedRegisters = 16; 150 151 // Check whether preemption has been requested. 152 void CheckPreemption(); 153 154 // Check whether we are exceeding the stack limit on the backtrack stack. 155 void CheckStackLimit(); 156 157 void CallCheckStackGuardState(Register scratch); 158 void CallIsCharacterInRangeArray(const ZoneList<CharacterRange>* ranges); 159 160 // Location of a 32 bit position register. 161 MemOperand register_location(int register_index); 162 163 // Location of a 64 bit capture, combining two position registers. 164 MemOperand capture_location(int register_index, Register scratch); 165 166 // Register holding the current input position as negative offset from 167 // the end of the string. 168 static constexpr Register current_input_offset() { return w21; } 169 170 // The register containing the current character after LoadCurrentCharacter. 171 static constexpr Register current_character() { return w22; } 172 173 // Register holding address of the end of the input string. 174 static constexpr Register input_end() { return x25; } 175 176 // Register holding address of the start of the input string. 177 static constexpr Register input_start() { return x26; } 178 179 // Register holding the offset from the start of the string where we should 180 // start matching. 181 static constexpr Register start_offset() { return w27; } 182 183 // Pointer to the output array's first element. 184 static constexpr Register output_array() { return x28; } 185 186 // Register holding the frame address. Local variables, parameters and 187 // regexp registers are addressed relative to this. 188 static constexpr Register frame_pointer() { return fp; } 189 190 // The register containing the backtrack stack top. Provides a meaningful 191 // name to the register. 192 static constexpr Register backtrack_stackpointer() { return x23; } 193 194 // Register holding pointer to the current code object. 195 static constexpr Register code_pointer() { return x20; } 196 197 // Register holding the value used for clearing capture registers. 198 static constexpr Register string_start_minus_one() { return w24; } 199 // The top 32 bit of this register is used to store this value 200 // twice. This is used for clearing more than one register at a time. 201 static constexpr Register twice_non_position_value() { return x24; } 202 203 // Byte size of chars in the string to match (decided by the Mode argument) 204 int char_size() const { return static_cast<int>(mode_); } 205 206 // Equivalent to a conditional branch to the label, unless the label 207 // is nullptr, in which case it is a conditional Backtrack. 208 void BranchOrBacktrack(Condition condition, Label* to); 209 210 // Compares reg against immmediate before calling BranchOrBacktrack. 211 // It makes use of the Cbz and Cbnz instructions. 212 void CompareAndBranchOrBacktrack(Register reg, 213 int immediate, 214 Condition condition, 215 Label* to); 216 217 inline void CallIf(Label* to, Condition condition); 218 219 // Save and restore the link register on the stack in a way that 220 // is GC-safe. 221 inline void SaveLinkRegister(); 222 inline void RestoreLinkRegister(); 223 224 // Pushes the value of a register on the backtrack stack. Decrements the 225 // stack pointer by a word size and stores the register's value there. 226 inline void Push(Register source); 227 228 // Pops a value from the backtrack stack. Reads the word at the stack pointer 229 // and increments it by a word size. 230 inline void Pop(Register target); 231 232 // This state indicates where the register actually is. 233 enum RegisterState { 234 STACKED, // Resides in memory. 235 CACHED_LSW, // Least Significant Word of a 64 bit hardware register. 236 CACHED_MSW // Most Significant Word of a 64 bit hardware register. 237 }; 238 239 RegisterState GetRegisterState(int register_index) { 240 DCHECK_LE(0, register_index); 241 if (register_index >= kNumCachedRegisters) { 242 return STACKED; 243 } else { 244 if ((register_index % 2) == 0) { 245 return CACHED_LSW; 246 } else { 247 return CACHED_MSW; 248 } 249 } 250 } 251 252 // Store helper that takes the state of the register into account. 253 inline void StoreRegister(int register_index, Register source); 254 255 // Returns a hardware W register that holds the value of the capture 256 // register. 257 // 258 // This function will try to use an existing cache register (w0-w7) for the 259 // result. Otherwise, it will load the value into maybe_result. 260 // 261 // If the returned register is anything other than maybe_result, calling code 262 // must not write to it. 263 inline Register GetRegister(int register_index, Register maybe_result); 264 265 // Returns the harware register (x0-x7) holding the value of the capture 266 // register. 267 // This assumes that the state of the register is not STACKED. 268 inline Register GetCachedRegister(int register_index); 269 270 void LoadRegExpStackPointerFromMemory(Register dst); 271 void StoreRegExpStackPointerToMemory(Register src, Register scratch); 272 void PushRegExpBasePointer(Register stack_pointer, Register scratch); 273 void PopRegExpBasePointer(Register stack_pointer_out, Register scratch); 274 275 Isolate* isolate() const { return masm_->isolate(); } 276 277 const std::unique_ptr<MacroAssembler> masm_; 278 const NoRootArrayScope no_root_array_scope_; 279 280 // Which mode to generate code for (LATIN1 or UC16). 281 const Mode mode_; 282 283 // One greater than maximal register index actually used. 284 int num_registers_; 285 286 // Number of registers to output at the end (the saved registers 287 // are always 0..num_saved_registers_-1) 288 const int num_saved_registers_; 289 290 // Labels used internally. 291 Label entry_label_; 292 Label start_label_; 293 Label success_label_; 294 Label backtrack_label_; 295 Label exit_label_; 296 Label check_preempt_label_; 297 Label stack_overflow_label_; 298 Label fallback_label_; 299}; 300 301} // namespace internal 302} // namespace v8 303 304#endif // V8_REGEXP_ARM64_REGEXP_MACRO_ASSEMBLER_ARM64_H_ 305