1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_REGEXP_X64_REGEXP_MACRO_ASSEMBLER_X64_H_ 6 #define V8_REGEXP_X64_REGEXP_MACRO_ASSEMBLER_X64_H_ 7 8 #include "src/macro-assembler.h" 9 #include "src/regexp/regexp-macro-assembler.h" 10 #include "src/x64/assembler-x64.h" 11 #include "src/zone/zone-chunk-list.h" 12 13 namespace v8 { 14 namespace internal { 15 16 #ifndef V8_INTERPRETED_REGEXP 17 18 class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler { 19 public: 20 RegExpMacroAssemblerX64(Isolate* isolate, Zone* zone, Mode mode, 21 int registers_to_save); 22 virtual ~RegExpMacroAssemblerX64(); 23 virtual int stack_limit_slack(); 24 virtual void AdvanceCurrentPosition(int by); 25 virtual void AdvanceRegister(int reg, int by); 26 virtual void Backtrack(); 27 virtual void Bind(Label* label); 28 virtual void CheckAtStart(Label* on_at_start); 29 virtual void CheckCharacter(uint32_t c, Label* on_equal); 30 virtual void CheckCharacterAfterAnd(uint32_t c, 31 uint32_t mask, 32 Label* on_equal); 33 virtual void CheckCharacterGT(uc16 limit, Label* on_greater); 34 virtual void CheckCharacterLT(uc16 limit, Label* on_less); 35 // A "greedy loop" is a loop that is both greedy and with a simple 36 // body. It has a particularly simple implementation. 37 virtual void CheckGreedyLoop(Label* on_tos_equals_current_position); 38 virtual void CheckNotAtStart(int cp_offset, Label* on_not_at_start); 39 virtual void CheckNotBackReference(int start_reg, bool read_backward, 40 Label* on_no_match); 41 virtual void CheckNotBackReferenceIgnoreCase(int start_reg, 42 bool read_backward, bool unicode, 43 Label* on_no_match); 44 virtual void CheckNotCharacter(uint32_t c, Label* on_not_equal); 45 virtual void CheckNotCharacterAfterAnd(uint32_t c, 46 uint32_t mask, 47 Label* on_not_equal); 48 virtual void CheckNotCharacterAfterMinusAnd(uc16 c, 49 uc16 minus, 50 uc16 mask, 51 Label* on_not_equal); 52 virtual void CheckCharacterInRange(uc16 from, 53 uc16 to, 54 Label* on_in_range); 55 virtual void CheckCharacterNotInRange(uc16 from, 56 uc16 to, 57 Label* on_not_in_range); 58 virtual void CheckBitInTable(Handle<ByteArray> table, Label* on_bit_set); 59 60 // Checks whether the given offset from the current position is before 61 // the end of the string. 62 virtual void CheckPosition(int cp_offset, Label* on_outside_input); 63 virtual bool CheckSpecialCharacterClass(uc16 type, 64 Label* on_no_match); 65 virtual void Fail(); 66 virtual Handle<HeapObject> GetCode(Handle<String> source); 67 virtual void GoTo(Label* label); 68 virtual void IfRegisterGE(int reg, int comparand, Label* if_ge); 69 virtual void IfRegisterLT(int reg, int comparand, Label* if_lt); 70 virtual void IfRegisterEqPos(int reg, Label* if_eq); 71 virtual IrregexpImplementation Implementation(); 72 virtual void LoadCurrentCharacter(int cp_offset, 73 Label* on_end_of_input, 74 bool check_bounds = true, 75 int characters = 1); 76 virtual void PopCurrentPosition(); 77 virtual void PopRegister(int register_index); 78 virtual void PushBacktrack(Label* label); 79 virtual void PushCurrentPosition(); 80 virtual void PushRegister(int register_index, 81 StackCheckFlag check_stack_limit); 82 virtual void ReadCurrentPositionFromRegister(int reg); 83 virtual void ReadStackPointerFromRegister(int reg); 84 virtual void SetCurrentPositionFromEnd(int by); 85 virtual void SetRegister(int register_index, int to); 86 virtual bool Succeed(); 87 virtual void WriteCurrentPositionToRegister(int reg, int cp_offset); 88 virtual void ClearRegisters(int reg_from, int reg_to); 89 virtual void WriteStackPointerToRegister(int reg); 90 91 static Result Match(Handle<Code> regexp, 92 Handle<String> subject, 93 int* offsets_vector, 94 int offsets_vector_length, 95 int previous_index, 96 Isolate* isolate); 97 98 static Result Execute(Code* code, 99 String* input, 100 int start_offset, 101 const byte* input_start, 102 const byte* input_end, 103 int* output, 104 bool at_start); 105 106 // Called from RegExp if the stack-guard is triggered. 107 // If the code object is relocated, the return address is fixed before 108 // returning. 109 static int CheckStackGuardState(Address* return_address, 110 Code* re_code, 111 Address re_frame); 112 113 private: 114 // Offsets from rbp of function parameters and stored registers. 115 static const int kFramePointer = 0; 116 // Above the frame pointer - function parameters and return address. 117 static const int kReturn_eip = kFramePointer + kRegisterSize; 118 static const int kFrameAlign = kReturn_eip + kRegisterSize; 119 120 #ifdef _WIN64 121 // Parameters (first four passed as registers, but with room on stack). 122 // In Microsoft 64-bit Calling Convention, there is room on the callers 123 // stack (before the return address) to spill parameter registers. We 124 // use this space to store the register passed parameters. 125 static const int kInputString = kFrameAlign; 126 // StartIndex is passed as 32 bit int. 127 static const int kStartIndex = kInputString + kRegisterSize; 128 static const int kInputStart = kStartIndex + kRegisterSize; 129 static const int kInputEnd = kInputStart + kRegisterSize; 130 static const int kRegisterOutput = kInputEnd + kRegisterSize; 131 // For the case of global regular expression, we have room to store at least 132 // one set of capture results. For the case of non-global regexp, we ignore 133 // this value. NumOutputRegisters is passed as 32-bit value. The upper 134 // 32 bit of this 64-bit stack slot may contain garbage. 135 static const int kNumOutputRegisters = kRegisterOutput + kRegisterSize; 136 static const int kStackHighEnd = kNumOutputRegisters + kRegisterSize; 137 // DirectCall is passed as 32 bit int (values 0 or 1). 138 static const int kDirectCall = kStackHighEnd + kRegisterSize; 139 static const int kIsolate = kDirectCall + kRegisterSize; 140 #else 141 // In AMD64 ABI Calling Convention, the first six integer parameters 142 // are passed as registers, and caller must allocate space on the stack 143 // if it wants them stored. We push the parameters after the frame pointer. 144 static const int kInputString = kFramePointer - kRegisterSize; 145 static const int kStartIndex = kInputString - kRegisterSize; 146 static const int kInputStart = kStartIndex - kRegisterSize; 147 static const int kInputEnd = kInputStart - kRegisterSize; 148 static const int kRegisterOutput = kInputEnd - kRegisterSize; 149 150 // For the case of global regular expression, we have room to store at least 151 // one set of capture results. For the case of non-global regexp, we ignore 152 // this value. 153 static const int kNumOutputRegisters = kRegisterOutput - kRegisterSize; 154 static const int kStackHighEnd = kFrameAlign; 155 static const int kDirectCall = kStackHighEnd + kRegisterSize; 156 static const int kIsolate = kDirectCall + kRegisterSize; 157 #endif 158 159 #ifdef _WIN64 160 // Microsoft calling convention has three callee-saved registers 161 // (that we are using). We push these after the frame pointer. 162 static const int kBackup_rsi = kFramePointer - kRegisterSize; 163 static const int kBackup_rdi = kBackup_rsi - kRegisterSize; 164 static const int kBackup_rbx = kBackup_rdi - kRegisterSize; 165 static const int kLastCalleeSaveRegister = kBackup_rbx; 166 #else 167 // AMD64 Calling Convention has only one callee-save register that 168 // we use. We push this after the frame pointer (and after the 169 // parameters). 170 static const int kBackup_rbx = kNumOutputRegisters - kRegisterSize; 171 static const int kLastCalleeSaveRegister = kBackup_rbx; 172 #endif 173 174 static const int kSuccessfulCaptures = kLastCalleeSaveRegister - kPointerSize; 175 // When adding local variables remember to push space for them in 176 // the frame in GetCode. 177 static const int kStringStartMinusOne = kSuccessfulCaptures - kPointerSize; 178 179 // First register address. Following registers are below it on the stack. 180 static const int kRegisterZero = kStringStartMinusOne - kPointerSize; 181 182 // Initial size of code buffer. 183 static const size_t kRegExpCodeSize = 1024; 184 185 // Load a number of characters at the given offset from the 186 // current position, into the current-character register. 187 void LoadCurrentCharacterUnchecked(int cp_offset, int character_count); 188 189 // Check whether preemption has been requested. 190 void CheckPreemption(); 191 192 // Check whether we are exceeding the stack limit on the backtrack stack. 193 void CheckStackLimit(); 194 195 // Generate a call to CheckStackGuardState. 196 void CallCheckStackGuardState(); 197 198 // The rbp-relative location of a regexp register. 199 Operand register_location(int register_index); 200 201 // The register containing the current character after LoadCurrentCharacter. current_character()202 inline Register current_character() { return rdx; } 203 204 // The register containing the backtrack stack top. Provides a meaningful 205 // name to the register. backtrack_stackpointer()206 inline Register backtrack_stackpointer() { return rcx; } 207 208 // The registers containing a self pointer to this code's Code object. code_object_pointer()209 inline Register code_object_pointer() { return r8; } 210 211 // Byte size of chars in the string to match (decided by the Mode argument) char_size()212 inline int char_size() { return static_cast<int>(mode_); } 213 214 // Equivalent to a conditional branch to the label, unless the label 215 // is nullptr, in which case it is a conditional Backtrack. 216 void BranchOrBacktrack(Condition condition, Label* to); 217 MarkPositionForCodeRelativeFixup()218 void MarkPositionForCodeRelativeFixup() { 219 code_relative_fixup_positions_.push_back(masm_.pc_offset()); 220 } 221 222 void FixupCodeRelativePositions(); 223 224 // Call and return internally in the generated code in a way that 225 // is GC-safe (i.e., doesn't leave absolute code addresses on the stack) 226 inline void SafeCall(Label* to); 227 inline void SafeCallTarget(Label* label); 228 inline void SafeReturn(); 229 230 // Pushes the value of a register on the backtrack stack. Decrements the 231 // stack pointer (rcx) by a word size and stores the register's value there. 232 inline void Push(Register source); 233 234 // Pushes a value on the backtrack stack. Decrements the stack pointer (rcx) 235 // by a word size and stores the value there. 236 inline void Push(Immediate value); 237 238 // Pushes the Code object relative offset of a label on the backtrack stack 239 // (i.e., a backtrack target). Decrements the stack pointer (rcx) 240 // by a word size and stores the value there. 241 inline void Push(Label* label); 242 243 // Pops a value from the backtrack stack. Reads the word at the stack pointer 244 // (rcx) and increments it by a word size. 245 inline void Pop(Register target); 246 247 // Drops the top value from the backtrack stack without reading it. 248 // Increments the stack pointer (rcx) by a word size. 249 inline void Drop(); 250 251 inline void ReadPositionFromRegister(Register dst, int reg); 252 isolate()253 Isolate* isolate() const { return masm_.isolate(); } 254 255 MacroAssembler masm_; 256 NoRootArrayScope no_root_array_scope_; 257 258 ZoneChunkList<int> code_relative_fixup_positions_; 259 260 // Which mode to generate code for (LATIN1 or UC16). 261 Mode mode_; 262 263 // One greater than maximal register index actually used. 264 int num_registers_; 265 266 // Number of registers to output at the end (the saved registers 267 // are always 0..num_saved_registers_-1) 268 int num_saved_registers_; 269 270 // Labels used internally. 271 Label entry_label_; 272 Label start_label_; 273 Label success_label_; 274 Label backtrack_label_; 275 Label exit_label_; 276 Label check_preempt_label_; 277 Label stack_overflow_label_; 278 }; 279 280 #endif // V8_INTERPRETED_REGEXP 281 282 } // namespace internal 283 } // namespace v8 284 285 #endif // V8_REGEXP_X64_REGEXP_MACRO_ASSEMBLER_X64_H_ 286