blob: 269e7afac8e0a0a43e6e770fe454ab95267d53b6 [file] [log] [blame]
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +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
28#include "v8.h"
Leon Clarkef7060e22010-06-03 12:02:55 +010029
30#if defined(V8_TARGET_ARCH_X64)
31
Steve Blocka7e24c12009-10-30 11:49:00 +000032#include "serialize.h"
33#include "unicode.h"
34#include "log.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000035#include "regexp-stack.h"
36#include "macro-assembler.h"
37#include "regexp-macro-assembler.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000038#include "x64/regexp-macro-assembler-x64.h"
39
40namespace v8 {
41namespace internal {
42
Steve Block6ded16b2010-05-10 14:33:55 +010043#ifndef V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +000044
45/*
46 * This assembler uses the following register assignment convention
47 * - rdx : currently loaded character(s) as ASCII or UC16. Must be loaded using
48 * LoadCurrentCharacter before using any of the dispatch methods.
49 * - rdi : current position in input, as negative offset from end of string.
50 * Please notice that this is the byte offset, not the character
51 * offset! Is always a 32-bit signed (negative) offset, but must be
52 * maintained sign-extended to 64 bits, since it is used as index.
53 * - rsi : end of input (points to byte after last character in input),
54 * so that rsi+rdi points to the current character.
55 * - rbp : frame pointer. Used to access arguments, local variables and
56 * RegExp registers.
57 * - rsp : points to tip of C stack.
58 * - rcx : points to tip of backtrack stack. The backtrack stack contains
59 * only 32-bit values. Most are offsets from some base (e.g., character
60 * positions from end of string or code location from Code* pointer).
61 * - r8 : code object pointer. Used to convert between absolute and
62 * code-object-relative addresses.
63 *
Leon Clarkee46be812010-01-19 14:06:41 +000064 * The registers rax, rbx, r9 and r11 are free to use for computations.
Steve Blocka7e24c12009-10-30 11:49:00 +000065 * If changed to use r12+, they should be saved as callee-save registers.
Steve Block44f0eee2011-05-26 01:26:41 +010066 * The macro assembler special registers r12 and r13 (kSmiConstantRegister,
67 * kRootRegister) aren't special during execution of RegExp code (they don't
68 * hold the values assumed when creating JS code), so no Smi or Root related
69 * macro operations can be used.
Steve Blocka7e24c12009-10-30 11:49:00 +000070 *
71 * Each call to a C++ method should retain these registers.
72 *
73 * The stack will have the following content, in some order, indexable from the
74 * frame pointer (see, e.g., kStackHighEnd):
Steve Block44f0eee2011-05-26 01:26:41 +010075 * - Isolate* isolate (Address of the current isolate)
Leon Clarkee46be812010-01-19 14:06:41 +000076 * - direct_call (if 1, direct call from JavaScript code, if 0 call
77 * through the runtime system)
78 * - stack_area_base (High end of the memory area to use as
79 * backtracking stack)
Leon Clarkee46be812010-01-19 14:06:41 +000080 * - int* capture_array (int[num_saved_registers_], for output).
81 * - end of input (Address of end of string)
82 * - start of input (Address of first character in string)
83 * - start index (character index of start)
84 * - String* input_string (input string)
Steve Blocka7e24c12009-10-30 11:49:00 +000085 * - return address
86 * - backup of callee save registers (rbx, possibly rsi and rdi).
87 * - Offset of location before start of input (effectively character
88 * position -1). Used to initialize capture registers to a non-position.
Leon Clarked91b9f72010-01-27 17:25:45 +000089 * - At start of string (if 1, we are starting at the start of the
90 * string, otherwise 0)
Steve Blocka7e24c12009-10-30 11:49:00 +000091 * - register 0 rbp[-n] (Only positions must be stored in the first
92 * - register 1 rbp[-n-8] num_saved_registers_ registers)
93 * - ...
94 *
95 * The first num_saved_registers_ registers are initialized to point to
96 * "character -1" in the string (i.e., char_size() bytes before the first
97 * character of the string). The remaining registers starts out uninitialized.
98 *
99 * The first seven values must be provided by the calling code by
100 * calling the code's entry address cast to a function pointer with the
101 * following signature:
102 * int (*match)(String* input_string,
Leon Clarkee46be812010-01-19 14:06:41 +0000103 * int start_index,
Steve Blocka7e24c12009-10-30 11:49:00 +0000104 * Address start,
105 * Address end,
106 * int* capture_output_array,
107 * bool at_start,
Leon Clarkee46be812010-01-19 14:06:41 +0000108 * byte* stack_area_base,
109 * bool direct_call)
Steve Blocka7e24c12009-10-30 11:49:00 +0000110 */
111
Steve Block44f0eee2011-05-26 01:26:41 +0100112#define __ ACCESS_MASM((&masm_))
Steve Blocka7e24c12009-10-30 11:49:00 +0000113
114RegExpMacroAssemblerX64::RegExpMacroAssemblerX64(
115 Mode mode,
116 int registers_to_save)
Steve Block44f0eee2011-05-26 01:26:41 +0100117 : masm_(NULL, kRegExpCodeSize),
118 no_root_array_scope_(&masm_),
Steve Blocka7e24c12009-10-30 11:49:00 +0000119 code_relative_fixup_positions_(4),
120 mode_(mode),
121 num_registers_(registers_to_save),
122 num_saved_registers_(registers_to_save),
123 entry_label_(),
124 start_label_(),
125 success_label_(),
126 backtrack_label_(),
127 exit_label_() {
128 ASSERT_EQ(0, registers_to_save % 2);
129 __ jmp(&entry_label_); // We'll write the entry code when we know more.
130 __ bind(&start_label_); // And then continue from here.
131}
132
133
134RegExpMacroAssemblerX64::~RegExpMacroAssemblerX64() {
Steve Blocka7e24c12009-10-30 11:49:00 +0000135 // Unuse labels in case we throw away the assembler without calling GetCode.
136 entry_label_.Unuse();
137 start_label_.Unuse();
138 success_label_.Unuse();
139 backtrack_label_.Unuse();
140 exit_label_.Unuse();
141 check_preempt_label_.Unuse();
142 stack_overflow_label_.Unuse();
143}
144
145
146int RegExpMacroAssemblerX64::stack_limit_slack() {
147 return RegExpStack::kStackLimitSlack;
148}
149
150
151void RegExpMacroAssemblerX64::AdvanceCurrentPosition(int by) {
152 if (by != 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000153 __ addq(rdi, Immediate(by * char_size()));
154 }
155}
156
157
158void RegExpMacroAssemblerX64::AdvanceRegister(int reg, int by) {
159 ASSERT(reg >= 0);
160 ASSERT(reg < num_registers_);
161 if (by != 0) {
162 __ addq(register_location(reg), Immediate(by));
163 }
164}
165
166
167void RegExpMacroAssemblerX64::Backtrack() {
168 CheckPreemption();
169 // Pop Code* offset from backtrack stack, add Code* and jump to location.
170 Pop(rbx);
171 __ addq(rbx, code_object_pointer());
172 __ jmp(rbx);
173}
174
175
176void RegExpMacroAssemblerX64::Bind(Label* label) {
177 __ bind(label);
178}
179
180
181void RegExpMacroAssemblerX64::CheckCharacter(uint32_t c, Label* on_equal) {
182 __ cmpl(current_character(), Immediate(c));
183 BranchOrBacktrack(equal, on_equal);
184}
185
186
187void RegExpMacroAssemblerX64::CheckCharacterGT(uc16 limit, Label* on_greater) {
188 __ cmpl(current_character(), Immediate(limit));
189 BranchOrBacktrack(greater, on_greater);
190}
191
192
193void RegExpMacroAssemblerX64::CheckAtStart(Label* on_at_start) {
194 Label not_at_start;
195 // Did we start the match at the start of the string at all?
Kristian Monsen25f61362010-05-21 11:50:48 +0100196 __ cmpb(Operand(rbp, kStartIndex), Immediate(0));
197 BranchOrBacktrack(not_equal, &not_at_start);
Steve Blocka7e24c12009-10-30 11:49:00 +0000198 // If we did, are we still at the start of the input?
199 __ lea(rax, Operand(rsi, rdi, times_1, 0));
200 __ cmpq(rax, Operand(rbp, kInputStart));
201 BranchOrBacktrack(equal, on_at_start);
202 __ bind(&not_at_start);
203}
204
205
206void RegExpMacroAssemblerX64::CheckNotAtStart(Label* on_not_at_start) {
207 // Did we start the match at the start of the string at all?
Kristian Monsen25f61362010-05-21 11:50:48 +0100208 __ cmpb(Operand(rbp, kStartIndex), Immediate(0));
209 BranchOrBacktrack(not_equal, on_not_at_start);
Steve Blocka7e24c12009-10-30 11:49:00 +0000210 // If we did, are we still at the start of the input?
211 __ lea(rax, Operand(rsi, rdi, times_1, 0));
212 __ cmpq(rax, Operand(rbp, kInputStart));
213 BranchOrBacktrack(not_equal, on_not_at_start);
214}
215
216
217void RegExpMacroAssemblerX64::CheckCharacterLT(uc16 limit, Label* on_less) {
218 __ cmpl(current_character(), Immediate(limit));
219 BranchOrBacktrack(less, on_less);
220}
221
222
223void RegExpMacroAssemblerX64::CheckCharacters(Vector<const uc16> str,
224 int cp_offset,
225 Label* on_failure,
226 bool check_end_of_string) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100227#ifdef DEBUG
228 // If input is ASCII, don't even bother calling here if the string to
229 // match contains a non-ascii character.
230 if (mode_ == ASCII) {
Steve Block9fac8402011-05-12 15:51:54 +0100231 ASSERT(String::IsAscii(str.start(), str.length()));
Kristian Monsen25f61362010-05-21 11:50:48 +0100232 }
233#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000234 int byte_length = str.length() * char_size();
235 int byte_offset = cp_offset * char_size();
236 if (check_end_of_string) {
237 // Check that there are at least str.length() characters left in the input.
238 __ cmpl(rdi, Immediate(-(byte_offset + byte_length)));
239 BranchOrBacktrack(greater, on_failure);
240 }
241
242 if (on_failure == NULL) {
243 // Instead of inlining a backtrack, (re)use the global backtrack target.
244 on_failure = &backtrack_label_;
245 }
246
Kristian Monsen25f61362010-05-21 11:50:48 +0100247 // Do one character test first to minimize loading for the case that
248 // we don't match at all (loading more than one character introduces that
249 // chance of reading unaligned and reading across cache boundaries).
250 // If the first character matches, expect a larger chance of matching the
251 // string, and start loading more characters at a time.
252 if (mode_ == ASCII) {
253 __ cmpb(Operand(rsi, rdi, times_1, byte_offset),
254 Immediate(static_cast<int8_t>(str[0])));
255 } else {
256 // Don't use 16-bit immediate. The size changing prefix throws off
257 // pre-decoding.
258 __ movzxwl(rax,
259 Operand(rsi, rdi, times_1, byte_offset));
260 __ cmpl(rax, Immediate(static_cast<int32_t>(str[0])));
261 }
262 BranchOrBacktrack(not_equal, on_failure);
263
264 __ lea(rbx, Operand(rsi, rdi, times_1, 0));
265 for (int i = 1, n = str.length(); i < n; ) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000266 if (mode_ == ASCII) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100267 if (i + 8 <= n) {
268 uint64_t combined_chars =
269 (static_cast<uint64_t>(str[i + 0]) << 0) ||
270 (static_cast<uint64_t>(str[i + 1]) << 8) ||
271 (static_cast<uint64_t>(str[i + 2]) << 16) ||
272 (static_cast<uint64_t>(str[i + 3]) << 24) ||
273 (static_cast<uint64_t>(str[i + 4]) << 32) ||
274 (static_cast<uint64_t>(str[i + 5]) << 40) ||
275 (static_cast<uint64_t>(str[i + 6]) << 48) ||
276 (static_cast<uint64_t>(str[i + 7]) << 56);
277 __ movq(rax, combined_chars, RelocInfo::NONE);
278 __ cmpq(rax, Operand(rbx, byte_offset + i));
279 i += 8;
280 } else if (i + 4 <= n) {
281 uint32_t combined_chars =
282 (static_cast<uint32_t>(str[i + 0]) << 0) ||
283 (static_cast<uint32_t>(str[i + 1]) << 8) ||
284 (static_cast<uint32_t>(str[i + 2]) << 16) ||
285 (static_cast<uint32_t>(str[i + 3]) << 24);
286 __ cmpl(Operand(rbx, byte_offset + i), Immediate(combined_chars));
287 i += 4;
288 } else {
289 __ cmpb(Operand(rbx, byte_offset + i),
290 Immediate(static_cast<int8_t>(str[i])));
291 i++;
292 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000293 } else {
294 ASSERT(mode_ == UC16);
Kristian Monsen25f61362010-05-21 11:50:48 +0100295 if (i + 4 <= n) {
296 uint64_t combined_chars = *reinterpret_cast<const uint64_t*>(&str[i]);
297 __ movq(rax, combined_chars, RelocInfo::NONE);
298 __ cmpq(rax,
299 Operand(rsi, rdi, times_1, byte_offset + i * sizeof(uc16)));
300 i += 4;
301 } else if (i + 2 <= n) {
302 uint32_t combined_chars = *reinterpret_cast<const uint32_t*>(&str[i]);
303 __ cmpl(Operand(rsi, rdi, times_1, byte_offset + i * sizeof(uc16)),
304 Immediate(combined_chars));
305 i += 2;
306 } else {
307 __ movzxwl(rax,
308 Operand(rsi, rdi, times_1, byte_offset + i * sizeof(uc16)));
309 __ cmpl(rax, Immediate(str[i]));
310 i++;
311 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000312 }
313 BranchOrBacktrack(not_equal, on_failure);
314 }
315}
316
317
318void RegExpMacroAssemblerX64::CheckGreedyLoop(Label* on_equal) {
319 Label fallthrough;
320 __ cmpl(rdi, Operand(backtrack_stackpointer(), 0));
321 __ j(not_equal, &fallthrough);
322 Drop();
323 BranchOrBacktrack(no_condition, on_equal);
324 __ bind(&fallthrough);
325}
326
327
328void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase(
329 int start_reg,
330 Label* on_no_match) {
331 Label fallthrough;
332 __ movq(rdx, register_location(start_reg)); // Offset of start of capture
333 __ movq(rbx, register_location(start_reg + 1)); // Offset of end of capture
334 __ subq(rbx, rdx); // Length of capture.
335
336 // -----------------------
337 // rdx = Start offset of capture.
338 // rbx = Length of capture
339
340 // If length is negative, this code will fail (it's a symptom of a partial or
341 // illegal capture where start of capture after end of capture).
342 // This must not happen (no back-reference can reference a capture that wasn't
343 // closed before in the reg-exp, and we must not generate code that can cause
344 // this condition).
345
346 // If length is zero, either the capture is empty or it is nonparticipating.
347 // In either case succeed immediately.
348 __ j(equal, &fallthrough);
349
350 if (mode_ == ASCII) {
351 Label loop_increment;
352 if (on_no_match == NULL) {
353 on_no_match = &backtrack_label_;
354 }
355
356 __ lea(r9, Operand(rsi, rdx, times_1, 0));
357 __ lea(r11, Operand(rsi, rdi, times_1, 0));
358 __ addq(rbx, r9); // End of capture
359 // ---------------------
360 // r11 - current input character address
361 // r9 - current capture character address
362 // rbx - end of capture
363
364 Label loop;
365 __ bind(&loop);
366 __ movzxbl(rdx, Operand(r9, 0));
367 __ movzxbl(rax, Operand(r11, 0));
368 // al - input character
369 // dl - capture character
370 __ cmpb(rax, rdx);
371 __ j(equal, &loop_increment);
372
373 // Mismatch, try case-insensitive match (converting letters to lower-case).
374 // I.e., if or-ing with 0x20 makes values equal and in range 'a'-'z', it's
375 // a match.
376 __ or_(rax, Immediate(0x20)); // Convert match character to lower-case.
377 __ or_(rdx, Immediate(0x20)); // Convert capture character to lower-case.
378 __ cmpb(rax, rdx);
379 __ j(not_equal, on_no_match); // Definitely not equal.
380 __ subb(rax, Immediate('a'));
381 __ cmpb(rax, Immediate('z' - 'a'));
382 __ j(above, on_no_match); // Weren't letters anyway.
383
384 __ bind(&loop_increment);
385 // Increment pointers into match and capture strings.
386 __ addq(r11, Immediate(1));
387 __ addq(r9, Immediate(1));
388 // Compare to end of capture, and loop if not done.
389 __ cmpq(r9, rbx);
390 __ j(below, &loop);
391
392 // Compute new value of character position after the matched part.
393 __ movq(rdi, r11);
394 __ subq(rdi, rsi);
395 } else {
396 ASSERT(mode_ == UC16);
397 // Save important/volatile registers before calling C function.
398#ifndef _WIN64
Leon Clarke4515c472010-02-03 11:58:03 +0000399 // Caller save on Linux and callee save in Windows.
Steve Blocka7e24c12009-10-30 11:49:00 +0000400 __ push(rsi);
401 __ push(rdi);
402#endif
403 __ push(backtrack_stackpointer());
404
Steve Block6ded16b2010-05-10 14:33:55 +0100405 static const int num_arguments = 3;
Leon Clarke4515c472010-02-03 11:58:03 +0000406 __ PrepareCallCFunction(num_arguments);
Steve Blocka7e24c12009-10-30 11:49:00 +0000407
408 // Put arguments into parameter registers. Parameters are
409 // Address byte_offset1 - Address captured substring's start.
410 // Address byte_offset2 - Address of current character position.
411 // size_t byte_length - length of capture in bytes(!)
412#ifdef _WIN64
413 // Compute and set byte_offset1 (start of capture).
414 __ lea(rcx, Operand(rsi, rdx, times_1, 0));
415 // Set byte_offset2.
416 __ lea(rdx, Operand(rsi, rdi, times_1, 0));
417 // Set byte_length.
418 __ movq(r8, rbx);
419#else // AMD64 calling convention
420 // Compute byte_offset2 (current position = rsi+rdi).
421 __ lea(rax, Operand(rsi, rdi, times_1, 0));
422 // Compute and set byte_offset1 (start of capture).
423 __ lea(rdi, Operand(rsi, rdx, times_1, 0));
424 // Set byte_offset2.
425 __ movq(rsi, rax);
426 // Set byte_length.
427 __ movq(rdx, rbx);
428#endif
429 ExternalReference compare =
Steve Block44f0eee2011-05-26 01:26:41 +0100430 ExternalReference::re_case_insensitive_compare_uc16(masm_.isolate());
Leon Clarke4515c472010-02-03 11:58:03 +0000431 __ CallCFunction(compare, num_arguments);
Steve Blocka7e24c12009-10-30 11:49:00 +0000432
433 // Restore original values before reacting on result value.
Steve Block44f0eee2011-05-26 01:26:41 +0100434 __ Move(code_object_pointer(), masm_.CodeObject());
Steve Blocka7e24c12009-10-30 11:49:00 +0000435 __ pop(backtrack_stackpointer());
436#ifndef _WIN64
437 __ pop(rdi);
438 __ pop(rsi);
439#endif
440
441 // Check if function returned non-zero for success or zero for failure.
442 __ testq(rax, rax);
443 BranchOrBacktrack(zero, on_no_match);
444 // On success, increment position by length of capture.
445 // Requires that rbx is callee save (true for both Win64 and AMD64 ABIs).
446 __ addq(rdi, rbx);
447 }
448 __ bind(&fallthrough);
449}
450
451
452void RegExpMacroAssemblerX64::CheckNotBackReference(
453 int start_reg,
454 Label* on_no_match) {
455 Label fallthrough;
456
457 // Find length of back-referenced capture.
458 __ movq(rdx, register_location(start_reg));
459 __ movq(rax, register_location(start_reg + 1));
460 __ subq(rax, rdx); // Length to check.
461
462 // Fail on partial or illegal capture (start of capture after end of capture).
463 // This must not happen (no back-reference can reference a capture that wasn't
464 // closed before in the reg-exp).
465 __ Check(greater_equal, "Invalid capture referenced");
466
467 // Succeed on empty capture (including non-participating capture)
468 __ j(equal, &fallthrough);
469
470 // -----------------------
471 // rdx - Start of capture
472 // rax - length of capture
473
474 // Check that there are sufficient characters left in the input.
475 __ movl(rbx, rdi);
476 __ addl(rbx, rax);
477 BranchOrBacktrack(greater, on_no_match);
478
479 // Compute pointers to match string and capture string
480 __ lea(rbx, Operand(rsi, rdi, times_1, 0)); // Start of match.
481 __ addq(rdx, rsi); // Start of capture.
482 __ lea(r9, Operand(rdx, rax, times_1, 0)); // End of capture
483
484 // -----------------------
485 // rbx - current capture character address.
486 // rbx - current input character address .
487 // r9 - end of input to match (capture length after rbx).
488
489 Label loop;
490 __ bind(&loop);
491 if (mode_ == ASCII) {
492 __ movzxbl(rax, Operand(rdx, 0));
493 __ cmpb(rax, Operand(rbx, 0));
494 } else {
495 ASSERT(mode_ == UC16);
496 __ movzxwl(rax, Operand(rdx, 0));
497 __ cmpw(rax, Operand(rbx, 0));
498 }
499 BranchOrBacktrack(not_equal, on_no_match);
500 // Increment pointers into capture and match string.
501 __ addq(rbx, Immediate(char_size()));
502 __ addq(rdx, Immediate(char_size()));
503 // Check if we have reached end of match area.
504 __ cmpq(rdx, r9);
505 __ j(below, &loop);
506
507 // Success.
508 // Set current character position to position after match.
509 __ movq(rdi, rbx);
510 __ subq(rdi, rsi);
511
512 __ bind(&fallthrough);
513}
514
515
516void RegExpMacroAssemblerX64::CheckNotRegistersEqual(int reg1,
517 int reg2,
518 Label* on_not_equal) {
519 __ movq(rax, register_location(reg1));
520 __ cmpq(rax, register_location(reg2));
521 BranchOrBacktrack(not_equal, on_not_equal);
522}
523
524
525void RegExpMacroAssemblerX64::CheckNotCharacter(uint32_t c,
526 Label* on_not_equal) {
527 __ cmpl(current_character(), Immediate(c));
528 BranchOrBacktrack(not_equal, on_not_equal);
529}
530
531
532void RegExpMacroAssemblerX64::CheckCharacterAfterAnd(uint32_t c,
533 uint32_t mask,
534 Label* on_equal) {
535 __ movl(rax, current_character());
536 __ and_(rax, Immediate(mask));
537 __ cmpl(rax, Immediate(c));
538 BranchOrBacktrack(equal, on_equal);
539}
540
541
542void RegExpMacroAssemblerX64::CheckNotCharacterAfterAnd(uint32_t c,
543 uint32_t mask,
544 Label* on_not_equal) {
545 __ movl(rax, current_character());
546 __ and_(rax, Immediate(mask));
547 __ cmpl(rax, Immediate(c));
548 BranchOrBacktrack(not_equal, on_not_equal);
549}
550
551
552void RegExpMacroAssemblerX64::CheckNotCharacterAfterMinusAnd(
553 uc16 c,
554 uc16 minus,
555 uc16 mask,
556 Label* on_not_equal) {
557 ASSERT(minus < String::kMaxUC16CharCode);
558 __ lea(rax, Operand(current_character(), -minus));
559 __ and_(rax, Immediate(mask));
560 __ cmpl(rax, Immediate(c));
561 BranchOrBacktrack(not_equal, on_not_equal);
562}
563
564
565bool RegExpMacroAssemblerX64::CheckSpecialCharacterClass(uc16 type,
Steve Blocka7e24c12009-10-30 11:49:00 +0000566 Label* on_no_match) {
567 // Range checks (c in min..max) are generally implemented by an unsigned
Leon Clarkee46be812010-01-19 14:06:41 +0000568 // (c - min) <= (max - min) check, using the sequence:
569 // lea(rax, Operand(current_character(), -min)) or sub(rax, Immediate(min))
570 // cmp(rax, Immediate(max - min))
Steve Blocka7e24c12009-10-30 11:49:00 +0000571 switch (type) {
572 case 's':
573 // Match space-characters
574 if (mode_ == ASCII) {
575 // ASCII space characters are '\t'..'\r' and ' '.
Steve Blocka7e24c12009-10-30 11:49:00 +0000576 Label success;
577 __ cmpl(current_character(), Immediate(' '));
578 __ j(equal, &success);
579 // Check range 0x09..0x0d
Leon Clarkee46be812010-01-19 14:06:41 +0000580 __ lea(rax, Operand(current_character(), -'\t'));
581 __ cmpl(rax, Immediate('\r' - '\t'));
Steve Blocka7e24c12009-10-30 11:49:00 +0000582 BranchOrBacktrack(above, on_no_match);
583 __ bind(&success);
584 return true;
585 }
586 return false;
587 case 'S':
588 // Match non-space characters.
Steve Blocka7e24c12009-10-30 11:49:00 +0000589 if (mode_ == ASCII) {
590 // ASCII space characters are '\t'..'\r' and ' '.
591 __ cmpl(current_character(), Immediate(' '));
592 BranchOrBacktrack(equal, on_no_match);
Leon Clarkee46be812010-01-19 14:06:41 +0000593 __ lea(rax, Operand(current_character(), -'\t'));
594 __ cmpl(rax, Immediate('\r' - '\t'));
Steve Blocka7e24c12009-10-30 11:49:00 +0000595 BranchOrBacktrack(below_equal, on_no_match);
596 return true;
597 }
598 return false;
599 case 'd':
600 // Match ASCII digits ('0'..'9')
Leon Clarkee46be812010-01-19 14:06:41 +0000601 __ lea(rax, Operand(current_character(), -'0'));
602 __ cmpl(rax, Immediate('9' - '0'));
Steve Blocka7e24c12009-10-30 11:49:00 +0000603 BranchOrBacktrack(above, on_no_match);
604 return true;
605 case 'D':
606 // Match non ASCII-digits
Leon Clarkee46be812010-01-19 14:06:41 +0000607 __ lea(rax, Operand(current_character(), -'0'));
608 __ cmpl(rax, Immediate('9' - '0'));
Steve Blocka7e24c12009-10-30 11:49:00 +0000609 BranchOrBacktrack(below_equal, on_no_match);
610 return true;
611 case '.': {
612 // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
Leon Clarkee46be812010-01-19 14:06:41 +0000613 __ movl(rax, current_character());
614 __ xor_(rax, Immediate(0x01));
Steve Blocka7e24c12009-10-30 11:49:00 +0000615 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
Leon Clarkee46be812010-01-19 14:06:41 +0000616 __ subl(rax, Immediate(0x0b));
617 __ cmpl(rax, Immediate(0x0c - 0x0b));
Steve Blocka7e24c12009-10-30 11:49:00 +0000618 BranchOrBacktrack(below_equal, on_no_match);
619 if (mode_ == UC16) {
620 // Compare original value to 0x2028 and 0x2029, using the already
621 // computed (current_char ^ 0x01 - 0x0b). I.e., check for
622 // 0x201d (0x2028 - 0x0b) or 0x201e.
Leon Clarkee46be812010-01-19 14:06:41 +0000623 __ subl(rax, Immediate(0x2028 - 0x0b));
624 __ cmpl(rax, Immediate(0x2029 - 0x2028));
Steve Blocka7e24c12009-10-30 11:49:00 +0000625 BranchOrBacktrack(below_equal, on_no_match);
626 }
627 return true;
628 }
Leon Clarkee46be812010-01-19 14:06:41 +0000629 case 'n': {
630 // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
631 __ movl(rax, current_character());
632 __ xor_(rax, Immediate(0x01));
633 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
634 __ subl(rax, Immediate(0x0b));
635 __ cmpl(rax, Immediate(0x0c - 0x0b));
636 if (mode_ == ASCII) {
637 BranchOrBacktrack(above, on_no_match);
638 } else {
639 Label done;
640 BranchOrBacktrack(below_equal, &done);
641 // Compare original value to 0x2028 and 0x2029, using the already
642 // computed (current_char ^ 0x01 - 0x0b). I.e., check for
643 // 0x201d (0x2028 - 0x0b) or 0x201e.
644 __ subl(rax, Immediate(0x2028 - 0x0b));
645 __ cmpl(rax, Immediate(0x2029 - 0x2028));
646 BranchOrBacktrack(above, on_no_match);
647 __ bind(&done);
Steve Blocka7e24c12009-10-30 11:49:00 +0000648 }
649 return true;
Leon Clarkee46be812010-01-19 14:06:41 +0000650 }
651 case 'w': {
652 if (mode_ != ASCII) {
653 // Table is 128 entries, so all ASCII characters can be tested.
654 __ cmpl(current_character(), Immediate('z'));
655 BranchOrBacktrack(above, on_no_match);
656 }
657 __ movq(rbx, ExternalReference::re_word_character_map());
658 ASSERT_EQ(0, word_character_map[0]); // Character '\0' is not a word char.
659 ExternalReference word_map = ExternalReference::re_word_character_map();
660 __ testb(Operand(rbx, current_character(), times_1, 0),
661 current_character());
662 BranchOrBacktrack(zero, on_no_match);
663 return true;
664 }
665 case 'W': {
666 Label done;
667 if (mode_ != ASCII) {
668 // Table is 128 entries, so all ASCII characters can be tested.
669 __ cmpl(current_character(), Immediate('z'));
670 __ j(above, &done);
671 }
672 __ movq(rbx, ExternalReference::re_word_character_map());
673 ASSERT_EQ(0, word_character_map[0]); // Character '\0' is not a word char.
674 ExternalReference word_map = ExternalReference::re_word_character_map();
675 __ testb(Operand(rbx, current_character(), times_1, 0),
676 current_character());
677 BranchOrBacktrack(not_zero, on_no_match);
678 if (mode_ != ASCII) {
679 __ bind(&done);
680 }
681 return true;
682 }
683
684 case '*':
685 // Match any character.
686 return true;
687 // No custom implementation (yet): s(UC16), S(UC16).
Steve Blocka7e24c12009-10-30 11:49:00 +0000688 default:
689 return false;
690 }
691}
692
693
694void RegExpMacroAssemblerX64::Fail() {
695 ASSERT(FAILURE == 0); // Return value for failure is zero.
Steve Block9fac8402011-05-12 15:51:54 +0100696 __ Set(rax, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000697 __ jmp(&exit_label_);
698}
699
700
701Handle<Object> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
702 // Finalize code - write the entry point code now we know how many
703 // registers we need.
Steve Blocka7e24c12009-10-30 11:49:00 +0000704 // Entry code:
705 __ bind(&entry_label_);
706 // Start new stack frame.
707 __ push(rbp);
708 __ movq(rbp, rsp);
709 // Save parameters and callee-save registers. Order here should correspond
710 // to order of kBackup_ebx etc.
711#ifdef _WIN64
712 // MSVC passes arguments in rcx, rdx, r8, r9, with backing stack slots.
713 // Store register parameters in pre-allocated stack slots,
714 __ movq(Operand(rbp, kInputString), rcx);
715 __ movq(Operand(rbp, kStartIndex), rdx); // Passed as int32 in edx.
716 __ movq(Operand(rbp, kInputStart), r8);
717 __ movq(Operand(rbp, kInputEnd), r9);
718 // Callee-save on Win64.
719 __ push(rsi);
720 __ push(rdi);
721 __ push(rbx);
722#else
723 // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9 (and then on stack).
724 // Push register parameters on stack for reference.
725 ASSERT_EQ(kInputString, -1 * kPointerSize);
726 ASSERT_EQ(kStartIndex, -2 * kPointerSize);
727 ASSERT_EQ(kInputStart, -3 * kPointerSize);
728 ASSERT_EQ(kInputEnd, -4 * kPointerSize);
729 ASSERT_EQ(kRegisterOutput, -5 * kPointerSize);
Leon Clarked91b9f72010-01-27 17:25:45 +0000730 ASSERT_EQ(kStackHighEnd, -6 * kPointerSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000731 __ push(rdi);
732 __ push(rsi);
733 __ push(rdx);
734 __ push(rcx);
735 __ push(r8);
736 __ push(r9);
737
738 __ push(rbx); // Callee-save
739#endif
Leon Clarke4515c472010-02-03 11:58:03 +0000740
Leon Clarked91b9f72010-01-27 17:25:45 +0000741 __ push(Immediate(0)); // Make room for "at start" constant.
Steve Blocka7e24c12009-10-30 11:49:00 +0000742
743 // Check if we have space on the stack for registers.
744 Label stack_limit_hit;
745 Label stack_ok;
746
Steve Blockd0582a62009-12-15 09:54:21 +0000747 ExternalReference stack_limit =
Steve Block44f0eee2011-05-26 01:26:41 +0100748 ExternalReference::address_of_stack_limit(masm_.isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000749 __ movq(rcx, rsp);
Steve Blockd0582a62009-12-15 09:54:21 +0000750 __ movq(kScratchRegister, stack_limit);
Steve Blocka7e24c12009-10-30 11:49:00 +0000751 __ subq(rcx, Operand(kScratchRegister, 0));
752 // Handle it if the stack pointer is already below the stack limit.
753 __ j(below_equal, &stack_limit_hit);
754 // Check if there is room for the variable number of registers above
755 // the stack limit.
756 __ cmpq(rcx, Immediate(num_registers_ * kPointerSize));
757 __ j(above_equal, &stack_ok);
758 // Exit with OutOfMemory exception. There is not enough space on the stack
759 // for our working registers.
760 __ movq(rax, Immediate(EXCEPTION));
761 __ jmp(&exit_label_);
762
763 __ bind(&stack_limit_hit);
Steve Block44f0eee2011-05-26 01:26:41 +0100764 __ Move(code_object_pointer(), masm_.CodeObject());
Steve Blocka7e24c12009-10-30 11:49:00 +0000765 CallCheckStackGuardState(); // Preserves no registers beside rbp and rsp.
766 __ testq(rax, rax);
767 // If returned value is non-zero, we exit with the returned value as result.
768 __ j(not_zero, &exit_label_);
769
770 __ bind(&stack_ok);
771
772 // Allocate space on stack for registers.
773 __ subq(rsp, Immediate(num_registers_ * kPointerSize));
774 // Load string length.
775 __ movq(rsi, Operand(rbp, kInputEnd));
776 // Load input position.
777 __ movq(rdi, Operand(rbp, kInputStart));
778 // Set up rdi to be negative offset from string end.
779 __ subq(rdi, rsi);
Steve Block6ded16b2010-05-10 14:33:55 +0100780 // Set rax to address of char before start of the string
Steve Blocka7e24c12009-10-30 11:49:00 +0000781 // (effectively string position -1).
Steve Block6ded16b2010-05-10 14:33:55 +0100782 __ movq(rbx, Operand(rbp, kStartIndex));
783 __ neg(rbx);
784 if (mode_ == UC16) {
785 __ lea(rax, Operand(rdi, rbx, times_2, -char_size()));
786 } else {
787 __ lea(rax, Operand(rdi, rbx, times_1, -char_size()));
788 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000789 // Store this value in a local variable, for use when clearing
790 // position registers.
791 __ movq(Operand(rbp, kInputStartMinusOne), rax);
Leon Clarked91b9f72010-01-27 17:25:45 +0000792
Steve Blocka7e24c12009-10-30 11:49:00 +0000793 if (num_saved_registers_ > 0) {
794 // Fill saved registers with initial value = start offset - 1
795 // Fill in stack push order, to avoid accessing across an unwritten
796 // page (a problem on Windows).
797 __ movq(rcx, Immediate(kRegisterZero));
798 Label init_loop;
799 __ bind(&init_loop);
800 __ movq(Operand(rbp, rcx, times_1, 0), rax);
801 __ subq(rcx, Immediate(kPointerSize));
802 __ cmpq(rcx,
803 Immediate(kRegisterZero - num_saved_registers_ * kPointerSize));
804 __ j(greater, &init_loop);
805 }
806 // Ensure that we have written to each stack page, in order. Skipping a page
807 // on Windows can cause segmentation faults. Assuming page size is 4k.
808 const int kPageSize = 4096;
809 const int kRegistersPerPage = kPageSize / kPointerSize;
810 for (int i = num_saved_registers_ + kRegistersPerPage - 1;
811 i < num_registers_;
812 i += kRegistersPerPage) {
813 __ movq(register_location(i), rax); // One write every page.
814 }
815
816 // Initialize backtrack stack pointer.
817 __ movq(backtrack_stackpointer(), Operand(rbp, kStackHighEnd));
818 // Initialize code object pointer.
Steve Block44f0eee2011-05-26 01:26:41 +0100819 __ Move(code_object_pointer(), masm_.CodeObject());
Steve Blocka7e24c12009-10-30 11:49:00 +0000820 // Load previous char as initial value of current-character.
821 Label at_start;
Kristian Monsen25f61362010-05-21 11:50:48 +0100822 __ cmpb(Operand(rbp, kStartIndex), Immediate(0));
823 __ j(equal, &at_start);
Steve Blocka7e24c12009-10-30 11:49:00 +0000824 LoadCurrentCharacterUnchecked(-1, 1); // Load previous char.
825 __ jmp(&start_label_);
826 __ bind(&at_start);
827 __ movq(current_character(), Immediate('\n'));
828 __ jmp(&start_label_);
829
830
831 // Exit code:
832 if (success_label_.is_linked()) {
833 // Save captures when successful.
834 __ bind(&success_label_);
835 if (num_saved_registers_ > 0) {
836 // copy captures to output
Steve Block6ded16b2010-05-10 14:33:55 +0100837 __ movq(rdx, Operand(rbp, kStartIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +0000838 __ movq(rbx, Operand(rbp, kRegisterOutput));
839 __ movq(rcx, Operand(rbp, kInputEnd));
840 __ subq(rcx, Operand(rbp, kInputStart));
Steve Block6ded16b2010-05-10 14:33:55 +0100841 if (mode_ == UC16) {
842 __ lea(rcx, Operand(rcx, rdx, times_2, 0));
843 } else {
844 __ addq(rcx, rdx);
845 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000846 for (int i = 0; i < num_saved_registers_; i++) {
847 __ movq(rax, register_location(i));
848 __ addq(rax, rcx); // Convert to index from start, not end.
849 if (mode_ == UC16) {
850 __ sar(rax, Immediate(1)); // Convert byte index to character index.
851 }
852 __ movl(Operand(rbx, i * kIntSize), rax);
853 }
854 }
855 __ movq(rax, Immediate(SUCCESS));
856 }
857
858 // Exit and return rax
859 __ bind(&exit_label_);
860
861#ifdef _WIN64
862 // Restore callee save registers.
863 __ lea(rsp, Operand(rbp, kLastCalleeSaveRegister));
864 __ pop(rbx);
865 __ pop(rdi);
866 __ pop(rsi);
867 // Stack now at rbp.
868#else
869 // Restore callee save register.
870 __ movq(rbx, Operand(rbp, kBackup_rbx));
871 // Skip rsp to rbp.
872 __ movq(rsp, rbp);
873#endif
874 // Exit function frame, restore previous one.
875 __ pop(rbp);
876 __ ret(0);
877
878 // Backtrack code (branch target for conditional backtracks).
879 if (backtrack_label_.is_linked()) {
880 __ bind(&backtrack_label_);
881 Backtrack();
882 }
883
884 Label exit_with_exception;
885
886 // Preempt-code
887 if (check_preempt_label_.is_linked()) {
888 SafeCallTarget(&check_preempt_label_);
889
890 __ push(backtrack_stackpointer());
891 __ push(rdi);
892
893 CallCheckStackGuardState();
894 __ testq(rax, rax);
895 // If returning non-zero, we should end execution with the given
896 // result as return value.
897 __ j(not_zero, &exit_label_);
898
899 // Restore registers.
Steve Block44f0eee2011-05-26 01:26:41 +0100900 __ Move(code_object_pointer(), masm_.CodeObject());
Steve Blocka7e24c12009-10-30 11:49:00 +0000901 __ pop(rdi);
902 __ pop(backtrack_stackpointer());
903 // String might have moved: Reload esi from frame.
904 __ movq(rsi, Operand(rbp, kInputEnd));
905 SafeReturn();
906 }
907
908 // Backtrack stack overflow code.
909 if (stack_overflow_label_.is_linked()) {
910 SafeCallTarget(&stack_overflow_label_);
911 // Reached if the backtrack-stack limit has been hit.
912
913 Label grow_failed;
914 // Save registers before calling C function
915#ifndef _WIN64
916 // Callee-save in Microsoft 64-bit ABI, but not in AMD64 ABI.
917 __ push(rsi);
918 __ push(rdi);
919#endif
920
921 // Call GrowStack(backtrack_stackpointer())
Steve Block6ded16b2010-05-10 14:33:55 +0100922 static const int num_arguments = 2;
Leon Clarke4515c472010-02-03 11:58:03 +0000923 __ PrepareCallCFunction(num_arguments);
Steve Blocka7e24c12009-10-30 11:49:00 +0000924#ifdef _WIN64
925 // Microsoft passes parameters in rcx, rdx.
926 // First argument, backtrack stackpointer, is already in rcx.
927 __ lea(rdx, Operand(rbp, kStackHighEnd)); // Second argument
928#else
929 // AMD64 ABI passes parameters in rdi, rsi.
930 __ movq(rdi, backtrack_stackpointer()); // First argument.
931 __ lea(rsi, Operand(rbp, kStackHighEnd)); // Second argument.
932#endif
Steve Block44f0eee2011-05-26 01:26:41 +0100933 ExternalReference grow_stack =
934 ExternalReference::re_grow_stack(masm_.isolate());
Leon Clarke4515c472010-02-03 11:58:03 +0000935 __ CallCFunction(grow_stack, num_arguments);
Steve Blocka7e24c12009-10-30 11:49:00 +0000936 // If return NULL, we have failed to grow the stack, and
937 // must exit with a stack-overflow exception.
938 __ testq(rax, rax);
939 __ j(equal, &exit_with_exception);
940 // Otherwise use return value as new stack pointer.
941 __ movq(backtrack_stackpointer(), rax);
942 // Restore saved registers and continue.
Steve Block44f0eee2011-05-26 01:26:41 +0100943 __ Move(code_object_pointer(), masm_.CodeObject());
Steve Blocka7e24c12009-10-30 11:49:00 +0000944#ifndef _WIN64
945 __ pop(rdi);
946 __ pop(rsi);
947#endif
948 SafeReturn();
949 }
950
951 if (exit_with_exception.is_linked()) {
952 // If any of the code above needed to exit with an exception.
953 __ bind(&exit_with_exception);
954 // Exit with Result EXCEPTION(-1) to signal thrown exception.
955 __ movq(rax, Immediate(EXCEPTION));
956 __ jmp(&exit_label_);
957 }
958
959 FixupCodeRelativePositions();
960
961 CodeDesc code_desc;
Steve Block44f0eee2011-05-26 01:26:41 +0100962 masm_.GetCode(&code_desc);
963 Isolate* isolate = ISOLATE;
964 Handle<Code> code = isolate->factory()->NewCode(
965 code_desc, Code::ComputeFlags(Code::REGEXP),
966 masm_.CodeObject());
967 PROFILE(isolate, RegExpCodeCreateEvent(*code, *source));
Steve Blocka7e24c12009-10-30 11:49:00 +0000968 return Handle<Object>::cast(code);
969}
970
971
972void RegExpMacroAssemblerX64::GoTo(Label* to) {
973 BranchOrBacktrack(no_condition, to);
974}
975
976
977void RegExpMacroAssemblerX64::IfRegisterGE(int reg,
978 int comparand,
979 Label* if_ge) {
980 __ cmpq(register_location(reg), Immediate(comparand));
981 BranchOrBacktrack(greater_equal, if_ge);
982}
983
984
985void RegExpMacroAssemblerX64::IfRegisterLT(int reg,
986 int comparand,
987 Label* if_lt) {
988 __ cmpq(register_location(reg), Immediate(comparand));
989 BranchOrBacktrack(less, if_lt);
990}
991
992
993void RegExpMacroAssemblerX64::IfRegisterEqPos(int reg,
994 Label* if_eq) {
995 __ cmpq(rdi, register_location(reg));
996 BranchOrBacktrack(equal, if_eq);
997}
998
999
1000RegExpMacroAssembler::IrregexpImplementation
1001 RegExpMacroAssemblerX64::Implementation() {
1002 return kX64Implementation;
1003}
1004
1005
1006void RegExpMacroAssemblerX64::LoadCurrentCharacter(int cp_offset,
1007 Label* on_end_of_input,
1008 bool check_bounds,
1009 int characters) {
1010 ASSERT(cp_offset >= -1); // ^ and \b can look behind one character.
1011 ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works)
1012 if (check_bounds) {
1013 CheckPosition(cp_offset + characters - 1, on_end_of_input);
1014 }
1015 LoadCurrentCharacterUnchecked(cp_offset, characters);
1016}
1017
1018
1019void RegExpMacroAssemblerX64::PopCurrentPosition() {
1020 Pop(rdi);
1021}
1022
1023
1024void RegExpMacroAssemblerX64::PopRegister(int register_index) {
1025 Pop(rax);
1026 __ movq(register_location(register_index), rax);
1027}
1028
1029
1030void RegExpMacroAssemblerX64::PushBacktrack(Label* label) {
1031 Push(label);
1032 CheckStackLimit();
1033}
1034
1035
1036void RegExpMacroAssemblerX64::PushCurrentPosition() {
1037 Push(rdi);
1038}
1039
1040
1041void RegExpMacroAssemblerX64::PushRegister(int register_index,
1042 StackCheckFlag check_stack_limit) {
1043 __ movq(rax, register_location(register_index));
1044 Push(rax);
1045 if (check_stack_limit) CheckStackLimit();
1046}
1047
1048
1049void RegExpMacroAssemblerX64::ReadCurrentPositionFromRegister(int reg) {
1050 __ movq(rdi, register_location(reg));
1051}
1052
1053
1054void RegExpMacroAssemblerX64::ReadStackPointerFromRegister(int reg) {
1055 __ movq(backtrack_stackpointer(), register_location(reg));
1056 __ addq(backtrack_stackpointer(), Operand(rbp, kStackHighEnd));
1057}
1058
1059
Ben Murdochf87a2032010-10-22 12:50:53 +01001060void RegExpMacroAssemblerX64::SetCurrentPositionFromEnd(int by) {
1061 NearLabel after_position;
1062 __ cmpq(rdi, Immediate(-by * char_size()));
1063 __ j(greater_equal, &after_position);
1064 __ movq(rdi, Immediate(-by * char_size()));
1065 // On RegExp code entry (where this operation is used), the character before
1066 // the current position is expected to be already loaded.
1067 // We have advanced the position, so it's safe to read backwards.
1068 LoadCurrentCharacterUnchecked(-1, 1);
1069 __ bind(&after_position);
1070}
1071
1072
Steve Blocka7e24c12009-10-30 11:49:00 +00001073void RegExpMacroAssemblerX64::SetRegister(int register_index, int to) {
1074 ASSERT(register_index >= num_saved_registers_); // Reserved for positions!
1075 __ movq(register_location(register_index), Immediate(to));
1076}
1077
1078
1079void RegExpMacroAssemblerX64::Succeed() {
1080 __ jmp(&success_label_);
1081}
1082
1083
1084void RegExpMacroAssemblerX64::WriteCurrentPositionToRegister(int reg,
1085 int cp_offset) {
1086 if (cp_offset == 0) {
1087 __ movq(register_location(reg), rdi);
1088 } else {
1089 __ lea(rax, Operand(rdi, cp_offset * char_size()));
1090 __ movq(register_location(reg), rax);
1091 }
1092}
1093
1094
1095void RegExpMacroAssemblerX64::ClearRegisters(int reg_from, int reg_to) {
1096 ASSERT(reg_from <= reg_to);
1097 __ movq(rax, Operand(rbp, kInputStartMinusOne));
1098 for (int reg = reg_from; reg <= reg_to; reg++) {
1099 __ movq(register_location(reg), rax);
1100 }
1101}
1102
1103
1104void RegExpMacroAssemblerX64::WriteStackPointerToRegister(int reg) {
1105 __ movq(rax, backtrack_stackpointer());
1106 __ subq(rax, Operand(rbp, kStackHighEnd));
1107 __ movq(register_location(reg), rax);
1108}
1109
1110
1111// Private methods:
1112
1113void RegExpMacroAssemblerX64::CallCheckStackGuardState() {
1114 // This function call preserves no register values. Caller should
1115 // store anything volatile in a C call or overwritten by this function.
Steve Block6ded16b2010-05-10 14:33:55 +01001116 static const int num_arguments = 3;
Leon Clarke4515c472010-02-03 11:58:03 +00001117 __ PrepareCallCFunction(num_arguments);
Steve Blocka7e24c12009-10-30 11:49:00 +00001118#ifdef _WIN64
1119 // Second argument: Code* of self. (Do this before overwriting r8).
1120 __ movq(rdx, code_object_pointer());
1121 // Third argument: RegExp code frame pointer.
1122 __ movq(r8, rbp);
1123 // First argument: Next address on the stack (will be address of
1124 // return address).
1125 __ lea(rcx, Operand(rsp, -kPointerSize));
1126#else
1127 // Third argument: RegExp code frame pointer.
1128 __ movq(rdx, rbp);
1129 // Second argument: Code* of self.
1130 __ movq(rsi, code_object_pointer());
1131 // First argument: Next address on the stack (will be address of
1132 // return address).
1133 __ lea(rdi, Operand(rsp, -kPointerSize));
1134#endif
1135 ExternalReference stack_check =
Steve Block44f0eee2011-05-26 01:26:41 +01001136 ExternalReference::re_check_stack_guard_state(masm_.isolate());
Leon Clarke4515c472010-02-03 11:58:03 +00001137 __ CallCFunction(stack_check, num_arguments);
Steve Blocka7e24c12009-10-30 11:49:00 +00001138}
1139
1140
1141// Helper function for reading a value out of a stack frame.
1142template <typename T>
1143static T& frame_entry(Address re_frame, int frame_offset) {
1144 return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset));
1145}
1146
1147
1148int RegExpMacroAssemblerX64::CheckStackGuardState(Address* return_address,
1149 Code* re_code,
1150 Address re_frame) {
Steve Block44f0eee2011-05-26 01:26:41 +01001151 Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
1152 ASSERT(isolate == Isolate::Current());
1153 if (isolate->stack_guard()->IsStackOverflow()) {
1154 isolate->StackOverflow();
Steve Blocka7e24c12009-10-30 11:49:00 +00001155 return EXCEPTION;
1156 }
1157
1158 // If not real stack overflow the stack guard was used to interrupt
1159 // execution for another purpose.
1160
Leon Clarke4515c472010-02-03 11:58:03 +00001161 // If this is a direct call from JavaScript retry the RegExp forcing the call
1162 // through the runtime system. Currently the direct call cannot handle a GC.
1163 if (frame_entry<int>(re_frame, kDirectCall) == 1) {
1164 return RETRY;
1165 }
1166
Steve Blocka7e24c12009-10-30 11:49:00 +00001167 // Prepare for possible GC.
1168 HandleScope handles;
1169 Handle<Code> code_handle(re_code);
1170
1171 Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
1172 // Current string.
1173 bool is_ascii = subject->IsAsciiRepresentation();
1174
1175 ASSERT(re_code->instruction_start() <= *return_address);
1176 ASSERT(*return_address <=
1177 re_code->instruction_start() + re_code->instruction_size());
1178
John Reck59135872010-11-02 12:39:01 -07001179 MaybeObject* result = Execution::HandleStackGuardInterrupt();
Steve Blocka7e24c12009-10-30 11:49:00 +00001180
1181 if (*code_handle != re_code) { // Return address no longer valid
1182 intptr_t delta = *code_handle - re_code;
1183 // Overwrite the return address on the stack.
1184 *return_address += delta;
1185 }
1186
1187 if (result->IsException()) {
1188 return EXCEPTION;
1189 }
1190
1191 // String might have changed.
1192 if (subject->IsAsciiRepresentation() != is_ascii) {
1193 // If we changed between an ASCII and an UC16 string, the specialized
1194 // code cannot be used, and we need to restart regexp matching from
1195 // scratch (including, potentially, compiling a new version of the code).
1196 return RETRY;
1197 }
1198
1199 // Otherwise, the content of the string might have moved. It must still
1200 // be a sequential or external string with the same content.
1201 // Update the start and end pointers in the stack frame to the current
1202 // location (whether it has actually moved or not).
1203 ASSERT(StringShape(*subject).IsSequential() ||
1204 StringShape(*subject).IsExternal());
1205
1206 // The original start address of the characters to match.
1207 const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
1208
1209 // Find the current start address of the same character at the current string
1210 // position.
1211 int start_index = frame_entry<int>(re_frame, kStartIndex);
1212 const byte* new_address = StringCharacterPosition(*subject, start_index);
1213
1214 if (start_address != new_address) {
1215 // If there is a difference, update the object pointer and start and end
1216 // addresses in the RegExp stack frame to match the new value.
1217 const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
Steve Blockd0582a62009-12-15 09:54:21 +00001218 int byte_length = static_cast<int>(end_address - start_address);
Steve Blocka7e24c12009-10-30 11:49:00 +00001219 frame_entry<const String*>(re_frame, kInputString) = *subject;
1220 frame_entry<const byte*>(re_frame, kInputStart) = new_address;
1221 frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
1222 }
1223
1224 return 0;
1225}
1226
1227
1228Operand RegExpMacroAssemblerX64::register_location(int register_index) {
1229 ASSERT(register_index < (1<<30));
1230 if (num_registers_ <= register_index) {
1231 num_registers_ = register_index + 1;
1232 }
1233 return Operand(rbp, kRegisterZero - register_index * kPointerSize);
1234}
1235
1236
1237void RegExpMacroAssemblerX64::CheckPosition(int cp_offset,
1238 Label* on_outside_input) {
1239 __ cmpl(rdi, Immediate(-cp_offset * char_size()));
1240 BranchOrBacktrack(greater_equal, on_outside_input);
1241}
1242
1243
1244void RegExpMacroAssemblerX64::BranchOrBacktrack(Condition condition,
1245 Label* to) {
1246 if (condition < 0) { // No condition
1247 if (to == NULL) {
1248 Backtrack();
1249 return;
1250 }
1251 __ jmp(to);
1252 return;
1253 }
1254 if (to == NULL) {
1255 __ j(condition, &backtrack_label_);
1256 return;
1257 }
1258 __ j(condition, to);
1259}
1260
1261
1262void RegExpMacroAssemblerX64::SafeCall(Label* to) {
1263 __ call(to);
1264}
1265
1266
1267void RegExpMacroAssemblerX64::SafeCallTarget(Label* label) {
1268 __ bind(label);
1269 __ subq(Operand(rsp, 0), code_object_pointer());
1270}
1271
1272
1273void RegExpMacroAssemblerX64::SafeReturn() {
1274 __ addq(Operand(rsp, 0), code_object_pointer());
1275 __ ret(0);
1276}
1277
1278
1279void RegExpMacroAssemblerX64::Push(Register source) {
1280 ASSERT(!source.is(backtrack_stackpointer()));
1281 // Notice: This updates flags, unlike normal Push.
1282 __ subq(backtrack_stackpointer(), Immediate(kIntSize));
1283 __ movl(Operand(backtrack_stackpointer(), 0), source);
1284}
1285
1286
1287void RegExpMacroAssemblerX64::Push(Immediate value) {
1288 // Notice: This updates flags, unlike normal Push.
1289 __ subq(backtrack_stackpointer(), Immediate(kIntSize));
1290 __ movl(Operand(backtrack_stackpointer(), 0), value);
1291}
1292
1293
1294void RegExpMacroAssemblerX64::FixupCodeRelativePositions() {
1295 for (int i = 0, n = code_relative_fixup_positions_.length(); i < n; i++) {
1296 int position = code_relative_fixup_positions_[i];
1297 // The position succeeds a relative label offset from position.
1298 // Patch the relative offset to be relative to the Code object pointer
1299 // instead.
1300 int patch_position = position - kIntSize;
Steve Block44f0eee2011-05-26 01:26:41 +01001301 int offset = masm_.long_at(patch_position);
1302 masm_.long_at_put(patch_position,
Steve Blocka7e24c12009-10-30 11:49:00 +00001303 offset
1304 + position
1305 + Code::kHeaderSize
1306 - kHeapObjectTag);
1307 }
1308 code_relative_fixup_positions_.Clear();
1309}
1310
1311
1312void RegExpMacroAssemblerX64::Push(Label* backtrack_target) {
1313 __ subq(backtrack_stackpointer(), Immediate(kIntSize));
1314 __ movl(Operand(backtrack_stackpointer(), 0), backtrack_target);
1315 MarkPositionForCodeRelativeFixup();
1316}
1317
1318
1319void RegExpMacroAssemblerX64::Pop(Register target) {
1320 ASSERT(!target.is(backtrack_stackpointer()));
1321 __ movsxlq(target, Operand(backtrack_stackpointer(), 0));
1322 // Notice: This updates flags, unlike normal Pop.
1323 __ addq(backtrack_stackpointer(), Immediate(kIntSize));
1324}
1325
1326
1327void RegExpMacroAssemblerX64::Drop() {
1328 __ addq(backtrack_stackpointer(), Immediate(kIntSize));
1329}
1330
1331
1332void RegExpMacroAssemblerX64::CheckPreemption() {
1333 // Check for preemption.
1334 Label no_preempt;
Steve Blockd0582a62009-12-15 09:54:21 +00001335 ExternalReference stack_limit =
Steve Block44f0eee2011-05-26 01:26:41 +01001336 ExternalReference::address_of_stack_limit(masm_.isolate());
Steve Blockd0582a62009-12-15 09:54:21 +00001337 __ load_rax(stack_limit);
Steve Blocka7e24c12009-10-30 11:49:00 +00001338 __ cmpq(rsp, rax);
1339 __ j(above, &no_preempt);
1340
1341 SafeCall(&check_preempt_label_);
1342
1343 __ bind(&no_preempt);
1344}
1345
1346
1347void RegExpMacroAssemblerX64::CheckStackLimit() {
Steve Blockd0582a62009-12-15 09:54:21 +00001348 Label no_stack_overflow;
1349 ExternalReference stack_limit =
Steve Block44f0eee2011-05-26 01:26:41 +01001350 ExternalReference::address_of_regexp_stack_limit(masm_.isolate());
Steve Blockd0582a62009-12-15 09:54:21 +00001351 __ load_rax(stack_limit);
1352 __ cmpq(backtrack_stackpointer(), rax);
1353 __ j(above, &no_stack_overflow);
Steve Blocka7e24c12009-10-30 11:49:00 +00001354
Steve Blockd0582a62009-12-15 09:54:21 +00001355 SafeCall(&stack_overflow_label_);
Steve Blocka7e24c12009-10-30 11:49:00 +00001356
Steve Blockd0582a62009-12-15 09:54:21 +00001357 __ bind(&no_stack_overflow);
Steve Blocka7e24c12009-10-30 11:49:00 +00001358}
1359
1360
Steve Blocka7e24c12009-10-30 11:49:00 +00001361void RegExpMacroAssemblerX64::LoadCurrentCharacterUnchecked(int cp_offset,
1362 int characters) {
1363 if (mode_ == ASCII) {
1364 if (characters == 4) {
1365 __ movl(current_character(), Operand(rsi, rdi, times_1, cp_offset));
1366 } else if (characters == 2) {
1367 __ movzxwl(current_character(), Operand(rsi, rdi, times_1, cp_offset));
1368 } else {
1369 ASSERT(characters == 1);
1370 __ movzxbl(current_character(), Operand(rsi, rdi, times_1, cp_offset));
1371 }
1372 } else {
1373 ASSERT(mode_ == UC16);
1374 if (characters == 2) {
1375 __ movl(current_character(),
1376 Operand(rsi, rdi, times_1, cp_offset * sizeof(uc16)));
1377 } else {
1378 ASSERT(characters == 1);
1379 __ movzxwl(current_character(),
1380 Operand(rsi, rdi, times_1, cp_offset * sizeof(uc16)));
1381 }
1382 }
1383}
1384
Steve Blocka7e24c12009-10-30 11:49:00 +00001385#undef __
1386
Steve Block6ded16b2010-05-10 14:33:55 +01001387#endif // V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +00001388
1389}} // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01001390
1391#endif // V8_TARGET_ARCH_X64