regexp-macro-assembler-x64.h 12.1 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5 6
#ifndef V8_REGEXP_X64_REGEXP_MACRO_ASSEMBLER_X64_H_
#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

12 13 14
namespace v8 {
namespace internal {

15
#ifndef V8_INTERPRETED_REGEXP
lrn@chromium.org's avatar
lrn@chromium.org committed
16

17 18
class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler {
 public:
19 20
  RegExpMacroAssemblerX64(Isolate* isolate, Zone* zone, Mode mode,
                          int registers_to_save);
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
  virtual ~RegExpMacroAssemblerX64();
  virtual int stack_limit_slack();
  virtual void AdvanceCurrentPosition(int by);
  virtual void AdvanceRegister(int reg, int by);
  virtual void Backtrack();
  virtual void Bind(Label* label);
  virtual void CheckAtStart(Label* on_at_start);
  virtual void CheckCharacter(uint32_t c, Label* on_equal);
  virtual void CheckCharacterAfterAnd(uint32_t c,
                                      uint32_t mask,
                                      Label* on_equal);
  virtual void CheckCharacterGT(uc16 limit, Label* on_greater);
  virtual void CheckCharacterLT(uc16 limit, Label* on_less);
  // A "greedy loop" is a loop that is both greedy and with a simple
  // body. It has a particularly simple implementation.
  virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
37 38 39
  virtual void CheckNotAtStart(int cp_offset, Label* on_not_at_start);
  virtual void CheckNotBackReference(int start_reg, bool read_backward,
                                     Label* on_no_match);
40
  virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
41
                                               bool read_backward, bool unicode,
42 43 44 45 46 47 48 49 50
                                               Label* on_no_match);
  virtual void CheckNotCharacter(uint32_t c, Label* on_not_equal);
  virtual void CheckNotCharacterAfterAnd(uint32_t c,
                                         uint32_t mask,
                                         Label* on_not_equal);
  virtual void CheckNotCharacterAfterMinusAnd(uc16 c,
                                              uc16 minus,
                                              uc16 mask,
                                              Label* on_not_equal);
51 52 53 54 55 56 57 58
  virtual void CheckCharacterInRange(uc16 from,
                                     uc16 to,
                                     Label* on_in_range);
  virtual void CheckCharacterNotInRange(uc16 from,
                                        uc16 to,
                                        Label* on_not_in_range);
  virtual void CheckBitInTable(Handle<ByteArray> table, Label* on_bit_set);

59 60 61 62 63 64
  // Checks whether the given offset from the current position is before
  // the end of the string.
  virtual void CheckPosition(int cp_offset, Label* on_outside_input);
  virtual bool CheckSpecialCharacterClass(uc16 type,
                                          Label* on_no_match);
  virtual void Fail();
65
  virtual Handle<HeapObject> GetCode(Handle<String> source);
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
  virtual void GoTo(Label* label);
  virtual void IfRegisterGE(int reg, int comparand, Label* if_ge);
  virtual void IfRegisterLT(int reg, int comparand, Label* if_lt);
  virtual void IfRegisterEqPos(int reg, Label* if_eq);
  virtual IrregexpImplementation Implementation();
  virtual void LoadCurrentCharacter(int cp_offset,
                                    Label* on_end_of_input,
                                    bool check_bounds = true,
                                    int characters = 1);
  virtual void PopCurrentPosition();
  virtual void PopRegister(int register_index);
  virtual void PushBacktrack(Label* label);
  virtual void PushCurrentPosition();
  virtual void PushRegister(int register_index,
                            StackCheckFlag check_stack_limit);
  virtual void ReadCurrentPositionFromRegister(int reg);
  virtual void ReadStackPointerFromRegister(int reg);
83
  virtual void SetCurrentPositionFromEnd(int by);
84
  virtual void SetRegister(int register_index, int to);
85
  virtual bool Succeed();
86 87 88 89 90 91 92 93
  virtual void WriteCurrentPositionToRegister(int reg, int cp_offset);
  virtual void ClearRegisters(int reg_from, int reg_to);
  virtual void WriteStackPointerToRegister(int reg);

  static Result Match(Handle<Code> regexp,
                      Handle<String> subject,
                      int* offsets_vector,
                      int offsets_vector_length,
94 95
                      int previous_index,
                      Isolate* isolate);
96 97 98 99 100 101 102 103 104

  static Result Execute(Code* code,
                        String* input,
                        int start_offset,
                        const byte* input_start,
                        const byte* input_end,
                        int* output,
                        bool at_start);

lrn@chromium.org's avatar
lrn@chromium.org committed
105 106 107 108 109 110 111
  // Called from RegExp if the stack-guard is triggered.
  // If the code object is relocated, the return address is fixed before
  // returning.
  static int CheckStackGuardState(Address* return_address,
                                  Code* re_code,
                                  Address re_frame);

112 113 114 115
 private:
  // Offsets from rbp of function parameters and stored registers.
  static const int kFramePointer = 0;
  // Above the frame pointer - function parameters and return address.
116 117
  static const int kReturn_eip = kFramePointer + kRegisterSize;
  static const int kFrameAlign = kReturn_eip + kRegisterSize;
118

119
#ifdef _WIN64
120 121 122 123 124
  // Parameters (first four passed as registers, but with room on stack).
  // In Microsoft 64-bit Calling Convention, there is room on the callers
  // stack (before the return address) to spill parameter registers. We
  // use this space to store the register passed parameters.
  static const int kInputString = kFrameAlign;
125
  // StartIndex is passed as 32 bit int.
126 127 128 129
  static const int kStartIndex = kInputString + kRegisterSize;
  static const int kInputStart = kStartIndex + kRegisterSize;
  static const int kInputEnd = kInputStart + kRegisterSize;
  static const int kRegisterOutput = kInputEnd + kRegisterSize;
130 131
  // For the case of global regular expression, we have room to store at least
  // one set of capture results.  For the case of non-global regexp, we ignore
132 133
  // this value. NumOutputRegisters is passed as 32-bit value.  The upper
  // 32 bit of this 64-bit stack slot may contain garbage.
134 135
  static const int kNumOutputRegisters = kRegisterOutput + kRegisterSize;
  static const int kStackHighEnd = kNumOutputRegisters + kRegisterSize;
136
  // DirectCall is passed as 32 bit int (values 0 or 1).
137 138
  static const int kDirectCall = kStackHighEnd + kRegisterSize;
  static const int kIsolate = kDirectCall + kRegisterSize;
139 140 141 142
#else
  // In AMD64 ABI Calling Convention, the first six integer parameters
  // are passed as registers, and caller must allocate space on the stack
  // if it wants them stored. We push the parameters after the frame pointer.
143 144 145 146 147 148
  static const int kInputString = kFramePointer - kRegisterSize;
  static const int kStartIndex = kInputString - kRegisterSize;
  static const int kInputStart = kStartIndex - kRegisterSize;
  static const int kInputEnd = kInputStart - kRegisterSize;
  static const int kRegisterOutput = kInputEnd - kRegisterSize;

149 150 151
  // For the case of global regular expression, we have room to store at least
  // one set of capture results.  For the case of non-global regexp, we ignore
  // this value.
152
  static const int kNumOutputRegisters = kRegisterOutput - kRegisterSize;
153
  static const int kStackHighEnd = kFrameAlign;
154 155
  static const int kDirectCall = kStackHighEnd + kRegisterSize;
  static const int kIsolate = kDirectCall + kRegisterSize;
156 157
#endif

158
#ifdef _WIN64
159 160
  // Microsoft calling convention has three callee-saved registers
  // (that we are using). We push these after the frame pointer.
161 162 163
  static const int kBackup_rsi = kFramePointer - kRegisterSize;
  static const int kBackup_rdi = kBackup_rsi - kRegisterSize;
  static const int kBackup_rbx = kBackup_rdi - kRegisterSize;
164 165 166 167 168
  static const int kLastCalleeSaveRegister = kBackup_rbx;
#else
  // AMD64 Calling Convention has only one callee-save register that
  // we use. We push this after the frame pointer (and after the
  // parameters).
169
  static const int kBackup_rbx = kNumOutputRegisters - kRegisterSize;
170 171 172
  static const int kLastCalleeSaveRegister = kBackup_rbx;
#endif

173
  static const int kSuccessfulCaptures = kLastCalleeSaveRegister - kPointerSize;
174 175
  // When adding local variables remember to push space for them in
  // the frame in GetCode.
176
  static const int kStringStartMinusOne = kSuccessfulCaptures - kPointerSize;
177 178

  // First register address. Following registers are below it on the stack.
179
  static const int kRegisterZero = kStringStartMinusOne - kPointerSize;
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213

  // Initial size of code buffer.
  static const size_t kRegExpCodeSize = 1024;

  // Load a number of characters at the given offset from the
  // current position, into the current-character register.
  void LoadCurrentCharacterUnchecked(int cp_offset, int character_count);

  // Check whether preemption has been requested.
  void CheckPreemption();

  // Check whether we are exceeding the stack limit on the backtrack stack.
  void CheckStackLimit();

  // Generate a call to CheckStackGuardState.
  void CallCheckStackGuardState();

  // The rbp-relative location of a regexp register.
  Operand register_location(int register_index);

  // The register containing the current character after LoadCurrentCharacter.
  inline Register current_character() { return rdx; }

  // The register containing the backtrack stack top. Provides a meaningful
  // name to the register.
  inline Register backtrack_stackpointer() { return rcx; }

  // The registers containing a self pointer to this code's Code object.
  inline Register code_object_pointer() { return r8; }

  // Byte size of chars in the string to match (decided by the Mode argument)
  inline int char_size() { return static_cast<int>(mode_); }

  // Equivalent to a conditional branch to the label, unless the label
214
  // is nullptr, in which case it is a conditional Backtrack.
215 216 217
  void BranchOrBacktrack(Condition condition, Label* to);

  void MarkPositionForCodeRelativeFixup() {
218
    code_relative_fixup_positions_.Add(masm_.pc_offset(), zone());
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
  }

  void FixupCodeRelativePositions();

  // Call and return internally in the generated code in a way that
  // is GC-safe (i.e., doesn't leave absolute code addresses on the stack)
  inline void SafeCall(Label* to);
  inline void SafeCallTarget(Label* label);
  inline void SafeReturn();

  // Pushes the value of a register on the backtrack stack. Decrements the
  // stack pointer (rcx) by a word size and stores the register's value there.
  inline void Push(Register source);

  // Pushes a value on the backtrack stack. Decrements the stack pointer (rcx)
  // by a word size and stores the value there.
  inline void Push(Immediate value);

  // Pushes the Code object relative offset of a label on the backtrack stack
  // (i.e., a backtrack target). Decrements the stack pointer (rcx)
  // by a word size and stores the value there.
  inline void Push(Label* label);

  // Pops a value from the backtrack stack. Reads the word at the stack pointer
  // (rcx) and increments it by a word size.
  inline void Pop(Register target);

  // Drops the top value from the backtrack stack without reading it.
  // Increments the stack pointer (rcx) by a word size.
  inline void Drop();

250 251
  inline void ReadPositionFromRegister(Register dst, int reg);

252 253
  Isolate* isolate() const { return masm_.isolate(); }

254
  MacroAssembler masm_;
255
  MacroAssembler::NoRootArrayScope no_root_array_scope_;
256 257 258

  ZoneList<int> code_relative_fixup_positions_;

259
  // Which mode to generate code for (LATIN1 or UC16).
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
  Mode mode_;

  // One greater than maximal register index actually used.
  int num_registers_;

  // Number of registers to output at the end (the saved registers
  // are always 0..num_saved_registers_-1)
  int num_saved_registers_;

  // Labels used internally.
  Label entry_label_;
  Label start_label_;
  Label success_label_;
  Label backtrack_label_;
  Label exit_label_;
  Label check_preempt_label_;
  Label stack_overflow_label_;
};

279
#endif  // V8_INTERPRETED_REGEXP
lrn@chromium.org's avatar
lrn@chromium.org committed
280

281 282
}  // namespace internal
}  // namespace v8
283

284
#endif  // V8_REGEXP_X64_REGEXP_MACRO_ASSEMBLER_X64_H_