regexp-macro-assembler-x64.h 12 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 37 38 39 40 41 42 43 44 45 46 47 48
  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);
  virtual void CheckNotAtStart(Label* on_not_at_start);
  virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
  virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
                                               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);
49 50 51 52 53 54 55 56
  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);

57 58 59 60 61 62
  // 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();
63
  virtual Handle<HeapObject> GetCode(Handle<String> source);
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
  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);
81
  virtual void SetCurrentPositionFromEnd(int by);
82
  virtual void SetRegister(int register_index, int to);
83
  virtual bool Succeed();
84 85 86 87 88 89 90 91
  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,
92 93
                      int previous_index,
                      Isolate* isolate);
94 95 96 97 98 99 100 101 102

  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
103 104 105 106 107 108 109
  // 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);

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

117
#ifdef _WIN64
118 119 120 121 122
  // 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;
123
  // StartIndex is passed as 32 bit int.
124 125 126 127
  static const int kStartIndex = kInputString + kRegisterSize;
  static const int kInputStart = kStartIndex + kRegisterSize;
  static const int kInputEnd = kInputStart + kRegisterSize;
  static const int kRegisterOutput = kInputEnd + kRegisterSize;
128 129
  // 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
130 131
  // this value. NumOutputRegisters is passed as 32-bit value.  The upper
  // 32 bit of this 64-bit stack slot may contain garbage.
132 133
  static const int kNumOutputRegisters = kRegisterOutput + kRegisterSize;
  static const int kStackHighEnd = kNumOutputRegisters + kRegisterSize;
134
  // DirectCall is passed as 32 bit int (values 0 or 1).
135 136
  static const int kDirectCall = kStackHighEnd + kRegisterSize;
  static const int kIsolate = kDirectCall + kRegisterSize;
137 138 139 140
#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.
141 142 143 144 145 146
  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;

147 148 149
  // 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.
150
  static const int kNumOutputRegisters = kRegisterOutput - kRegisterSize;
151
  static const int kStackHighEnd = kFrameAlign;
152 153
  static const int kDirectCall = kStackHighEnd + kRegisterSize;
  static const int kIsolate = kDirectCall + kRegisterSize;
154 155
#endif

156
#ifdef _WIN64
157 158
  // Microsoft calling convention has three callee-saved registers
  // (that we are using). We push these after the frame pointer.
159 160 161
  static const int kBackup_rsi = kFramePointer - kRegisterSize;
  static const int kBackup_rdi = kBackup_rsi - kRegisterSize;
  static const int kBackup_rbx = kBackup_rdi - kRegisterSize;
162 163 164 165 166
  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).
167
  static const int kBackup_rbx = kNumOutputRegisters - kRegisterSize;
168 169 170
  static const int kLastCalleeSaveRegister = kBackup_rbx;
#endif

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

  // First register address. Following registers are below it on the stack.
177
  static const int kRegisterZero = kInputStartMinusOne - kPointerSize;
178 179 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 214 215

  // 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
  // is NULL, in which case it is a conditional Backtrack.
  void BranchOrBacktrack(Condition condition, Label* to);

  void MarkPositionForCodeRelativeFixup() {
216
    code_relative_fixup_positions_.Add(masm_.pc_offset(), zone());
217 218 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
  }

  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();

248 249
  inline void ReadPositionFromRegister(Register dst, int reg);

250 251
  Isolate* isolate() const { return masm_.isolate(); }

252
  MacroAssembler masm_;
253
  MacroAssembler::NoRootArrayScope no_root_array_scope_;
254 255 256

  ZoneList<int> code_relative_fixup_positions_;

257
  // Which mode to generate code for (LATIN1 or UC16).
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
  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_;
};

277
#endif  // V8_INTERPRETED_REGEXP
lrn@chromium.org's avatar
lrn@chromium.org committed
278

279 280
}  // namespace internal
}  // namespace v8
281

282
#endif  // V8_REGEXP_X64_REGEXP_MACRO_ASSEMBLER_X64_H_