Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: src/x64/regexp-macro-assembler-x64.cc

Issue 165443: X64: Implement RegExp natively. (Closed)
Patch Set: Addressed review comments. Created 11 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2009 the V8 project authors. All rights reserved. 1 // Copyright 2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution. 11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its 12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived 13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission. 14 // from this software without specific prior written permission.
15 // 15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 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. 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28 #include "v8.h"
29 #include "serialize.h"
30 #include "unicode.h"
31 #include "log.h"
32 #include "ast.h"
33 #include "regexp-stack.h"
34 #include "macro-assembler.h"
35 #include "regexp-macro-assembler.h"
36 #include "x64/macro-assembler-x64.h"
37 #include "x64/regexp-macro-assembler-x64.h"
38
39 namespace v8 {
40 namespace internal {
41
42 /*
43 * This assembler uses the following register assignment convention
44 * - rdx : currently loaded character(s) as ASCII or UC16. Must be loaded using
45 * LoadCurrentCharacter before using any of the dispatch methods.
46 * - rdi : current position in input, as negative offset from end of string.
47 * Please notice that this is the byte offset, not the character
48 * offset! Is always a 32-bit signed (negative) offset, but must be
49 * maintained sign-extended to 64 bits, since it is used as index.
50 * - rsi : end of input (points to byte after last character in input),
51 * so that rsi+rdi points to the current character.
52 * - rbp : frame pointer. Used to access arguments, local variables and
53 * RegExp registers.
54 * - rsp : points to tip of C stack.
55 * - rcx : points to tip of backtrack stack. The backtrack stack contains
56 * only 32-bit values. Most are offsets from some base (e.g., character
57 * positions from end of string or code location from Code* pointer).
58 * - r8 : code object pointer. Used to convert between absolute and
59 * code-object-relative addresses.
60 *
61 * The registers rax, rbx, rcx, r9 and r11 are free to use for computations.
62 * If changed to use r12+, they should be saved as callee-save registers.
63 *
64 * Each call to a C++ method should retain these registers.
65 *
66 * The stack will have the following content, in some order, indexable from the
67 * frame pointer (see, e.g., kStackHighEnd):
68 * - stack_area_base (High end of the memory area to use as
69 * backtracking stack)
70 * - at_start (if 1, start at start of string, if 0, don't)
71 * - int* capture_array (int[num_saved_registers_], for output).
72 * - end of input (Address of end of string)
73 * - start of input (Address of first character in string)
74 * - String** input_string (location of a handle containing the string)
75 * - return address
76 * - backup of callee save registers (rbx, possibly rsi and rdi).
77 * - Offset of location before start of input (effectively character
78 * position -1). Used to initialize capture registers to a non-position.
79 * - register 0 rbp[-n] (Only positions must be stored in the first
80 * - register 1 rbp[-n-8] num_saved_registers_ registers)
81 * - ...
82 *
83 * The first num_saved_registers_ registers are initialized to point to
84 * "character -1" in the string (i.e., char_size() bytes before the first
85 * character of the string). The remaining registers starts out uninitialized.
86 *
87 * The first seven values must be provided by the calling code by
88 * calling the code's entry address cast to a function pointer with the
89 * following signature:
90 * int (*match)(String* input_string,
91 * Address start,
92 * Address end,
93 * int* capture_output_array,
94 * bool at_start,
95 * byte* stack_area_base)
96 */
97
98 #define __ ACCESS_MASM(masm_)
99
100 RegExpMacroAssemblerX64::RegExpMacroAssemblerX64(
101 Mode mode,
102 int registers_to_save)
103 : masm_(new MacroAssembler(NULL, kRegExpCodeSize)),
104 code_relative_fixup_positions_(4),
105 mode_(mode),
106 num_registers_(registers_to_save),
107 num_saved_registers_(registers_to_save),
108 entry_label_(),
109 start_label_(),
110 success_label_(),
111 backtrack_label_(),
112 exit_label_() {
113 __ jmp(&entry_label_); // We'll write the entry code when we know more.
114 __ bind(&start_label_); // And then continue from here.
115 }
116
117
118 RegExpMacroAssemblerX64::~RegExpMacroAssemblerX64() {
119 delete masm_;
120 // Unuse labels in case we throw away the assembler without calling GetCode.
121 entry_label_.Unuse();
122 start_label_.Unuse();
123 success_label_.Unuse();
124 backtrack_label_.Unuse();
125 exit_label_.Unuse();
126 check_preempt_label_.Unuse();
127 stack_overflow_label_.Unuse();
128 }
129
130
131 int RegExpMacroAssemblerX64::stack_limit_slack() {
132 return RegExpStack::kStackLimitSlack;
133 }
134
135
136 void RegExpMacroAssemblerX64::AdvanceCurrentPosition(int by) {
137 if (by != 0) {
138 Label inside_string;
139 __ addq(rdi, Immediate(by * char_size()));
140 }
141 }
142
143
144 void RegExpMacroAssemblerX64::AdvanceRegister(int reg, int by) {
145 ASSERT(reg >= 0);
146 ASSERT(reg < num_registers_);
147 if (by != 0) {
148 __ addq(register_location(reg), Immediate(by));
149 }
150 }
151
152
153 void RegExpMacroAssemblerX64::Backtrack() {
154 CheckPreemption();
155 // Pop Code* offset from backtrack stack, add Code* and jump to location.
156 Pop(rbx);
157 __ addq(rbx, code_object_pointer());
158 __ jmp(rbx);
159 }
160
161
162 void RegExpMacroAssemblerX64::Bind(Label* label) {
163 __ bind(label);
164 }
165
166
167 void RegExpMacroAssemblerX64::CheckCharacter(uint32_t c, Label* on_equal) {
168 __ cmpl(current_character(), Immediate(c));
169 BranchOrBacktrack(equal, on_equal);
170 }
171
172
173 void RegExpMacroAssemblerX64::CheckCharacterGT(uc16 limit, Label* on_greater) {
174 __ cmpl(current_character(), Immediate(limit));
175 BranchOrBacktrack(greater, on_greater);
176 }
177
178
179 void RegExpMacroAssemblerX64::CheckAtStart(Label* on_at_start) {
180 Label not_at_start;
181 // Did we start the match at the start of the string at all?
182 __ cmpb(Operand(rbp, kAtStart), Immediate(0));
183 BranchOrBacktrack(equal, &not_at_start);
184 // If we did, are we still at the start of the input?
185 __ lea(rax, Operand(rsi, rdi, times_1, 0));
186 __ cmpq(rax, Operand(rbp, kInputStart));
187 BranchOrBacktrack(equal, on_at_start);
188 __ bind(&not_at_start);
189 }
190
191
192 void RegExpMacroAssemblerX64::CheckNotAtStart(Label* on_not_at_start) {
193 // Did we start the match at the start of the string at all?
194 __ cmpb(Operand(rbp, kAtStart), Immediate(0));
195 BranchOrBacktrack(equal, on_not_at_start);
196 // If we did, are we still at the start of the input?
197 __ lea(rax, Operand(rsi, rdi, times_1, 0));
198 __ cmpq(rax, Operand(rbp, kInputStart));
199 BranchOrBacktrack(not_equal, on_not_at_start);
200 }
201
202
203 void RegExpMacroAssemblerX64::CheckCharacterLT(uc16 limit, Label* on_less) {
204 __ cmpl(current_character(), Immediate(limit));
205 BranchOrBacktrack(less, on_less);
206 }
207
208
209 void RegExpMacroAssemblerX64::CheckCharacters(Vector<const uc16> str,
210 int cp_offset,
211 Label* on_failure,
212 bool check_end_of_string) {
213 int byte_length = str.length() * char_size();
214 int byte_offset = cp_offset * char_size();
215 if (check_end_of_string) {
216 // Check that there are at least str.length() characters left in the input.
217 __ cmpl(rdi, Immediate(-(byte_offset + byte_length)));
218 BranchOrBacktrack(greater, on_failure);
219 }
220
221 if (on_failure == NULL) {
222 // Instead of inlining a backtrack, (re)use the global backtrack target.
223 on_failure = &backtrack_label_;
224 }
225
226 // TODO(lrn): Test multiple characters at a time by loading 4 or 8 bytes
227 // at a time.
228 for (int i = 0; i < str.length(); i++) {
229 if (mode_ == ASCII) {
230 __ cmpb(Operand(rsi, rdi, times_1, byte_offset + i),
231 Immediate(static_cast<int8_t>(str[i])));
232 } else {
233 ASSERT(mode_ == UC16);
234 __ cmpw(Operand(rsi, rdi, times_1, byte_offset + i * sizeof(uc16)),
235 Immediate(str[i]));
236 }
237 BranchOrBacktrack(not_equal, on_failure);
238 }
239 }
240
241
242 void RegExpMacroAssemblerX64::CheckGreedyLoop(Label* on_equal) {
243 Label fallthrough;
244 __ cmpl(rdi, Operand(backtrack_stackpointer(), 0));
245 __ j(not_equal, &fallthrough);
246 Drop();
247 BranchOrBacktrack(no_condition, on_equal);
248 __ bind(&fallthrough);
249 }
250
251
252 void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase(
253 int start_reg,
254 Label* on_no_match) {
255 Label fallthrough;
256 __ movq(rdx, register_location(start_reg)); // Offset of start of capture
257 __ movq(rbx, register_location(start_reg + 1)); // Offset of end of capture
258 __ subq(rbx, rdx); // Length of capture.
259
260 // -----------------------
261 // rdx = Start offset of capture.
262 // rbx = Length of capture
263
264 // If length is negative, this code will fail (it's a symptom of a partial or
265 // illegal capture where start of capture after end of capture).
266 // This must not happen (no back-reference can reference a capture that wasn't
267 // closed before in the reg-exp, and we must not generate code that can cause
268 // this condition).
269
270 // If length is zero, either the capture is empty or it is nonparticipating.
271 // In either case succeed immediately.
272 __ j(equal, &fallthrough);
273
274 if (mode_ == ASCII) {
275 Label loop_increment;
276 if (on_no_match == NULL) {
277 on_no_match = &backtrack_label_;
278 }
279
280 __ lea(r9, Operand(rsi, rdx, times_1, 0));
281 __ lea(r11, Operand(rsi, rdi, times_1, 0));
282 __ addq(rbx, r9); // End of capture
283 // ---------------------
284 // r11 - current input character address
285 // r9 - current capture character address
286 // rbx - end of capture
287
288 Label loop;
289 __ bind(&loop);
290 __ movzxbl(rdx, Operand(r9, 0));
291 __ movzxbl(rax, Operand(r11, 0));
292 // al - input character
293 // dl - capture character
294 __ cmpb(rax, rdx);
295 __ j(equal, &loop_increment);
296
297 // Mismatch, try case-insensitive match (converting letters to lower-case).
298 // I.e., if or-ing with 0x20 makes values equal and in range 'a'-'z', it's
299 // a match.
300 __ or_(rax, Immediate(0x20)); // Convert match character to lower-case.
301 __ or_(rdx, Immediate(0x20)); // Convert capture character to lower-case.
302 __ cmpb(rax, rdx);
303 __ j(not_equal, on_no_match); // Definitely not equal.
304 __ subb(rax, Immediate('a'));
305 __ cmpb(rax, Immediate('z' - 'a'));
306 __ j(above, on_no_match); // Weren't letters anyway.
307
308 __ bind(&loop_increment);
309 // Increment pointers into match and capture strings.
310 __ addq(r11, Immediate(1));
311 __ addq(r9, Immediate(1));
312 // Compare to end of capture, and loop if not done.
313 __ cmpq(r9, rbx);
314 __ j(below, &loop);
315
316 // Compute new value of character position after the matched part.
317 __ movq(rdi, r11);
318 __ subq(rdi, rsi);
319 } else {
320 ASSERT(mode_ == UC16);
321 // Save important/volatile registers before calling C function.
322 #ifndef __MSVC__
323 // Callee save on Win64
324 __ push(rsi);
325 __ push(rdi);
326 #endif
327 __ push(backtrack_stackpointer());
328
329 int num_arguments = 3;
330 FrameAlign(num_arguments);
331
332 // Put arguments into parameter registers. Parameters are
333 // Address byte_offset1 - Address captured substring's start.
334 // Address byte_offset2 - Address of current character position.
335 // size_t byte_length - length of capture in bytes(!)
336 #ifdef __MSVC__
337 // Compute and set byte_offset1 (start of capture).
338 __ lea(rcx, Operand(rsi, rdx, times_1, 0));
339 // Set byte_offset2.
340 __ lea(rdx, Operand(rsi, rdi, times_1, 0));
341 // Set byte_length.
342 __ movq(r8, rbx);
343 #else // AMD64 calling convention
344 // Compute byte_offset2 (current position = rsi+rdi).
345 __ lea(rax, Operand(rsi, rdi, times_1, 0));
346 // Compute and set byte_offset1 (start of capture).
347 __ lea(rdi, Operand(rsi, rdx, times_1, 0));
348 // Set byte_offset2.
349 __ movq(rsi, rax);
350 // Set byte_length.
351 __ movq(rdx, rbx);
352 #endif
353 Address function_address = FUNCTION_ADDR(&CaseInsensitiveCompareUC16);
354 CallCFunction(function_address, num_arguments);
355
356 // Restore original values before reacting on result value.
357 __ Move(code_object_pointer(), masm_->CodeObject());
358 __ pop(backtrack_stackpointer());
359 #ifndef __MSVC__
360 __ pop(rdi);
361 __ pop(rsi);
362 #endif
363
364 // Check if function returned non-zero for success or zero for failure.
365 __ testq(rax, rax);
366 BranchOrBacktrack(zero, on_no_match);
367 // On success, increment position by length of capture.
368 // Requires that rbx is callee save (true for both Win64 and AMD64 ABIs).
369 __ addq(rdi, rbx);
370 }
371 __ bind(&fallthrough);
372 }
373
374
375 void RegExpMacroAssemblerX64::CheckNotBackReference(
376 int start_reg,
377 Label* on_no_match) {
378 Label fallthrough;
379
380 // Find length of back-referenced capture.
381 __ movq(rdx, register_location(start_reg));
382 __ movq(rax, register_location(start_reg + 1));
383 __ subq(rax, rdx); // Length to check.
384
385 // Fail on partial or illegal capture (start of capture after end of capture).
386 // This must not happen (no back-reference can reference a capture that wasn't
387 // closed before in the reg-exp).
388 __ Check(greater_equal, "Invalid capture referenced");
389
390 // Succeed on empty capture (including non-participating capture)
391 __ j(equal, &fallthrough);
392
393 // -----------------------
394 // rdx - Start of capture
395 // rax - length of capture
396
397 // Check that there are sufficient characters left in the input.
398 __ movl(rbx, rdi);
399 __ addl(rbx, rax);
400 BranchOrBacktrack(greater, on_no_match);
401
402 // Compute pointers to match string and capture string
403 __ lea(rbx, Operand(rsi, rdi, times_1, 0)); // Start of match.
404 __ addq(rdx, rsi); // Start of capture.
405 __ lea(r9, Operand(rdx, rax, times_1, 0)); // End of capture
406
407 // -----------------------
408 // rbx - current capture character address.
409 // rbx - current input character address .
410 // r9 - end of input to match (capture length after rbx).
411
412 Label loop;
413 __ bind(&loop);
414 if (mode_ == ASCII) {
415 __ movzxbl(rax, Operand(rdx, 0));
416 __ cmpb(rax, Operand(rbx, 0));
417 } else {
418 ASSERT(mode_ == UC16);
419 __ movzxwl(rax, Operand(rdx, 0));
420 __ cmpw(rax, Operand(rbx, 0));
421 }
422 BranchOrBacktrack(not_equal, on_no_match);
423 // Increment pointers into capture and match string.
424 __ addq(rbx, Immediate(char_size()));
425 __ addq(rdx, Immediate(char_size()));
426 // Check if we have reached end of match area.
427 __ cmpq(rdx, r9);
428 __ j(below, &loop);
429
430 // Success.
431 // Set current character position to position after match.
432 __ movq(rdi, rbx);
433 __ subq(rdi, rsi);
434
435 __ bind(&fallthrough);
436 }
437
438
439 void RegExpMacroAssemblerX64::CheckNotRegistersEqual(int reg1,
440 int reg2,
441 Label* on_not_equal) {
442 __ movq(rax, register_location(reg1));
443 __ cmpq(rax, register_location(reg2));
444 BranchOrBacktrack(not_equal, on_not_equal);
445 }
446
447
448 void RegExpMacroAssemblerX64::CheckNotCharacter(uint32_t c,
449 Label* on_not_equal) {
450 __ cmpl(current_character(), Immediate(c));
451 BranchOrBacktrack(not_equal, on_not_equal);
452 }
453
454
455 void RegExpMacroAssemblerX64::CheckCharacterAfterAnd(uint32_t c,
456 uint32_t mask,
457 Label* on_equal) {
458 __ movl(rax, current_character());
459 __ and_(rax, Immediate(mask));
460 __ cmpl(rax, Immediate(c));
461 BranchOrBacktrack(equal, on_equal);
462 }
463
464
465 void RegExpMacroAssemblerX64::CheckNotCharacterAfterAnd(uint32_t c,
466 uint32_t mask,
467 Label* on_not_equal) {
468 __ movl(rax, current_character());
469 __ and_(rax, Immediate(mask));
470 __ cmpl(rax, Immediate(c));
471 BranchOrBacktrack(not_equal, on_not_equal);
472 }
473
474
475 void RegExpMacroAssemblerX64::CheckNotCharacterAfterMinusAnd(
476 uc16 c,
477 uc16 minus,
478 uc16 mask,
479 Label* on_not_equal) {
480 ASSERT(minus < String::kMaxUC16CharCode);
481 __ lea(rax, Operand(current_character(), -minus));
482 __ and_(rax, Immediate(mask));
483 __ cmpl(rax, Immediate(c));
484 BranchOrBacktrack(not_equal, on_not_equal);
485 }
486
487
488 bool RegExpMacroAssemblerX64::CheckSpecialCharacterClass(uc16 type,
489 int cp_offset,
490 bool check_offset,
491 Label* on_no_match) {
492 // Range checks (c in min..max) are generally implemented by an unsigned
493 // (c - min) <= (max - min) check
494 switch (type) {
495 case 's':
496 // Match space-characters
497 if (mode_ == ASCII) {
498 // ASCII space characters are '\t'..'\r' and ' '.
499 if (check_offset) {
500 LoadCurrentCharacter(cp_offset, on_no_match);
501 } else {
502 LoadCurrentCharacterUnchecked(cp_offset, 1);
503 }
504 Label success;
505 __ cmpl(current_character(), Immediate(' '));
506 __ j(equal, &success);
507 // Check range 0x09..0x0d
508 __ subl(current_character(), Immediate('\t'));
509 __ cmpl(current_character(), Immediate('\r' - '\t'));
510 BranchOrBacktrack(above, on_no_match);
511 __ bind(&success);
512 return true;
513 }
514 return false;
515 case 'S':
516 // Match non-space characters.
517 if (check_offset) {
518 LoadCurrentCharacter(cp_offset, on_no_match, 1);
519 } else {
520 LoadCurrentCharacterUnchecked(cp_offset, 1);
521 }
522 if (mode_ == ASCII) {
523 // ASCII space characters are '\t'..'\r' and ' '.
524 __ cmpl(current_character(), Immediate(' '));
525 BranchOrBacktrack(equal, on_no_match);
526 __ subl(current_character(), Immediate('\t'));
527 __ cmpl(current_character(), Immediate('\r' - '\t'));
528 BranchOrBacktrack(below_equal, on_no_match);
529 return true;
530 }
531 return false;
532 case 'd':
533 // Match ASCII digits ('0'..'9')
534 if (check_offset) {
535 LoadCurrentCharacter(cp_offset, on_no_match, 1);
536 } else {
537 LoadCurrentCharacterUnchecked(cp_offset, 1);
538 }
539 __ subl(current_character(), Immediate('0'));
540 __ cmpl(current_character(), Immediate('9' - '0'));
541 BranchOrBacktrack(above, on_no_match);
542 return true;
543 case 'D':
544 // Match non ASCII-digits
545 if (check_offset) {
546 LoadCurrentCharacter(cp_offset, on_no_match, 1);
547 } else {
548 LoadCurrentCharacterUnchecked(cp_offset, 1);
549 }
550 __ subl(current_character(), Immediate('0'));
551 __ cmpl(current_character(), Immediate('9' - '0'));
552 BranchOrBacktrack(below_equal, on_no_match);
553 return true;
554 case '.': {
555 // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
556 if (check_offset) {
557 LoadCurrentCharacter(cp_offset, on_no_match, 1);
558 } else {
559 LoadCurrentCharacterUnchecked(cp_offset, 1);
560 }
561 __ xor_(current_character(), Immediate(0x01));
562 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
563 __ subl(current_character(), Immediate(0x0b));
564 __ cmpl(current_character(), Immediate(0x0c - 0x0b));
565 BranchOrBacktrack(below_equal, on_no_match);
566 if (mode_ == UC16) {
567 // Compare original value to 0x2028 and 0x2029, using the already
568 // computed (current_char ^ 0x01 - 0x0b). I.e., check for
569 // 0x201d (0x2028 - 0x0b) or 0x201e.
570 __ subl(current_character(), Immediate(0x2028 - 0x0b));
571 __ cmpl(current_character(), Immediate(1));
572 BranchOrBacktrack(below_equal, on_no_match);
573 }
574 return true;
575 }
576 case '*':
577 // Match any character.
578 if (check_offset) {
579 CheckPosition(cp_offset, on_no_match);
580 }
581 return true;
582 // No custom implementation (yet): w, W, s(UC16), S(UC16).
583 default:
584 return false;
585 }
586 }
587
588
589 void RegExpMacroAssemblerX64::Fail() {
590 ASSERT(FAILURE == 0); // Return value for failure is zero.
591 __ xor_(rax, rax); // zero rax.
592 __ jmp(&exit_label_);
593 }
594
595
596 Handle<Object> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
597 // Finalize code - write the entry point code now we know how many
598 // registers we need.
599
600 // Entry code:
601 __ bind(&entry_label_);
602 // Start new stack frame.
603 __ push(rbp);
604 __ movq(rbp, rsp);
605 // Save parameters and callee-save registers. Order here should correspond
606 // to order of kBackup_ebx etc.
607 #ifdef __MSVC__
608 // MSVC passes arguments in rcx, rdx, r8, r9, with backing stack slots.
609 // Store register parameters in pre-allocated stack slots,
610 __ movq(Operand(rbp, kInputString), rcx);
611 __ movq(Operand(rbp, kStartIndex), rdx);
612 __ movq(Operand(rbp, kInputStart), r8);
613 __ movq(Operand(rbp, kInputEnd), r9);
614 // Callee-save on Win64.
615 __ push(rsi);
616 __ push(rdi);
617 __ push(rbx);
618 #else
619 // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9 (and then on stack).
620 // Push register parameters on stack for reference.
621 ASSERT_EQ(kInputString, -1 * kPointerSize);
622 ASSERT_EQ(kStartIndex, -2 * kPointerSize);
623 ASSERT_EQ(kInputStart, -3 * kPointerSize);
624 ASSERT_EQ(kInputEnd, -4 * kPointerSize);
625 ASSERT_EQ(kRegisterOutput, -5 * kPointerSize);
626 ASSERT_EQ(kAtStart, -6 * kPointerSize);
627 __ push(rdi);
628 __ push(rsi);
629 __ push(rdx);
630 __ push(rcx);
631 __ push(r8);
632 __ push(r9);
633
634 __ push(rbx); // Callee-save
635 #endif
636 __ push(Immediate(0)); // Make room for "input start - 1" constant.
637
638 // Check if we have space on the stack for registers.
639 Label stack_limit_hit;
640 Label stack_ok;
641
642 ExternalReference stack_guard_limit =
643 ExternalReference::address_of_stack_guard_limit();
644 __ movq(rcx, rsp);
645 __ movq(kScratchRegister, stack_guard_limit);
646 __ subq(rcx, Operand(kScratchRegister, 0));
647 // Handle it if the stack pointer is already below the stack limit.
648 __ j(below_equal, &stack_limit_hit);
649 // Check if there is room for the variable number of registers above
650 // the stack limit.
651 __ cmpq(rcx, Immediate(num_registers_ * kPointerSize));
652 __ j(above_equal, &stack_ok);
653 // Exit with OutOfMemory exception. There is not enough space on the stack
654 // for our working registers.
655 __ movq(rax, Immediate(EXCEPTION));
656 __ jmp(&exit_label_);
657
658 __ bind(&stack_limit_hit);
659 __ Move(code_object_pointer(), masm_->CodeObject());
660 CallCheckStackGuardState(); // Preserves no registers beside rbp and rsp.
661 __ testq(rax, rax);
662 // If returned value is non-zero, we exit with the returned value as result.
663 __ j(not_zero, &exit_label_);
664
665 __ bind(&stack_ok);
666
667 // Allocate space on stack for registers.
668 __ subq(rsp, Immediate(num_registers_ * kPointerSize));
669 // Load string length.
670 __ movq(rsi, Operand(rbp, kInputEnd));
671 // Load input position.
672 __ movq(rdi, Operand(rbp, kInputStart));
673 // Set up rdi to be negative offset from string end.
674 __ subq(rdi, rsi);
675 // Set rax to address of char before start of input
676 // (effectively string position -1).
677 __ lea(rax, Operand(rdi, -char_size()));
678 // Store this value in a local variable, for use when clearing
679 // position registers.
680 __ movq(Operand(rbp, kInputStartMinusOne), rax);
681 if (num_saved_registers_ > 0) {
682 // Fill saved registers with initial value = start offset - 1
683 // Fill in stack push order, to avoid accessing across an unwritten
684 // page (a problem on Windows).
685 __ movq(rcx, Immediate(kRegisterZero));
686 Label init_loop;
687 __ bind(&init_loop);
688 __ movq(Operand(rbp, rcx, times_1, 0), rax);
689 __ subq(rcx, Immediate(kPointerSize));
690 __ cmpq(rcx,
691 Immediate(kRegisterZero - num_saved_registers_ * kPointerSize));
692 __ j(greater, &init_loop);
693 }
694 // Ensure that we have written to each stack page, in order. Skipping a page
695 // on Windows can cause segmentation faults. Assuming page size is 4k.
696 const int kPageSize = 4096;
697 const int kRegistersPerPage = kPageSize / kPointerSize;
698 for (int i = num_saved_registers_ + kRegistersPerPage - 1;
699 i < num_registers_;
700 i += kRegistersPerPage) {
701 __ movq(register_location(i), rax); // One write every page.
702 }
703
704 // Initialize backtrack stack pointer.
705 __ movq(backtrack_stackpointer(), Operand(rbp, kStackHighEnd));
706 // Initialize code object pointer.
707 __ Move(code_object_pointer(), masm_->CodeObject());
708 // Load previous char as initial value of current-character.
709 Label at_start;
710 __ cmpq(Operand(rbp, kAtStart), Immediate(0));
711 __ j(not_equal, &at_start);
712 LoadCurrentCharacterUnchecked(-1, 1); // Load previous char.
713 __ jmp(&start_label_);
714 __ bind(&at_start);
715 __ movq(current_character(), Immediate('\n'));
716 __ jmp(&start_label_);
717
718
719 // Exit code:
720 if (success_label_.is_linked()) {
721 // Save captures when successful.
722 __ bind(&success_label_);
723 if (num_saved_registers_ > 0) {
724 // copy captures to output
725 __ movq(rbx, Operand(rbp, kRegisterOutput));
726 __ movq(rcx, Operand(rbp, kInputEnd));
727 __ subq(rcx, Operand(rbp, kInputStart));
728 for (int i = 0; i < num_saved_registers_; i++) {
729 __ movq(rax, register_location(i));
730 __ addq(rax, rcx); // Convert to index from start, not end.
731 if (mode_ == UC16) {
732 __ sar(rax, Immediate(1)); // Convert byte index to character index.
733 }
734 __ movl(Operand(rbx, i * kIntSize), rax);
735 }
736 }
737 __ movq(rax, Immediate(SUCCESS));
738 }
739
740 // Exit and return rax
741 __ bind(&exit_label_);
742
743 #ifdef __MSVC__
744 // Restore callee save registers.
745 __ lea(rsp, Operand(rbp, kLastCalleeSaveRegister));
746 __ pop(rbx);
747 __ pop(rdi);
748 __ pop(rsi);
749 // Stack now at rbp.
750 #else
751 // Restore callee save register.
752 __ movq(rbx, Operand(rbp, kBackup_rbx));
753 // Skip rsp to rbp.
754 __ movq(rsp, rbp);
755 #endif
756 // Exit function frame, restore previous one.
757 __ pop(rbp);
758 __ ret(0);
759
760 // Backtrack code (branch target for conditional backtracks).
761 if (backtrack_label_.is_linked()) {
762 __ bind(&backtrack_label_);
763 Backtrack();
764 }
765
766 Label exit_with_exception;
767
768 // Preempt-code
769 if (check_preempt_label_.is_linked()) {
770 SafeCallTarget(&check_preempt_label_);
771
772 __ push(backtrack_stackpointer());
773 __ push(rdi);
774
775 CallCheckStackGuardState();
776 __ testq(rax, rax);
777 // If returning non-zero, we should end execution with the given
778 // result as return value.
779 __ j(not_zero, &exit_label_);
780
781 // Restore registers.
782 __ Move(code_object_pointer(), masm_->CodeObject());
783 __ pop(rdi);
784 __ pop(backtrack_stackpointer());
785 // String might have moved: Reload esi from frame.
786 __ movq(rsi, Operand(rbp, kInputEnd));
787 SafeReturn();
788 }
789
790 // Backtrack stack overflow code.
791 if (stack_overflow_label_.is_linked()) {
792 SafeCallTarget(&stack_overflow_label_);
793 // Reached if the backtrack-stack limit has been hit.
794
795 Label grow_failed;
796 // Save registers before calling C function
797 #ifndef __MSVC__
798 // Callee-save in Microsoft 64-bit ABI, but not in AMD64 ABI.
799 __ push(rsi);
800 __ push(rdi);
801 #endif
802
803 // Call GrowStack(backtrack_stackpointer())
804 int num_arguments = 2;
805 FrameAlign(num_arguments);
806 #ifdef __MSVC__
807 // Microsoft passes parameters in rcx, rdx.
808 // First argument, backtrack stackpointer, is already in rcx.
809 __ lea(rdx, Operand(rbp, kStackHighEnd)); // Second argument
810 #else
811 // AMD64 ABI passes paremeters in rdi, rsi.
812 __ movq(rdi, backtrack_stackpointer()); // First argument.
813 __ lea(rsi, Operand(rbp, kStackHighEnd)); // Second argument.
814 #endif
815 CallCFunction(FUNCTION_ADDR(&GrowStack), num_arguments);
816 // If return NULL, we have failed to grow the stack, and
817 // must exit with a stack-overflow exception.
818 __ testq(rax, rax);
819 __ j(equal, &exit_with_exception);
820 // Otherwise use return value as new stack pointer.
821 __ movq(backtrack_stackpointer(), rax);
822 // Restore saved registers and continue.
823 __ Move(code_object_pointer(), masm_->CodeObject());
824 #ifndef __MSVC__
825 __ pop(rdi);
826 __ pop(rsi);
827 #endif
828 SafeReturn();
829 }
830
831 if (exit_with_exception.is_linked()) {
832 // If any of the code above needed to exit with an exception.
833 __ bind(&exit_with_exception);
834 // Exit with Result EXCEPTION(-1) to signal thrown exception.
835 __ movq(rax, Immediate(EXCEPTION));
836 __ jmp(&exit_label_);
837 }
838
839 FixupCodeRelativePositions();
840
841 CodeDesc code_desc;
842 masm_->GetCode(&code_desc);
843 Handle<Code> code = Factory::NewCode(code_desc,
844 NULL,
845 Code::ComputeFlags(Code::REGEXP),
846 masm_->CodeObject());
847 LOG(RegExpCodeCreateEvent(*code, *source));
848 return Handle<Object>::cast(code);
849 }
850
851
852 void RegExpMacroAssemblerX64::GoTo(Label* to) {
853 BranchOrBacktrack(no_condition, to);
854 }
855
856
857 void RegExpMacroAssemblerX64::IfRegisterGE(int reg,
858 int comparand,
859 Label* if_ge) {
860 __ cmpq(register_location(reg), Immediate(comparand));
861 BranchOrBacktrack(greater_equal, if_ge);
862 }
863
864
865 void RegExpMacroAssemblerX64::IfRegisterLT(int reg,
866 int comparand,
867 Label* if_lt) {
868 __ cmpq(register_location(reg), Immediate(comparand));
869 BranchOrBacktrack(less, if_lt);
870 }
871
872
873 void RegExpMacroAssemblerX64::IfRegisterEqPos(int reg,
874 Label* if_eq) {
875 __ cmpq(rdi, register_location(reg));
876 BranchOrBacktrack(equal, if_eq);
877 }
878
879
880 RegExpMacroAssembler::IrregexpImplementation
881 RegExpMacroAssemblerX64::Implementation() {
882 return kX64Implementation;
883 }
884
885
886 void RegExpMacroAssemblerX64::LoadCurrentCharacter(int cp_offset,
887 Label* on_end_of_input,
888 bool check_bounds,
889 int characters) {
890 ASSERT(cp_offset >= -1); // ^ and \b can look behind one character.
891 ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works)
892 CheckPosition(cp_offset + characters - 1, on_end_of_input);
893 LoadCurrentCharacterUnchecked(cp_offset, characters);
894 }
895
896
897 void RegExpMacroAssemblerX64::PopCurrentPosition() {
898 Pop(rdi);
899 }
900
901
902 void RegExpMacroAssemblerX64::PopRegister(int register_index) {
903 Pop(rax);
904 __ movq(register_location(register_index), rax);
905 }
906
907
908 void RegExpMacroAssemblerX64::PushBacktrack(Label* label) {
909 Push(label);
910 CheckStackLimit();
911 }
912
913
914 void RegExpMacroAssemblerX64::PushCurrentPosition() {
915 Push(rdi);
916 }
917
918
919 void RegExpMacroAssemblerX64::PushRegister(int register_index,
920 StackCheckFlag check_stack_limit) {
921 __ movq(rax, register_location(register_index));
922 Push(rax);
923 if (check_stack_limit) CheckStackLimit();
924 }
925
926
927 void RegExpMacroAssemblerX64::ReadCurrentPositionFromRegister(int reg) {
928 __ movq(rdi, register_location(reg));
929 }
930
931
932 void RegExpMacroAssemblerX64::ReadStackPointerFromRegister(int reg) {
933 __ movq(backtrack_stackpointer(), register_location(reg));
934 __ addq(backtrack_stackpointer(), Operand(rbp, kStackHighEnd));
935 }
936
937
938 void RegExpMacroAssemblerX64::SetRegister(int register_index, int to) {
939 ASSERT(register_index >= num_saved_registers_); // Reserved for positions!
940 __ movq(register_location(register_index), Immediate(to));
941 }
942
943
944 void RegExpMacroAssemblerX64::Succeed() {
945 __ jmp(&success_label_);
946 }
947
948
949 void RegExpMacroAssemblerX64::WriteCurrentPositionToRegister(int reg,
950 int cp_offset) {
951 if (cp_offset == 0) {
952 __ movq(register_location(reg), rdi);
953 } else {
954 __ lea(rax, Operand(rdi, cp_offset * char_size()));
955 __ movq(register_location(reg), rax);
956 }
957 }
958
959
960 void RegExpMacroAssemblerX64::ClearRegisters(int reg_from, int reg_to) {
961 ASSERT(reg_from <= reg_to);
962 __ movq(rax, Operand(rbp, kInputStartMinusOne));
963 for (int reg = reg_from; reg <= reg_to; reg++) {
964 __ movq(register_location(reg), rax);
965 }
966 }
967
968
969 void RegExpMacroAssemblerX64::WriteStackPointerToRegister(int reg) {
970 __ movq(rax, backtrack_stackpointer());
971 __ subq(rax, Operand(rbp, kStackHighEnd));
972 __ movq(register_location(reg), rax);
973 }
974
975
976 // Private methods:
977
978 void RegExpMacroAssemblerX64::CallCheckStackGuardState() {
979 // This function call preserves no register values. Caller should
980 // store anything volatile in a C call or overwritten by this function.
981 int num_arguments = 3;
982 FrameAlign(num_arguments);
983 #ifdef __MSVC__
984 // Second argument: Code* of self. (Do this before overwriting r8).
985 __ movq(rdx, code_object_pointer());
986 // Third argument: RegExp code frame pointer.
987 __ movq(r8, rbp);
988 // First argument: Next address on the stack (will be address of
989 // return address).
990 __ lea(rcx, Operand(rsp, -kPointerSize));
991 #else
992 // Third argument: RegExp code frame pointer.
993 __ movq(rdx, rbp);
994 // Second argument: Code* of self.
995 __ movq(rsi, code_object_pointer());
996 // First argument: Next address on the stack (will be address of
997 // return address).
998 __ lea(rdi, Operand(rsp, -kPointerSize));
999 #endif
1000 CallCFunction(FUNCTION_ADDR(&CheckStackGuardState), num_arguments);
1001 }
1002
1003
1004 // Helper function for reading a value out of a stack frame.
1005 template <typename T>
1006 static T& frame_entry(Address re_frame, int frame_offset) {
1007 return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset));
1008 }
1009
1010
1011 int RegExpMacroAssemblerX64::CheckStackGuardState(Address* return_address,
1012 Code* re_code,
1013 Address re_frame) {
1014 if (StackGuard::IsStackOverflow()) {
1015 Top::StackOverflow();
1016 return EXCEPTION;
1017 }
1018
1019 // If not real stack overflow the stack guard was used to interrupt
1020 // execution for another purpose.
1021
1022 // Prepare for possible GC.
1023 HandleScope handles;
1024 Handle<Code> code_handle(re_code);
1025
1026 Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
1027 // Current string.
1028 bool is_ascii = subject->IsAsciiRepresentation();
1029
1030 ASSERT(re_code->instruction_start() <= *return_address);
1031 ASSERT(*return_address <=
1032 re_code->instruction_start() + re_code->instruction_size());
1033
1034 Object* result = Execution::HandleStackGuardInterrupt();
1035
1036 if (*code_handle != re_code) { // Return address no longer valid
1037 intptr_t delta = *code_handle - re_code;
1038 // Overwrite the return address on the stack.
1039 *return_address += delta;
1040 }
1041
1042 if (result->IsException()) {
1043 return EXCEPTION;
1044 }
1045
1046 // String might have changed.
1047 if (subject->IsAsciiRepresentation() != is_ascii) {
1048 // If we changed between an ASCII and an UC16 string, the specialized
1049 // code cannot be used, and we need to restart regexp matching from
1050 // scratch (including, potentially, compiling a new version of the code).
1051 return RETRY;
1052 }
1053
1054 // Otherwise, the content of the string might have moved. It must still
1055 // be a sequential or external string with the same content.
1056 // Update the start and end pointers in the stack frame to the current
1057 // location (whether it has actually moved or not).
1058 ASSERT(StringShape(*subject).IsSequential() ||
1059 StringShape(*subject).IsExternal());
1060
1061 // The original start address of the characters to match.
1062 const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
1063
1064 // Find the current start address of the same character at the current string
1065 // position.
1066 int start_index = frame_entry<int>(re_frame, kStartIndex);
1067 const byte* new_address = StringCharacterPosition(*subject, start_index);
1068
1069 if (start_address != new_address) {
1070 // If there is a difference, update the object pointer and start and end
1071 // addresses in the RegExp stack frame to match the new value.
1072 const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
1073 int byte_length = end_address - start_address;
1074 frame_entry<const String*>(re_frame, kInputString) = *subject;
1075 frame_entry<const byte*>(re_frame, kInputStart) = new_address;
1076 frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
1077 }
1078
1079 return 0;
1080 }
1081
1082
1083 Address RegExpMacroAssemblerX64::GrowStack(Address stack_pointer,
1084 Address* stack_base) {
1085 size_t size = RegExpStack::stack_capacity();
1086 Address old_stack_base = RegExpStack::stack_base();
1087 ASSERT(old_stack_base == *stack_base);
1088 ASSERT(stack_pointer <= old_stack_base);
1089 ASSERT(static_cast<size_t>(old_stack_base - stack_pointer) <= size);
1090 Address new_stack_base = RegExpStack::EnsureCapacity(size * 2);
1091 if (new_stack_base == NULL) {
1092 return NULL;
1093 }
1094 *stack_base = new_stack_base;
1095 intptr_t stack_content_size = old_stack_base - stack_pointer;
1096 return new_stack_base - stack_content_size;
1097 }
1098
1099
1100 Operand RegExpMacroAssemblerX64::register_location(int register_index) {
1101 ASSERT(register_index < (1<<30));
1102 if (num_registers_ <= register_index) {
1103 num_registers_ = register_index + 1;
1104 }
1105 return Operand(rbp, kRegisterZero - register_index * kPointerSize);
1106 }
1107
1108
1109 void RegExpMacroAssemblerX64::CheckPosition(int cp_offset,
1110 Label* on_outside_input) {
1111 __ cmpl(rdi, Immediate(-cp_offset * char_size()));
1112 BranchOrBacktrack(greater_equal, on_outside_input);
1113 }
1114
1115
1116 void RegExpMacroAssemblerX64::BranchOrBacktrack(Condition condition,
1117 Label* to) {
1118 if (condition < 0) { // No condition
1119 if (to == NULL) {
1120 Backtrack();
1121 return;
1122 }
1123 __ jmp(to);
1124 return;
1125 }
1126 if (to == NULL) {
1127 __ j(condition, &backtrack_label_);
1128 return;
1129 }
1130 __ j(condition, to);
1131 }
1132
1133
1134 void RegExpMacroAssemblerX64::SafeCall(Label* to) {
1135 __ call(to);
1136 }
1137
1138
1139 void RegExpMacroAssemblerX64::SafeCallTarget(Label* label) {
1140 __ bind(label);
1141 __ subq(Operand(rsp, 0), code_object_pointer());
1142 }
1143
1144
1145 void RegExpMacroAssemblerX64::SafeReturn() {
1146 __ addq(Operand(rsp, 0), code_object_pointer());
1147 __ ret(0);
1148 }
1149
1150
1151 void RegExpMacroAssemblerX64::Push(Register source) {
1152 ASSERT(!source.is(backtrack_stackpointer()));
1153 // Notice: This updates flags, unlike normal Push.
1154 __ subq(backtrack_stackpointer(), Immediate(kIntSize));
1155 __ movl(Operand(backtrack_stackpointer(), 0), source);
1156 }
1157
1158
1159 void RegExpMacroAssemblerX64::Push(Immediate value) {
1160 // Notice: This updates flags, unlike normal Push.
1161 __ subq(backtrack_stackpointer(), Immediate(kIntSize));
1162 __ movl(Operand(backtrack_stackpointer(), 0), value);
1163 }
1164
1165
1166 void RegExpMacroAssemblerX64::FixupCodeRelativePositions() {
1167 for (int i = 0, n = code_relative_fixup_positions_.length(); i < n; i++) {
1168 int position = code_relative_fixup_positions_[i];
1169 // The position succeeds a relative label offset from position.
1170 // Patch the relative offset to be relative to the Code object pointer
1171 // instead.
1172 int patch_position = position - kIntSize;
1173 int offset = masm_->long_at(patch_position);
1174 masm_->long_at_put(patch_position,
1175 offset
1176 + position
1177 + Code::kHeaderSize
1178 - kHeapObjectTag);
1179 }
1180 code_relative_fixup_positions_.Clear();
1181 }
1182
1183
1184 void RegExpMacroAssemblerX64::Push(Label* backtrack_target) {
1185 __ subq(backtrack_stackpointer(), Immediate(kIntSize));
1186 __ movl(Operand(backtrack_stackpointer(), 0), backtrack_target);
1187 MarkPositionForCodeRelativeFixup();
1188 }
1189
1190
1191 void RegExpMacroAssemblerX64::Pop(Register target) {
1192 ASSERT(!target.is(backtrack_stackpointer()));
1193 __ movsxlq(target, Operand(backtrack_stackpointer(), 0));
1194 // Notice: This updates flags, unlike normal Pop.
1195 __ addq(backtrack_stackpointer(), Immediate(kIntSize));
1196 }
1197
1198
1199 void RegExpMacroAssemblerX64::Drop() {
1200 __ addq(backtrack_stackpointer(), Immediate(kIntSize));
1201 }
1202
1203
1204 void RegExpMacroAssemblerX64::CheckPreemption() {
1205 // Check for preemption.
1206 Label no_preempt;
1207 ExternalReference stack_guard_limit =
1208 ExternalReference::address_of_stack_guard_limit();
1209 __ load_rax(stack_guard_limit);
1210 __ cmpq(rsp, rax);
1211 __ j(above, &no_preempt);
1212
1213 SafeCall(&check_preempt_label_);
1214
1215 __ bind(&no_preempt);
1216 }
1217
1218
1219 void RegExpMacroAssemblerX64::CheckStackLimit() {
1220 if (FLAG_check_stack) {
1221 Label no_stack_overflow;
1222 ExternalReference stack_limit =
1223 ExternalReference::address_of_regexp_stack_limit();
1224 __ load_rax(stack_limit);
1225 __ cmpq(backtrack_stackpointer(), rax);
1226 __ j(above, &no_stack_overflow);
1227
1228 SafeCall(&stack_overflow_label_);
1229
1230 __ bind(&no_stack_overflow);
1231 }
1232 }
1233
1234
1235 void RegExpMacroAssemblerX64::FrameAlign(int num_arguments) {
1236 // TODO(lrn): Since we no longer use the system stack arbitrarily (but we do
1237 // use it, e.g., for SafeCall), we know the number of elements on the stack
1238 // since the last frame alignment. We might be able to do this simpler then.
1239 int frameAlignment = OS::ActivationFrameAlignment();
1240 ASSERT(frameAlignment != 0);
1241 // Make stack end at alignment and make room for num_arguments pointers
1242 // (on Win64 only) and the original value of rsp.
1243 __ movq(kScratchRegister, rsp);
1244 ASSERT(IsPowerOf2(frameAlignment));
1245 #ifdef __MSVC__
1246 // Allocate space for parameters and old rsp.
1247 __ subq(rsp, Immediate((num_arguments + 1) * kPointerSize));
1248 __ and_(rsp, -frameAlignment);
1249 __ movq(Operand(rsp, num_arguments * kPointerSize), kScratchRegister);
1250 #else
1251 // Allocate space for old rsp.
1252 __ subq(rsp, Immediate(kPointerSize));
1253 __ and_(rsp, Immediate(-frameAlignment));
1254 __ movq(Operand(rsp, 0), kScratchRegister);
1255 #endif
1256 }
1257
1258
1259 void RegExpMacroAssemblerX64::CallCFunction(Address function_address,
1260 int num_arguments) {
1261 // Don't compile regexps with serialization enabled. The addresses of the C++
1262 // function being called isn't relocatable.
1263 ASSERT(!Serializer::enabled());
1264 __ movq(rax, reinterpret_cast<intptr_t>(function_address), RelocInfo::NONE);
1265 __ call(rax);
1266 ASSERT(OS::ActivationFrameAlignment() != 0);
1267 #ifdef __MSVC__
1268 __ movq(rsp, Operand(rsp, num_arguments * kPointerSize));
1269 #else
1270 __ pop(rsp);
1271 #endif
1272 }
1273
1274
1275 void RegExpMacroAssemblerX64::LoadCurrentCharacterUnchecked(int cp_offset,
1276 int characters) {
1277 if (mode_ == ASCII) {
1278 if (characters == 4) {
1279 __ movl(current_character(), Operand(rsi, rdi, times_1, cp_offset));
1280 } else if (characters == 2) {
1281 __ movzxwl(current_character(), Operand(rsi, rdi, times_1, cp_offset));
1282 } else {
1283 ASSERT(characters == 1);
1284 __ movzxbl(current_character(), Operand(rsi, rdi, times_1, cp_offset));
1285 }
1286 } else {
1287 ASSERT(mode_ == UC16);
1288 if (characters == 2) {
1289 __ movl(current_character(),
1290 Operand(rsi, rdi, times_1, cp_offset * sizeof(uc16)));
1291 } else {
1292 ASSERT(characters == 1);
1293 __ movzxwl(current_character(),
1294 Operand(rsi, rdi, times_1, cp_offset * sizeof(uc16)));
1295 }
1296 }
1297 }
1298
1299
1300 #undef __
1301 }} // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698