blob: 8c5dd24cc9314c98733bf569c1f4e1330b0c98f7 [file] [log] [blame]
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001// Copyright 2008-2009 the V8 project authors. All rights reserved.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
ager@chromium.org5ec48922009-05-05 07:25:34 +000028#ifndef V8_IA32_REGEXP_MACRO_ASSEMBLER_IA32_H_
29#define V8_IA32_REGEXP_MACRO_ASSEMBLER_IA32_H_
ager@chromium.orga74f0da2008-12-03 16:05:52 +000030
31namespace v8 { namespace internal {
32
33class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
34 public:
35 // Type of input string to generate code for.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000036 enum Mode { ASCII = 1, UC16 = 2 };
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000037 // Result of calling the generated RegExp code:
38 // RETRY: Something significant changed during execution, and the matching
39 // should be retried from scratch.
40 // EXCEPTION: Something failed during execution. If no exception has been
41 // thrown, it's an internal out-of-memory, and the caller should
42 // throw the exception.
43 // FAILURE: Matching failed.
44 // SUCCESS: Matching succeeded, and the output array has been filled with
45 // capture positions.
46 enum Result { RETRY = -2, EXCEPTION = -1, FAILURE = 0, SUCCESS = 1 };
ager@chromium.orga74f0da2008-12-03 16:05:52 +000047
48 RegExpMacroAssemblerIA32(Mode mode, int registers_to_save);
49 virtual ~RegExpMacroAssemblerIA32();
ager@chromium.org32912102009-01-16 10:38:43 +000050 virtual int stack_limit_slack();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000051 virtual void AdvanceCurrentPosition(int by);
52 virtual void AdvanceRegister(int reg, int by);
53 virtual void Backtrack();
54 virtual void Bind(Label* label);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000055 virtual void CheckAtStart(Label* on_at_start);
ager@chromium.orga74f0da2008-12-03 16:05:52 +000056 virtual void CheckBitmap(uc16 start, Label* bitmap, Label* on_zero);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000057 virtual void CheckCharacter(uint32_t c, Label* on_equal);
58 virtual void CheckCharacterAfterAnd(uint32_t c,
59 uint32_t mask,
60 Label* on_equal);
ager@chromium.orga74f0da2008-12-03 16:05:52 +000061 virtual void CheckCharacterGT(uc16 limit, Label* on_greater);
62 virtual void CheckCharacterLT(uc16 limit, Label* on_less);
63 virtual void CheckCharacters(Vector<const uc16> str,
64 int cp_offset,
ager@chromium.org8bb60582008-12-11 12:02:20 +000065 Label* on_failure,
66 bool check_end_of_string);
ager@chromium.org32912102009-01-16 10:38:43 +000067 // A "greedy loop" is a loop that is both greedy and with a simple
68 // body. It has a particularly simple implementation.
ager@chromium.org8bb60582008-12-11 12:02:20 +000069 virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
ager@chromium.orga74f0da2008-12-03 16:05:52 +000070 virtual void CheckNotAtStart(Label* on_not_at_start);
71 virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
72 virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
73 Label* on_no_match);
74 virtual void CheckNotRegistersEqual(int reg1, int reg2, Label* on_not_equal);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000075 virtual void CheckNotCharacter(uint32_t c, Label* on_not_equal);
76 virtual void CheckNotCharacterAfterAnd(uint32_t c,
77 uint32_t mask,
78 Label* on_not_equal);
79 virtual void CheckNotCharacterAfterMinusAnd(uc16 c,
80 uc16 minus,
81 uc16 mask,
82 Label* on_not_equal);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000083 // Checks whether the given offset from the current position is before
84 // the end of the string.
85 virtual void CheckPosition(int cp_offset, Label* on_outside_input);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000086 virtual bool CheckSpecialCharacterClass(uc16 type,
87 int cp_offset,
88 bool check_offset,
89 Label* on_no_match);
ager@chromium.orga74f0da2008-12-03 16:05:52 +000090 virtual void DispatchByteMap(uc16 start,
91 Label* byte_map,
92 const Vector<Label*>& destinations);
93 virtual void DispatchHalfNibbleMap(uc16 start,
94 Label* half_nibble_map,
95 const Vector<Label*>& destinations);
96 virtual void DispatchHighByteMap(byte start,
97 Label* byte_map,
98 const Vector<Label*>& destinations);
99 virtual void EmitOrLink(Label* label);
100 virtual void Fail();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000101 virtual Handle<Object> GetCode(Handle<String> source);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000102 virtual void GoTo(Label* label);
103 virtual void IfRegisterGE(int reg, int comparand, Label* if_ge);
104 virtual void IfRegisterLT(int reg, int comparand, Label* if_lt);
ager@chromium.org32912102009-01-16 10:38:43 +0000105 virtual void IfRegisterEqPos(int reg, Label* if_eq);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000106 virtual IrregexpImplementation Implementation();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000107 virtual void LoadCurrentCharacter(int cp_offset,
108 Label* on_end_of_input,
109 bool check_bounds = true,
110 int characters = 1);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000111 virtual void PopCurrentPosition();
112 virtual void PopRegister(int register_index);
113 virtual void PushBacktrack(Label* label);
114 virtual void PushCurrentPosition();
ager@chromium.org32912102009-01-16 10:38:43 +0000115 virtual void PushRegister(int register_index,
116 StackCheckFlag check_stack_limit);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000117 virtual void ReadCurrentPositionFromRegister(int reg);
118 virtual void ReadStackPointerFromRegister(int reg);
119 virtual void SetRegister(int register_index, int to);
120 virtual void Succeed();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000121 virtual void WriteCurrentPositionToRegister(int reg, int cp_offset);
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000122 virtual void ClearRegisters(int reg_from, int reg_to);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000123 virtual void WriteStackPointerToRegister(int reg);
124
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000125 static Result Match(Handle<Code> regexp,
126 Handle<String> subject,
127 int* offsets_vector,
128 int offsets_vector_length,
129 int previous_index);
130
ager@chromium.org32912102009-01-16 10:38:43 +0000131 static Result Execute(Code* code,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000132 String* input,
ager@chromium.org32912102009-01-16 10:38:43 +0000133 int start_offset,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000134 const byte* input_start,
135 const byte* input_end,
ager@chromium.org32912102009-01-16 10:38:43 +0000136 int* output,
137 bool at_start);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000138
139 private:
ager@chromium.org32912102009-01-16 10:38:43 +0000140 // Offsets from ebp of function parameters and stored registers.
141 static const int kFramePointer = 0;
142 // Above the frame pointer - function parameters and return address.
143 static const int kReturn_eip = kFramePointer + kPointerSize;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000144 static const int kFrameAlign = kReturn_eip + kPointerSize;
145 // Parameters.
146 static const int kInputString = kFrameAlign;
147 static const int kStartIndex = kInputString + kPointerSize;
148 static const int kInputStart = kStartIndex + kPointerSize;
149 static const int kInputEnd = kInputStart + kPointerSize;
150 static const int kRegisterOutput = kInputEnd + kPointerSize;
ager@chromium.org32912102009-01-16 10:38:43 +0000151 static const int kAtStart = kRegisterOutput + kPointerSize;
152 static const int kStackHighEnd = kAtStart + kPointerSize;
153 // Below the frame pointer - local stack variables.
154 // When adding local variables remember to push space for them in
155 // the frame in GetCode.
156 static const int kBackup_esi = kFramePointer - kPointerSize;
157 static const int kBackup_edi = kBackup_esi - kPointerSize;
158 static const int kBackup_ebx = kBackup_edi - kPointerSize;
159 static const int kInputStartMinusOne = kBackup_ebx - kPointerSize;
160 // First register address. Following registers are below it on the stack.
161 static const int kRegisterZero = kInputStartMinusOne - kPointerSize;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000162
163 // Initial size of code buffer.
164 static const size_t kRegExpCodeSize = 1024;
165 // Initial size of constant buffers allocated during compilation.
166 static const int kRegExpConstantsSize = 256;
ager@chromium.org8bb60582008-12-11 12:02:20 +0000167
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000168 static const byte* StringCharacterPosition(String* subject, int start_index);
169
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000170 // Compares two-byte strings case insensitively.
ager@chromium.org32912102009-01-16 10:38:43 +0000171 // Called from generated RegExp code.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000172 static int CaseInsensitiveCompareUC16(Address byte_offset1,
173 Address byte_offset2,
ager@chromium.org8bb60582008-12-11 12:02:20 +0000174 size_t byte_length);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000175
ager@chromium.org32912102009-01-16 10:38:43 +0000176 // Load a number of characters at the given offset from the
177 // current position, into the current-character register.
178 void LoadCurrentCharacterUnchecked(int cp_offset, int character_count);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000179
ager@chromium.org32912102009-01-16 10:38:43 +0000180 // Check whether preemption has been requested.
181 void CheckPreemption();
182
183 // Check whether we are exceeding the stack limit on the backtrack stack.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000184 void CheckStackLimit();
185
186 // Called from RegExp if the stack-guard is triggered.
187 // If the code object is relocated, the return address is fixed before
188 // returning.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000189 static int CheckStackGuardState(Address* return_address,
190 Code* re_code,
191 Address re_frame);
192
193 // Generate a call to CheckStackGuardState.
194 void CallCheckStackGuardState(Register scratch);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000195
ager@chromium.org32912102009-01-16 10:38:43 +0000196 // Called from RegExp if the backtrack stack limit is hit.
ager@chromium.org6f10e412009-02-13 10:11:16 +0000197 // Tries to expand the stack. Returns the new stack-pointer if
198 // successful, and updates the stack_top address, or returns 0 if unable
199 // to grow the stack.
ager@chromium.org32912102009-01-16 10:38:43 +0000200 // This function must not trigger a garbage collection.
ager@chromium.org6f10e412009-02-13 10:11:16 +0000201 static Address GrowStack(Address stack_pointer, Address* stack_top);
ager@chromium.org32912102009-01-16 10:38:43 +0000202
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000203 // The ebp-relative location of a regexp register.
204 Operand register_location(int register_index);
205
206 // The register containing the current character after LoadCurrentCharacter.
ager@chromium.org32912102009-01-16 10:38:43 +0000207 inline Register current_character() { return edx; }
208
209 // The register containing the backtrack stack top. Provides a meaningful
210 // name to the register.
211 inline Register backtrack_stackpointer() { return ecx; }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000212
213 // Byte size of chars in the string to match (decided by the Mode argument)
ager@chromium.org32912102009-01-16 10:38:43 +0000214 inline int char_size() { return static_cast<int>(mode_); }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000215
216 // Equivalent to a conditional branch to the label, unless the label
217 // is NULL, in which case it is a conditional Backtrack.
ager@chromium.org32912102009-01-16 10:38:43 +0000218 void BranchOrBacktrack(Condition condition, Label* to, Hint hint = no_hint);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000219
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000220 // Load the address of a "constant buffer" (a slice of a byte array)
221 // into a register. The address is computed from the ByteArray* address
222 // and an offset. Uses no extra registers.
223 void LoadConstantBufferAddress(Register reg, ArraySlice* buffer);
224
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000225 // Call and return internally in the generated code in a way that
226 // is GC-safe (i.e., doesn't leave absolute code addresses on the stack)
ager@chromium.org32912102009-01-16 10:38:43 +0000227 inline void SafeCall(Label* to);
228 inline void SafeReturn();
229
230 // Pushes the value of a register on the backtrack stack. Decrements the
231 // stack pointer (ecx) 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 (ecx)
235 // by a word size and stores the value there.
236 inline void Push(Immediate value);
237
238 // Pops a value from the backtrack stack. Reads the word at the stack pointer
239 // (ecx) and increments it by a word size.
240 inline void Pop(Register target);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000241
242 // Before calling a C-function from generated code, align arguments on stack.
243 // After aligning the frame, arguments must be stored in esp[0], esp[4],
244 // etc., not pushed. The argument count assumes all arguments are word sized.
ager@chromium.org32912102009-01-16 10:38:43 +0000245 // Some compilers/platforms require the stack to be aligned when calling
246 // C++ code.
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000247 // Needs a scratch register to do some arithmetic. This register will be
248 // trashed.
249 inline void FrameAlign(int num_arguments, Register scratch);
ager@chromium.org32912102009-01-16 10:38:43 +0000250
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000251 // Calls a C function and cleans up the space for arguments allocated
252 // by FrameAlign. The called function is not allowed to trigger a garbage
253 // collection, since that might move the code and invalidate the return
ager@chromium.org32912102009-01-16 10:38:43 +0000254 // address (unless this is somehow accounted for).
255 inline void CallCFunction(Address function_address, int num_arguments);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000256
257 MacroAssembler* masm_;
ager@chromium.org32912102009-01-16 10:38:43 +0000258
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000259 // Constant buffer provider. Allocates external storage for storing
260 // constants.
261 ByteArrayProvider constants_;
ager@chromium.org32912102009-01-16 10:38:43 +0000262
263 // Which mode to generate code for (ASCII or UC16).
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000264 Mode mode_;
ager@chromium.org32912102009-01-16 10:38:43 +0000265
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000266 // One greater than maximal register index actually used.
267 int num_registers_;
ager@chromium.org32912102009-01-16 10:38:43 +0000268
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000269 // Number of registers to output at the end (the saved registers
270 // are always 0..num_saved_registers_-1)
271 int num_saved_registers_;
ager@chromium.org32912102009-01-16 10:38:43 +0000272
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000273 // Labels used internally.
274 Label entry_label_;
275 Label start_label_;
276 Label success_label_;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000277 Label backtrack_label_;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000278 Label exit_label_;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000279 Label check_preempt_label_;
ager@chromium.org32912102009-01-16 10:38:43 +0000280 Label stack_overflow_label_;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000281};
282
283}} // namespace v8::internal
284
ager@chromium.org5ec48922009-05-05 07:25:34 +0000285#endif // V8_IA32_REGEXP_MACRO_ASSEMBLER_IA32_H_