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

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

Issue 1285163003: Move regexp implementation into its own folder. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: addressed comment Created 5 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
« no previous file with comments | « src/arm64/regexp-macro-assembler-arm64.h ('k') | src/assembler.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/v8.h"
6
7 #if V8_TARGET_ARCH_ARM64
8
9 #include "src/code-stubs.h"
10 #include "src/cpu-profiler.h"
11 #include "src/log.h"
12 #include "src/macro-assembler.h"
13 #include "src/regexp-macro-assembler.h"
14 #include "src/regexp-stack.h"
15 #include "src/unicode.h"
16
17 #include "src/arm64/regexp-macro-assembler-arm64.h"
18
19 namespace v8 {
20 namespace internal {
21
22 #ifndef V8_INTERPRETED_REGEXP
23 /*
24 * This assembler uses the following register assignment convention:
25 * - w19 : Used to temporarely store a value before a call to C code.
26 * See CheckNotBackReferenceIgnoreCase.
27 * - x20 : Pointer to the current code object (Code*),
28 * it includes the heap object tag.
29 * - w21 : Current position in input, as negative offset from
30 * the end of the string. Please notice that this is
31 * the byte offset, not the character offset!
32 * - w22 : Currently loaded character. Must be loaded using
33 * LoadCurrentCharacter before using any of the dispatch methods.
34 * - x23 : Points to tip of backtrack stack.
35 * - w24 : Position of the first character minus one: non_position_value.
36 * Used to initialize capture registers.
37 * - x25 : Address at the end of the input string: input_end.
38 * Points to byte after last character in input.
39 * - x26 : Address at the start of the input string: input_start.
40 * - w27 : Where to start in the input string.
41 * - x28 : Output array pointer.
42 * - x29/fp : Frame pointer. Used to access arguments, local variables and
43 * RegExp registers.
44 * - x16/x17 : IP registers, used by assembler. Very volatile.
45 * - csp : Points to tip of C stack.
46 *
47 * - x0-x7 : Used as a cache to store 32 bit capture registers. These
48 * registers need to be retained every time a call to C code
49 * is done.
50 *
51 * The remaining registers are free for computations.
52 * Each call to a public method should retain this convention.
53 *
54 * The stack will have the following structure:
55 *
56 * Location Name Description
57 * (as referred to in
58 * the code)
59 *
60 * - fp[104] isolate Address of the current isolate.
61 * - fp[96] return_address Secondary link/return address
62 * used by an exit frame if this is a
63 * native call.
64 * ^^^ csp when called ^^^
65 * - fp[88] lr Return from the RegExp code.
66 * - fp[80] r29 Old frame pointer (CalleeSaved).
67 * - fp[0..72] r19-r28 Backup of CalleeSaved registers.
68 * - fp[-8] direct_call 1 => Direct call from JavaScript code.
69 * 0 => Call through the runtime system.
70 * - fp[-16] stack_base High end of the memory area to use as
71 * the backtracking stack.
72 * - fp[-24] output_size Output may fit multiple sets of matches.
73 * - fp[-32] input Handle containing the input string.
74 * - fp[-40] success_counter
75 * ^^^^^^^^^^^^^ From here and downwards we store 32 bit values ^^^^^^^^^^^^^
76 * - fp[-44] register N Capture registers initialized with
77 * - fp[-48] register N + 1 non_position_value.
78 * ... The first kNumCachedRegisters (N) registers
79 * ... are cached in x0 to x7.
80 * ... Only positions must be stored in the first
81 * - ... num_saved_registers_ registers.
82 * - ...
83 * - register N + num_registers - 1
84 * ^^^^^^^^^ csp ^^^^^^^^^
85 *
86 * The first num_saved_registers_ registers are initialized to point to
87 * "character -1" in the string (i.e., char_size() bytes before the first
88 * character of the string). The remaining registers start out as garbage.
89 *
90 * The data up to the return address must be placed there by the calling
91 * code and the remaining arguments are passed in registers, e.g. by calling the
92 * code entry as cast to a function with the signature:
93 * int (*match)(String* input,
94 * int start_offset,
95 * Address input_start,
96 * Address input_end,
97 * int* output,
98 * int output_size,
99 * Address stack_base,
100 * bool direct_call = false,
101 * Address secondary_return_address, // Only used by native call.
102 * Isolate* isolate)
103 * The call is performed by NativeRegExpMacroAssembler::Execute()
104 * (in regexp-macro-assembler.cc) via the CALL_GENERATED_REGEXP_CODE macro
105 * in arm64/simulator-arm64.h.
106 * When calling as a non-direct call (i.e., from C++ code), the return address
107 * area is overwritten with the LR register by the RegExp code. When doing a
108 * direct call from generated code, the return address is placed there by
109 * the calling code, as in a normal exit frame.
110 */
111
112 #define __ ACCESS_MASM(masm_)
113
114 RegExpMacroAssemblerARM64::RegExpMacroAssemblerARM64(Isolate* isolate,
115 Zone* zone, Mode mode,
116 int registers_to_save)
117 : NativeRegExpMacroAssembler(isolate, zone),
118 masm_(new MacroAssembler(isolate, NULL, kRegExpCodeSize)),
119 mode_(mode),
120 num_registers_(registers_to_save),
121 num_saved_registers_(registers_to_save),
122 entry_label_(),
123 start_label_(),
124 success_label_(),
125 backtrack_label_(),
126 exit_label_() {
127 __ SetStackPointer(csp);
128 DCHECK_EQ(0, registers_to_save % 2);
129 // We can cache at most 16 W registers in x0-x7.
130 STATIC_ASSERT(kNumCachedRegisters <= 16);
131 STATIC_ASSERT((kNumCachedRegisters % 2) == 0);
132 __ B(&entry_label_); // We'll write the entry code later.
133 __ Bind(&start_label_); // And then continue from here.
134 }
135
136
137 RegExpMacroAssemblerARM64::~RegExpMacroAssemblerARM64() {
138 delete masm_;
139 // Unuse labels in case we throw away the assembler without calling GetCode.
140 entry_label_.Unuse();
141 start_label_.Unuse();
142 success_label_.Unuse();
143 backtrack_label_.Unuse();
144 exit_label_.Unuse();
145 check_preempt_label_.Unuse();
146 stack_overflow_label_.Unuse();
147 }
148
149 int RegExpMacroAssemblerARM64::stack_limit_slack() {
150 return RegExpStack::kStackLimitSlack;
151 }
152
153
154 void RegExpMacroAssemblerARM64::AdvanceCurrentPosition(int by) {
155 if (by != 0) {
156 __ Add(current_input_offset(),
157 current_input_offset(), by * char_size());
158 }
159 }
160
161
162 void RegExpMacroAssemblerARM64::AdvanceRegister(int reg, int by) {
163 DCHECK((reg >= 0) && (reg < num_registers_));
164 if (by != 0) {
165 Register to_advance;
166 RegisterState register_state = GetRegisterState(reg);
167 switch (register_state) {
168 case STACKED:
169 __ Ldr(w10, register_location(reg));
170 __ Add(w10, w10, by);
171 __ Str(w10, register_location(reg));
172 break;
173 case CACHED_LSW:
174 to_advance = GetCachedRegister(reg);
175 __ Add(to_advance, to_advance, by);
176 break;
177 case CACHED_MSW:
178 to_advance = GetCachedRegister(reg);
179 __ Add(to_advance, to_advance,
180 static_cast<int64_t>(by) << kWRegSizeInBits);
181 break;
182 default:
183 UNREACHABLE();
184 break;
185 }
186 }
187 }
188
189
190 void RegExpMacroAssemblerARM64::Backtrack() {
191 CheckPreemption();
192 Pop(w10);
193 __ Add(x10, code_pointer(), Operand(w10, UXTW));
194 __ Br(x10);
195 }
196
197
198 void RegExpMacroAssemblerARM64::Bind(Label* label) {
199 __ Bind(label);
200 }
201
202
203 void RegExpMacroAssemblerARM64::CheckCharacter(uint32_t c, Label* on_equal) {
204 CompareAndBranchOrBacktrack(current_character(), c, eq, on_equal);
205 }
206
207
208 void RegExpMacroAssemblerARM64::CheckCharacterGT(uc16 limit,
209 Label* on_greater) {
210 CompareAndBranchOrBacktrack(current_character(), limit, hi, on_greater);
211 }
212
213
214 void RegExpMacroAssemblerARM64::CheckAtStart(Label* on_at_start) {
215 Label not_at_start;
216 // Did we start the match at the start of the input string?
217 CompareAndBranchOrBacktrack(start_offset(), 0, ne, &not_at_start);
218 // If we did, are we still at the start of the input string?
219 __ Add(x10, input_end(), Operand(current_input_offset(), SXTW));
220 __ Cmp(x10, input_start());
221 BranchOrBacktrack(eq, on_at_start);
222 __ Bind(&not_at_start);
223 }
224
225
226 void RegExpMacroAssemblerARM64::CheckNotAtStart(Label* on_not_at_start) {
227 // Did we start the match at the start of the input string?
228 CompareAndBranchOrBacktrack(start_offset(), 0, ne, on_not_at_start);
229 // If we did, are we still at the start of the input string?
230 __ Add(x10, input_end(), Operand(current_input_offset(), SXTW));
231 __ Cmp(x10, input_start());
232 BranchOrBacktrack(ne, on_not_at_start);
233 }
234
235
236 void RegExpMacroAssemblerARM64::CheckCharacterLT(uc16 limit, Label* on_less) {
237 CompareAndBranchOrBacktrack(current_character(), limit, lo, on_less);
238 }
239
240
241 void RegExpMacroAssemblerARM64::CheckCharacters(Vector<const uc16> str,
242 int cp_offset,
243 Label* on_failure,
244 bool check_end_of_string) {
245 // This method is only ever called from the cctests.
246
247 if (check_end_of_string) {
248 // Is last character of required match inside string.
249 CheckPosition(cp_offset + str.length() - 1, on_failure);
250 }
251
252 Register characters_address = x11;
253
254 __ Add(characters_address,
255 input_end(),
256 Operand(current_input_offset(), SXTW));
257 if (cp_offset != 0) {
258 __ Add(characters_address, characters_address, cp_offset * char_size());
259 }
260
261 for (int i = 0; i < str.length(); i++) {
262 if (mode_ == LATIN1) {
263 __ Ldrb(w10, MemOperand(characters_address, 1, PostIndex));
264 DCHECK(str[i] <= String::kMaxOneByteCharCode);
265 } else {
266 __ Ldrh(w10, MemOperand(characters_address, 2, PostIndex));
267 }
268 CompareAndBranchOrBacktrack(w10, str[i], ne, on_failure);
269 }
270 }
271
272
273 void RegExpMacroAssemblerARM64::CheckGreedyLoop(Label* on_equal) {
274 __ Ldr(w10, MemOperand(backtrack_stackpointer()));
275 __ Cmp(current_input_offset(), w10);
276 __ Cset(x11, eq);
277 __ Add(backtrack_stackpointer(),
278 backtrack_stackpointer(), Operand(x11, LSL, kWRegSizeLog2));
279 BranchOrBacktrack(eq, on_equal);
280 }
281
282 void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase(
283 int start_reg,
284 Label* on_no_match) {
285 Label fallthrough;
286
287 Register capture_start_offset = w10;
288 // Save the capture length in a callee-saved register so it will
289 // be preserved if we call a C helper.
290 Register capture_length = w19;
291 DCHECK(kCalleeSaved.IncludesAliasOf(capture_length));
292
293 // Find length of back-referenced capture.
294 DCHECK((start_reg % 2) == 0);
295 if (start_reg < kNumCachedRegisters) {
296 __ Mov(capture_start_offset.X(), GetCachedRegister(start_reg));
297 __ Lsr(x11, GetCachedRegister(start_reg), kWRegSizeInBits);
298 } else {
299 __ Ldp(w11, capture_start_offset, capture_location(start_reg, x10));
300 }
301 __ Sub(capture_length, w11, capture_start_offset); // Length to check.
302 // Succeed on empty capture (including no capture).
303 __ Cbz(capture_length, &fallthrough);
304
305 // Check that there are enough characters left in the input.
306 __ Cmn(capture_length, current_input_offset());
307 BranchOrBacktrack(gt, on_no_match);
308
309 if (mode_ == LATIN1) {
310 Label success;
311 Label fail;
312 Label loop_check;
313
314 Register capture_start_address = x12;
315 Register capture_end_addresss = x13;
316 Register current_position_address = x14;
317
318 __ Add(capture_start_address,
319 input_end(),
320 Operand(capture_start_offset, SXTW));
321 __ Add(capture_end_addresss,
322 capture_start_address,
323 Operand(capture_length, SXTW));
324 __ Add(current_position_address,
325 input_end(),
326 Operand(current_input_offset(), SXTW));
327
328 Label loop;
329 __ Bind(&loop);
330 __ Ldrb(w10, MemOperand(capture_start_address, 1, PostIndex));
331 __ Ldrb(w11, MemOperand(current_position_address, 1, PostIndex));
332 __ Cmp(w10, w11);
333 __ B(eq, &loop_check);
334
335 // Mismatch, try case-insensitive match (converting letters to lower-case).
336 __ Orr(w10, w10, 0x20); // Convert capture character to lower-case.
337 __ Orr(w11, w11, 0x20); // Also convert input character.
338 __ Cmp(w11, w10);
339 __ B(ne, &fail);
340 __ Sub(w10, w10, 'a');
341 __ Cmp(w10, 'z' - 'a'); // Is w10 a lowercase letter?
342 __ B(ls, &loop_check); // In range 'a'-'z'.
343 // Latin-1: Check for values in range [224,254] but not 247.
344 __ Sub(w10, w10, 224 - 'a');
345 __ Cmp(w10, 254 - 224);
346 __ Ccmp(w10, 247 - 224, ZFlag, ls); // Check for 247.
347 __ B(eq, &fail); // Weren't Latin-1 letters.
348
349 __ Bind(&loop_check);
350 __ Cmp(capture_start_address, capture_end_addresss);
351 __ B(lt, &loop);
352 __ B(&success);
353
354 __ Bind(&fail);
355 BranchOrBacktrack(al, on_no_match);
356
357 __ Bind(&success);
358 // Compute new value of character position after the matched part.
359 __ Sub(current_input_offset().X(), current_position_address, input_end());
360 if (masm_->emit_debug_code()) {
361 __ Cmp(current_input_offset().X(), Operand(current_input_offset(), SXTW));
362 __ Ccmp(current_input_offset(), 0, NoFlag, eq);
363 // The current input offset should be <= 0, and fit in a W register.
364 __ Check(le, kOffsetOutOfRange);
365 }
366 } else {
367 DCHECK(mode_ == UC16);
368 int argument_count = 4;
369
370 // The cached registers need to be retained.
371 CPURegList cached_registers(CPURegister::kRegister, kXRegSizeInBits, 0, 7);
372 DCHECK((cached_registers.Count() * 2) == kNumCachedRegisters);
373 __ PushCPURegList(cached_registers);
374
375 // Put arguments into arguments registers.
376 // Parameters are
377 // x0: Address byte_offset1 - Address captured substring's start.
378 // x1: Address byte_offset2 - Address of current character position.
379 // w2: size_t byte_length - length of capture in bytes(!)
380 // x3: Isolate* isolate
381
382 // Address of start of capture.
383 __ Add(x0, input_end(), Operand(capture_start_offset, SXTW));
384 // Length of capture.
385 __ Mov(w2, capture_length);
386 // Address of current input position.
387 __ Add(x1, input_end(), Operand(current_input_offset(), SXTW));
388 // Isolate.
389 __ Mov(x3, ExternalReference::isolate_address(isolate()));
390
391 {
392 AllowExternalCallThatCantCauseGC scope(masm_);
393 ExternalReference function =
394 ExternalReference::re_case_insensitive_compare_uc16(isolate());
395 __ CallCFunction(function, argument_count);
396 }
397
398 // Check if function returned non-zero for success or zero for failure.
399 // x0 is one of the registers used as a cache so it must be tested before
400 // the cache is restored.
401 __ Cmp(x0, 0);
402 __ PopCPURegList(cached_registers);
403 BranchOrBacktrack(eq, on_no_match);
404
405 // On success, increment position by length of capture.
406 __ Add(current_input_offset(), current_input_offset(), capture_length);
407 }
408
409 __ Bind(&fallthrough);
410 }
411
412 void RegExpMacroAssemblerARM64::CheckNotBackReference(
413 int start_reg,
414 Label* on_no_match) {
415 Label fallthrough;
416
417 Register capture_start_address = x12;
418 Register capture_end_address = x13;
419 Register current_position_address = x14;
420 Register capture_length = w15;
421
422 // Find length of back-referenced capture.
423 DCHECK((start_reg % 2) == 0);
424 if (start_reg < kNumCachedRegisters) {
425 __ Mov(x10, GetCachedRegister(start_reg));
426 __ Lsr(x11, GetCachedRegister(start_reg), kWRegSizeInBits);
427 } else {
428 __ Ldp(w11, w10, capture_location(start_reg, x10));
429 }
430 __ Sub(capture_length, w11, w10); // Length to check.
431 // Succeed on empty capture (including no capture).
432 __ Cbz(capture_length, &fallthrough);
433
434 // Check that there are enough characters left in the input.
435 __ Cmn(capture_length, current_input_offset());
436 BranchOrBacktrack(gt, on_no_match);
437
438 // Compute pointers to match string and capture string
439 __ Add(capture_start_address, input_end(), Operand(w10, SXTW));
440 __ Add(capture_end_address,
441 capture_start_address,
442 Operand(capture_length, SXTW));
443 __ Add(current_position_address,
444 input_end(),
445 Operand(current_input_offset(), SXTW));
446
447 Label loop;
448 __ Bind(&loop);
449 if (mode_ == LATIN1) {
450 __ Ldrb(w10, MemOperand(capture_start_address, 1, PostIndex));
451 __ Ldrb(w11, MemOperand(current_position_address, 1, PostIndex));
452 } else {
453 DCHECK(mode_ == UC16);
454 __ Ldrh(w10, MemOperand(capture_start_address, 2, PostIndex));
455 __ Ldrh(w11, MemOperand(current_position_address, 2, PostIndex));
456 }
457 __ Cmp(w10, w11);
458 BranchOrBacktrack(ne, on_no_match);
459 __ Cmp(capture_start_address, capture_end_address);
460 __ B(lt, &loop);
461
462 // Move current character position to position after match.
463 __ Sub(current_input_offset().X(), current_position_address, input_end());
464 if (masm_->emit_debug_code()) {
465 __ Cmp(current_input_offset().X(), Operand(current_input_offset(), SXTW));
466 __ Ccmp(current_input_offset(), 0, NoFlag, eq);
467 // The current input offset should be <= 0, and fit in a W register.
468 __ Check(le, kOffsetOutOfRange);
469 }
470 __ Bind(&fallthrough);
471 }
472
473
474 void RegExpMacroAssemblerARM64::CheckNotCharacter(unsigned c,
475 Label* on_not_equal) {
476 CompareAndBranchOrBacktrack(current_character(), c, ne, on_not_equal);
477 }
478
479
480 void RegExpMacroAssemblerARM64::CheckCharacterAfterAnd(uint32_t c,
481 uint32_t mask,
482 Label* on_equal) {
483 __ And(w10, current_character(), mask);
484 CompareAndBranchOrBacktrack(w10, c, eq, on_equal);
485 }
486
487
488 void RegExpMacroAssemblerARM64::CheckNotCharacterAfterAnd(unsigned c,
489 unsigned mask,
490 Label* on_not_equal) {
491 __ And(w10, current_character(), mask);
492 CompareAndBranchOrBacktrack(w10, c, ne, on_not_equal);
493 }
494
495
496 void RegExpMacroAssemblerARM64::CheckNotCharacterAfterMinusAnd(
497 uc16 c,
498 uc16 minus,
499 uc16 mask,
500 Label* on_not_equal) {
501 DCHECK(minus < String::kMaxUtf16CodeUnit);
502 __ Sub(w10, current_character(), minus);
503 __ And(w10, w10, mask);
504 CompareAndBranchOrBacktrack(w10, c, ne, on_not_equal);
505 }
506
507
508 void RegExpMacroAssemblerARM64::CheckCharacterInRange(
509 uc16 from,
510 uc16 to,
511 Label* on_in_range) {
512 __ Sub(w10, current_character(), from);
513 // Unsigned lower-or-same condition.
514 CompareAndBranchOrBacktrack(w10, to - from, ls, on_in_range);
515 }
516
517
518 void RegExpMacroAssemblerARM64::CheckCharacterNotInRange(
519 uc16 from,
520 uc16 to,
521 Label* on_not_in_range) {
522 __ Sub(w10, current_character(), from);
523 // Unsigned higher condition.
524 CompareAndBranchOrBacktrack(w10, to - from, hi, on_not_in_range);
525 }
526
527
528 void RegExpMacroAssemblerARM64::CheckBitInTable(
529 Handle<ByteArray> table,
530 Label* on_bit_set) {
531 __ Mov(x11, Operand(table));
532 if ((mode_ != LATIN1) || (kTableMask != String::kMaxOneByteCharCode)) {
533 __ And(w10, current_character(), kTableMask);
534 __ Add(w10, w10, ByteArray::kHeaderSize - kHeapObjectTag);
535 } else {
536 __ Add(w10, current_character(), ByteArray::kHeaderSize - kHeapObjectTag);
537 }
538 __ Ldrb(w11, MemOperand(x11, w10, UXTW));
539 CompareAndBranchOrBacktrack(w11, 0, ne, on_bit_set);
540 }
541
542
543 bool RegExpMacroAssemblerARM64::CheckSpecialCharacterClass(uc16 type,
544 Label* on_no_match) {
545 // Range checks (c in min..max) are generally implemented by an unsigned
546 // (c - min) <= (max - min) check
547 switch (type) {
548 case 's':
549 // Match space-characters
550 if (mode_ == LATIN1) {
551 // One byte space characters are '\t'..'\r', ' ' and \u00a0.
552 Label success;
553 // Check for ' ' or 0x00a0.
554 __ Cmp(current_character(), ' ');
555 __ Ccmp(current_character(), 0x00a0, ZFlag, ne);
556 __ B(eq, &success);
557 // Check range 0x09..0x0d.
558 __ Sub(w10, current_character(), '\t');
559 CompareAndBranchOrBacktrack(w10, '\r' - '\t', hi, on_no_match);
560 __ Bind(&success);
561 return true;
562 }
563 return false;
564 case 'S':
565 // The emitted code for generic character classes is good enough.
566 return false;
567 case 'd':
568 // Match ASCII digits ('0'..'9').
569 __ Sub(w10, current_character(), '0');
570 CompareAndBranchOrBacktrack(w10, '9' - '0', hi, on_no_match);
571 return true;
572 case 'D':
573 // Match ASCII non-digits.
574 __ Sub(w10, current_character(), '0');
575 CompareAndBranchOrBacktrack(w10, '9' - '0', ls, on_no_match);
576 return true;
577 case '.': {
578 // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
579 // Here we emit the conditional branch only once at the end to make branch
580 // prediction more efficient, even though we could branch out of here
581 // as soon as a character matches.
582 __ Cmp(current_character(), 0x0a);
583 __ Ccmp(current_character(), 0x0d, ZFlag, ne);
584 if (mode_ == UC16) {
585 __ Sub(w10, current_character(), 0x2028);
586 // If the Z flag was set we clear the flags to force a branch.
587 __ Ccmp(w10, 0x2029 - 0x2028, NoFlag, ne);
588 // ls -> !((C==1) && (Z==0))
589 BranchOrBacktrack(ls, on_no_match);
590 } else {
591 BranchOrBacktrack(eq, on_no_match);
592 }
593 return true;
594 }
595 case 'n': {
596 // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
597 // We have to check all 4 newline characters before emitting
598 // the conditional branch.
599 __ Cmp(current_character(), 0x0a);
600 __ Ccmp(current_character(), 0x0d, ZFlag, ne);
601 if (mode_ == UC16) {
602 __ Sub(w10, current_character(), 0x2028);
603 // If the Z flag was set we clear the flags to force a fall-through.
604 __ Ccmp(w10, 0x2029 - 0x2028, NoFlag, ne);
605 // hi -> (C==1) && (Z==0)
606 BranchOrBacktrack(hi, on_no_match);
607 } else {
608 BranchOrBacktrack(ne, on_no_match);
609 }
610 return true;
611 }
612 case 'w': {
613 if (mode_ != LATIN1) {
614 // Table is 256 entries, so all Latin1 characters can be tested.
615 CompareAndBranchOrBacktrack(current_character(), 'z', hi, on_no_match);
616 }
617 ExternalReference map = ExternalReference::re_word_character_map();
618 __ Mov(x10, map);
619 __ Ldrb(w10, MemOperand(x10, current_character(), UXTW));
620 CompareAndBranchOrBacktrack(w10, 0, eq, on_no_match);
621 return true;
622 }
623 case 'W': {
624 Label done;
625 if (mode_ != LATIN1) {
626 // Table is 256 entries, so all Latin1 characters can be tested.
627 __ Cmp(current_character(), 'z');
628 __ B(hi, &done);
629 }
630 ExternalReference map = ExternalReference::re_word_character_map();
631 __ Mov(x10, map);
632 __ Ldrb(w10, MemOperand(x10, current_character(), UXTW));
633 CompareAndBranchOrBacktrack(w10, 0, ne, on_no_match);
634 __ Bind(&done);
635 return true;
636 }
637 case '*':
638 // Match any character.
639 return true;
640 // No custom implementation (yet): s(UC16), S(UC16).
641 default:
642 return false;
643 }
644 }
645
646
647 void RegExpMacroAssemblerARM64::Fail() {
648 __ Mov(w0, FAILURE);
649 __ B(&exit_label_);
650 }
651
652
653 Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) {
654 Label return_w0;
655 // Finalize code - write the entry point code now we know how many
656 // registers we need.
657
658 // Entry code:
659 __ Bind(&entry_label_);
660
661 // Arguments on entry:
662 // x0: String* input
663 // x1: int start_offset
664 // x2: byte* input_start
665 // x3: byte* input_end
666 // x4: int* output array
667 // x5: int output array size
668 // x6: Address stack_base
669 // x7: int direct_call
670
671 // The stack pointer should be csp on entry.
672 // csp[8]: address of the current isolate
673 // csp[0]: secondary link/return address used by native call
674
675 // Tell the system that we have a stack frame. Because the type is MANUAL, no
676 // code is generated.
677 FrameScope scope(masm_, StackFrame::MANUAL);
678
679 // Push registers on the stack, only push the argument registers that we need.
680 CPURegList argument_registers(x0, x5, x6, x7);
681
682 CPURegList registers_to_retain = kCalleeSaved;
683 DCHECK(kCalleeSaved.Count() == 11);
684 registers_to_retain.Combine(lr);
685
686 DCHECK(csp.Is(__ StackPointer()));
687 __ PushCPURegList(registers_to_retain);
688 __ PushCPURegList(argument_registers);
689
690 // Set frame pointer in place.
691 __ Add(frame_pointer(), csp, argument_registers.Count() * kPointerSize);
692
693 // Initialize callee-saved registers.
694 __ Mov(start_offset(), w1);
695 __ Mov(input_start(), x2);
696 __ Mov(input_end(), x3);
697 __ Mov(output_array(), x4);
698
699 // Set the number of registers we will need to allocate, that is:
700 // - success_counter (X register)
701 // - (num_registers_ - kNumCachedRegisters) (W registers)
702 int num_wreg_to_allocate = num_registers_ - kNumCachedRegisters;
703 // Do not allocate registers on the stack if they can all be cached.
704 if (num_wreg_to_allocate < 0) { num_wreg_to_allocate = 0; }
705 // Make room for the success_counter.
706 num_wreg_to_allocate += 2;
707
708 // Make sure the stack alignment will be respected.
709 int alignment = masm_->ActivationFrameAlignment();
710 DCHECK_EQ(alignment % 16, 0);
711 int align_mask = (alignment / kWRegSize) - 1;
712 num_wreg_to_allocate = (num_wreg_to_allocate + align_mask) & ~align_mask;
713
714 // Check if we have space on the stack.
715 Label stack_limit_hit;
716 Label stack_ok;
717
718 ExternalReference stack_limit =
719 ExternalReference::address_of_stack_limit(isolate());
720 __ Mov(x10, stack_limit);
721 __ Ldr(x10, MemOperand(x10));
722 __ Subs(x10, csp, x10);
723
724 // Handle it if the stack pointer is already below the stack limit.
725 __ B(ls, &stack_limit_hit);
726
727 // Check if there is room for the variable number of registers above
728 // the stack limit.
729 __ Cmp(x10, num_wreg_to_allocate * kWRegSize);
730 __ B(hs, &stack_ok);
731
732 // Exit with OutOfMemory exception. There is not enough space on the stack
733 // for our working registers.
734 __ Mov(w0, EXCEPTION);
735 __ B(&return_w0);
736
737 __ Bind(&stack_limit_hit);
738 CallCheckStackGuardState(x10);
739 // If returned value is non-zero, we exit with the returned value as result.
740 __ Cbnz(w0, &return_w0);
741
742 __ Bind(&stack_ok);
743
744 // Allocate space on stack.
745 __ Claim(num_wreg_to_allocate, kWRegSize);
746
747 // Initialize success_counter with 0.
748 __ Str(wzr, MemOperand(frame_pointer(), kSuccessCounter));
749
750 // Find negative length (offset of start relative to end).
751 __ Sub(x10, input_start(), input_end());
752 if (masm_->emit_debug_code()) {
753 // Check that the input string length is < 2^30.
754 __ Neg(x11, x10);
755 __ Cmp(x11, (1<<30) - 1);
756 __ Check(ls, kInputStringTooLong);
757 }
758 __ Mov(current_input_offset(), w10);
759
760 // The non-position value is used as a clearing value for the
761 // capture registers, it corresponds to the position of the first character
762 // minus one.
763 __ Sub(non_position_value(), current_input_offset(), char_size());
764 __ Sub(non_position_value(), non_position_value(),
765 Operand(start_offset(), LSL, (mode_ == UC16) ? 1 : 0));
766 // We can store this value twice in an X register for initializing
767 // on-stack registers later.
768 __ Orr(twice_non_position_value(),
769 non_position_value().X(),
770 Operand(non_position_value().X(), LSL, kWRegSizeInBits));
771
772 // Initialize code pointer register.
773 __ Mov(code_pointer(), Operand(masm_->CodeObject()));
774
775 Label load_char_start_regexp, start_regexp;
776 // Load newline if index is at start, previous character otherwise.
777 __ Cbnz(start_offset(), &load_char_start_regexp);
778 __ Mov(current_character(), '\n');
779 __ B(&start_regexp);
780
781 // Global regexp restarts matching here.
782 __ Bind(&load_char_start_regexp);
783 // Load previous char as initial value of current character register.
784 LoadCurrentCharacterUnchecked(-1, 1);
785 __ Bind(&start_regexp);
786 // Initialize on-stack registers.
787 if (num_saved_registers_ > 0) {
788 ClearRegisters(0, num_saved_registers_ - 1);
789 }
790
791 // Initialize backtrack stack pointer.
792 __ Ldr(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackBase));
793
794 // Execute
795 __ B(&start_label_);
796
797 if (backtrack_label_.is_linked()) {
798 __ Bind(&backtrack_label_);
799 Backtrack();
800 }
801
802 if (success_label_.is_linked()) {
803 Register first_capture_start = w15;
804
805 // Save captures when successful.
806 __ Bind(&success_label_);
807
808 if (num_saved_registers_ > 0) {
809 // V8 expects the output to be an int32_t array.
810 Register capture_start = w12;
811 Register capture_end = w13;
812 Register input_length = w14;
813
814 // Copy captures to output.
815
816 // Get string length.
817 __ Sub(x10, input_end(), input_start());
818 if (masm_->emit_debug_code()) {
819 // Check that the input string length is < 2^30.
820 __ Cmp(x10, (1<<30) - 1);
821 __ Check(ls, kInputStringTooLong);
822 }
823 // input_start has a start_offset offset on entry. We need to include
824 // it when computing the length of the whole string.
825 if (mode_ == UC16) {
826 __ Add(input_length, start_offset(), Operand(w10, LSR, 1));
827 } else {
828 __ Add(input_length, start_offset(), w10);
829 }
830
831 // Copy the results to the output array from the cached registers first.
832 for (int i = 0;
833 (i < num_saved_registers_) && (i < kNumCachedRegisters);
834 i += 2) {
835 __ Mov(capture_start.X(), GetCachedRegister(i));
836 __ Lsr(capture_end.X(), capture_start.X(), kWRegSizeInBits);
837 if ((i == 0) && global_with_zero_length_check()) {
838 // Keep capture start for the zero-length check later.
839 __ Mov(first_capture_start, capture_start);
840 }
841 // Offsets need to be relative to the start of the string.
842 if (mode_ == UC16) {
843 __ Add(capture_start, input_length, Operand(capture_start, ASR, 1));
844 __ Add(capture_end, input_length, Operand(capture_end, ASR, 1));
845 } else {
846 __ Add(capture_start, input_length, capture_start);
847 __ Add(capture_end, input_length, capture_end);
848 }
849 // The output pointer advances for a possible global match.
850 __ Stp(capture_start,
851 capture_end,
852 MemOperand(output_array(), kPointerSize, PostIndex));
853 }
854
855 // Only carry on if there are more than kNumCachedRegisters capture
856 // registers.
857 int num_registers_left_on_stack =
858 num_saved_registers_ - kNumCachedRegisters;
859 if (num_registers_left_on_stack > 0) {
860 Register base = x10;
861 // There are always an even number of capture registers. A couple of
862 // registers determine one match with two offsets.
863 DCHECK_EQ(0, num_registers_left_on_stack % 2);
864 __ Add(base, frame_pointer(), kFirstCaptureOnStack);
865
866 // We can unroll the loop here, we should not unroll for less than 2
867 // registers.
868 STATIC_ASSERT(kNumRegistersToUnroll > 2);
869 if (num_registers_left_on_stack <= kNumRegistersToUnroll) {
870 for (int i = 0; i < num_registers_left_on_stack / 2; i++) {
871 __ Ldp(capture_end,
872 capture_start,
873 MemOperand(base, -kPointerSize, PostIndex));
874 if ((i == 0) && global_with_zero_length_check()) {
875 // Keep capture start for the zero-length check later.
876 __ Mov(first_capture_start, capture_start);
877 }
878 // Offsets need to be relative to the start of the string.
879 if (mode_ == UC16) {
880 __ Add(capture_start,
881 input_length,
882 Operand(capture_start, ASR, 1));
883 __ Add(capture_end, input_length, Operand(capture_end, ASR, 1));
884 } else {
885 __ Add(capture_start, input_length, capture_start);
886 __ Add(capture_end, input_length, capture_end);
887 }
888 // The output pointer advances for a possible global match.
889 __ Stp(capture_start,
890 capture_end,
891 MemOperand(output_array(), kPointerSize, PostIndex));
892 }
893 } else {
894 Label loop, start;
895 __ Mov(x11, num_registers_left_on_stack);
896
897 __ Ldp(capture_end,
898 capture_start,
899 MemOperand(base, -kPointerSize, PostIndex));
900 if (global_with_zero_length_check()) {
901 __ Mov(first_capture_start, capture_start);
902 }
903 __ B(&start);
904
905 __ Bind(&loop);
906 __ Ldp(capture_end,
907 capture_start,
908 MemOperand(base, -kPointerSize, PostIndex));
909 __ Bind(&start);
910 if (mode_ == UC16) {
911 __ Add(capture_start, input_length, Operand(capture_start, ASR, 1));
912 __ Add(capture_end, input_length, Operand(capture_end, ASR, 1));
913 } else {
914 __ Add(capture_start, input_length, capture_start);
915 __ Add(capture_end, input_length, capture_end);
916 }
917 // The output pointer advances for a possible global match.
918 __ Stp(capture_start,
919 capture_end,
920 MemOperand(output_array(), kPointerSize, PostIndex));
921 __ Sub(x11, x11, 2);
922 __ Cbnz(x11, &loop);
923 }
924 }
925 }
926
927 if (global()) {
928 Register success_counter = w0;
929 Register output_size = x10;
930 // Restart matching if the regular expression is flagged as global.
931
932 // Increment success counter.
933 __ Ldr(success_counter, MemOperand(frame_pointer(), kSuccessCounter));
934 __ Add(success_counter, success_counter, 1);
935 __ Str(success_counter, MemOperand(frame_pointer(), kSuccessCounter));
936
937 // Capture results have been stored, so the number of remaining global
938 // output registers is reduced by the number of stored captures.
939 __ Ldr(output_size, MemOperand(frame_pointer(), kOutputSize));
940 __ Sub(output_size, output_size, num_saved_registers_);
941 // Check whether we have enough room for another set of capture results.
942 __ Cmp(output_size, num_saved_registers_);
943 __ B(lt, &return_w0);
944
945 // The output pointer is already set to the next field in the output
946 // array.
947 // Update output size on the frame before we restart matching.
948 __ Str(output_size, MemOperand(frame_pointer(), kOutputSize));
949
950 if (global_with_zero_length_check()) {
951 // Special case for zero-length matches.
952 __ Cmp(current_input_offset(), first_capture_start);
953 // Not a zero-length match, restart.
954 __ B(ne, &load_char_start_regexp);
955 // Offset from the end is zero if we already reached the end.
956 __ Cbz(current_input_offset(), &return_w0);
957 // Advance current position after a zero-length match.
958 __ Add(current_input_offset(),
959 current_input_offset(),
960 Operand((mode_ == UC16) ? 2 : 1));
961 }
962
963 __ B(&load_char_start_regexp);
964 } else {
965 __ Mov(w0, SUCCESS);
966 }
967 }
968
969 if (exit_label_.is_linked()) {
970 // Exit and return w0
971 __ Bind(&exit_label_);
972 if (global()) {
973 __ Ldr(w0, MemOperand(frame_pointer(), kSuccessCounter));
974 }
975 }
976
977 __ Bind(&return_w0);
978
979 // Set stack pointer back to first register to retain
980 DCHECK(csp.Is(__ StackPointer()));
981 __ Mov(csp, fp);
982 __ AssertStackConsistency();
983
984 // Restore registers.
985 __ PopCPURegList(registers_to_retain);
986
987 __ Ret();
988
989 Label exit_with_exception;
990 // Registers x0 to x7 are used to store the first captures, they need to be
991 // retained over calls to C++ code.
992 CPURegList cached_registers(CPURegister::kRegister, kXRegSizeInBits, 0, 7);
993 DCHECK((cached_registers.Count() * 2) == kNumCachedRegisters);
994
995 if (check_preempt_label_.is_linked()) {
996 __ Bind(&check_preempt_label_);
997 SaveLinkRegister();
998 // The cached registers need to be retained.
999 __ PushCPURegList(cached_registers);
1000 CallCheckStackGuardState(x10);
1001 // Returning from the regexp code restores the stack (csp <- fp)
1002 // so we don't need to drop the link register from it before exiting.
1003 __ Cbnz(w0, &return_w0);
1004 // Reset the cached registers.
1005 __ PopCPURegList(cached_registers);
1006 RestoreLinkRegister();
1007 __ Ret();
1008 }
1009
1010 if (stack_overflow_label_.is_linked()) {
1011 __ Bind(&stack_overflow_label_);
1012 SaveLinkRegister();
1013 // The cached registers need to be retained.
1014 __ PushCPURegList(cached_registers);
1015 // Call GrowStack(backtrack_stackpointer(), &stack_base)
1016 __ Mov(x2, ExternalReference::isolate_address(isolate()));
1017 __ Add(x1, frame_pointer(), kStackBase);
1018 __ Mov(x0, backtrack_stackpointer());
1019 ExternalReference grow_stack =
1020 ExternalReference::re_grow_stack(isolate());
1021 __ CallCFunction(grow_stack, 3);
1022 // If return NULL, we have failed to grow the stack, and
1023 // must exit with a stack-overflow exception.
1024 // Returning from the regexp code restores the stack (csp <- fp)
1025 // so we don't need to drop the link register from it before exiting.
1026 __ Cbz(w0, &exit_with_exception);
1027 // Otherwise use return value as new stack pointer.
1028 __ Mov(backtrack_stackpointer(), x0);
1029 // Reset the cached registers.
1030 __ PopCPURegList(cached_registers);
1031 RestoreLinkRegister();
1032 __ Ret();
1033 }
1034
1035 if (exit_with_exception.is_linked()) {
1036 __ Bind(&exit_with_exception);
1037 __ Mov(w0, EXCEPTION);
1038 __ B(&return_w0);
1039 }
1040
1041 CodeDesc code_desc;
1042 masm_->GetCode(&code_desc);
1043 Handle<Code> code = isolate()->factory()->NewCode(
1044 code_desc, Code::ComputeFlags(Code::REGEXP), masm_->CodeObject());
1045 PROFILE(masm_->isolate(), RegExpCodeCreateEvent(*code, *source));
1046 return Handle<HeapObject>::cast(code);
1047 }
1048
1049
1050 void RegExpMacroAssemblerARM64::GoTo(Label* to) {
1051 BranchOrBacktrack(al, to);
1052 }
1053
1054 void RegExpMacroAssemblerARM64::IfRegisterGE(int reg, int comparand,
1055 Label* if_ge) {
1056 Register to_compare = GetRegister(reg, w10);
1057 CompareAndBranchOrBacktrack(to_compare, comparand, ge, if_ge);
1058 }
1059
1060
1061 void RegExpMacroAssemblerARM64::IfRegisterLT(int reg, int comparand,
1062 Label* if_lt) {
1063 Register to_compare = GetRegister(reg, w10);
1064 CompareAndBranchOrBacktrack(to_compare, comparand, lt, if_lt);
1065 }
1066
1067
1068 void RegExpMacroAssemblerARM64::IfRegisterEqPos(int reg, Label* if_eq) {
1069 Register to_compare = GetRegister(reg, w10);
1070 __ Cmp(to_compare, current_input_offset());
1071 BranchOrBacktrack(eq, if_eq);
1072 }
1073
1074 RegExpMacroAssembler::IrregexpImplementation
1075 RegExpMacroAssemblerARM64::Implementation() {
1076 return kARM64Implementation;
1077 }
1078
1079
1080 void RegExpMacroAssemblerARM64::LoadCurrentCharacter(int cp_offset,
1081 Label* on_end_of_input,
1082 bool check_bounds,
1083 int characters) {
1084 // TODO(pielan): Make sure long strings are caught before this, and not
1085 // just asserted in debug mode.
1086 DCHECK(cp_offset >= -1); // ^ and \b can look behind one character.
1087 // Be sane! (And ensure that an int32_t can be used to index the string)
1088 DCHECK(cp_offset < (1<<30));
1089 if (check_bounds) {
1090 CheckPosition(cp_offset + characters - 1, on_end_of_input);
1091 }
1092 LoadCurrentCharacterUnchecked(cp_offset, characters);
1093 }
1094
1095
1096 void RegExpMacroAssemblerARM64::PopCurrentPosition() {
1097 Pop(current_input_offset());
1098 }
1099
1100
1101 void RegExpMacroAssemblerARM64::PopRegister(int register_index) {
1102 Pop(w10);
1103 StoreRegister(register_index, w10);
1104 }
1105
1106
1107 void RegExpMacroAssemblerARM64::PushBacktrack(Label* label) {
1108 if (label->is_bound()) {
1109 int target = label->pos();
1110 __ Mov(w10, target + Code::kHeaderSize - kHeapObjectTag);
1111 } else {
1112 __ Adr(x10, label, MacroAssembler::kAdrFar);
1113 __ Sub(x10, x10, code_pointer());
1114 if (masm_->emit_debug_code()) {
1115 __ Cmp(x10, kWRegMask);
1116 // The code offset has to fit in a W register.
1117 __ Check(ls, kOffsetOutOfRange);
1118 }
1119 }
1120 Push(w10);
1121 CheckStackLimit();
1122 }
1123
1124
1125 void RegExpMacroAssemblerARM64::PushCurrentPosition() {
1126 Push(current_input_offset());
1127 }
1128
1129
1130 void RegExpMacroAssemblerARM64::PushRegister(int register_index,
1131 StackCheckFlag check_stack_limit) {
1132 Register to_push = GetRegister(register_index, w10);
1133 Push(to_push);
1134 if (check_stack_limit) CheckStackLimit();
1135 }
1136
1137
1138 void RegExpMacroAssemblerARM64::ReadCurrentPositionFromRegister(int reg) {
1139 Register cached_register;
1140 RegisterState register_state = GetRegisterState(reg);
1141 switch (register_state) {
1142 case STACKED:
1143 __ Ldr(current_input_offset(), register_location(reg));
1144 break;
1145 case CACHED_LSW:
1146 cached_register = GetCachedRegister(reg);
1147 __ Mov(current_input_offset(), cached_register.W());
1148 break;
1149 case CACHED_MSW:
1150 cached_register = GetCachedRegister(reg);
1151 __ Lsr(current_input_offset().X(), cached_register, kWRegSizeInBits);
1152 break;
1153 default:
1154 UNREACHABLE();
1155 break;
1156 }
1157 }
1158
1159
1160 void RegExpMacroAssemblerARM64::ReadStackPointerFromRegister(int reg) {
1161 Register read_from = GetRegister(reg, w10);
1162 __ Ldr(x11, MemOperand(frame_pointer(), kStackBase));
1163 __ Add(backtrack_stackpointer(), x11, Operand(read_from, SXTW));
1164 }
1165
1166
1167 void RegExpMacroAssemblerARM64::SetCurrentPositionFromEnd(int by) {
1168 Label after_position;
1169 __ Cmp(current_input_offset(), -by * char_size());
1170 __ B(ge, &after_position);
1171 __ Mov(current_input_offset(), -by * char_size());
1172 // On RegExp code entry (where this operation is used), the character before
1173 // the current position is expected to be already loaded.
1174 // We have advanced the position, so it's safe to read backwards.
1175 LoadCurrentCharacterUnchecked(-1, 1);
1176 __ Bind(&after_position);
1177 }
1178
1179
1180 void RegExpMacroAssemblerARM64::SetRegister(int register_index, int to) {
1181 DCHECK(register_index >= num_saved_registers_); // Reserved for positions!
1182 Register set_to = wzr;
1183 if (to != 0) {
1184 set_to = w10;
1185 __ Mov(set_to, to);
1186 }
1187 StoreRegister(register_index, set_to);
1188 }
1189
1190
1191 bool RegExpMacroAssemblerARM64::Succeed() {
1192 __ B(&success_label_);
1193 return global();
1194 }
1195
1196
1197 void RegExpMacroAssemblerARM64::WriteCurrentPositionToRegister(int reg,
1198 int cp_offset) {
1199 Register position = current_input_offset();
1200 if (cp_offset != 0) {
1201 position = w10;
1202 __ Add(position, current_input_offset(), cp_offset * char_size());
1203 }
1204 StoreRegister(reg, position);
1205 }
1206
1207
1208 void RegExpMacroAssemblerARM64::ClearRegisters(int reg_from, int reg_to) {
1209 DCHECK(reg_from <= reg_to);
1210 int num_registers = reg_to - reg_from + 1;
1211
1212 // If the first capture register is cached in a hardware register but not
1213 // aligned on a 64-bit one, we need to clear the first one specifically.
1214 if ((reg_from < kNumCachedRegisters) && ((reg_from % 2) != 0)) {
1215 StoreRegister(reg_from, non_position_value());
1216 num_registers--;
1217 reg_from++;
1218 }
1219
1220 // Clear cached registers in pairs as far as possible.
1221 while ((num_registers >= 2) && (reg_from < kNumCachedRegisters)) {
1222 DCHECK(GetRegisterState(reg_from) == CACHED_LSW);
1223 __ Mov(GetCachedRegister(reg_from), twice_non_position_value());
1224 reg_from += 2;
1225 num_registers -= 2;
1226 }
1227
1228 if ((num_registers % 2) == 1) {
1229 StoreRegister(reg_from, non_position_value());
1230 num_registers--;
1231 reg_from++;
1232 }
1233
1234 if (num_registers > 0) {
1235 // If there are some remaining registers, they are stored on the stack.
1236 DCHECK(reg_from >= kNumCachedRegisters);
1237
1238 // Move down the indexes of the registers on stack to get the correct offset
1239 // in memory.
1240 reg_from -= kNumCachedRegisters;
1241 reg_to -= kNumCachedRegisters;
1242 // We should not unroll the loop for less than 2 registers.
1243 STATIC_ASSERT(kNumRegistersToUnroll > 2);
1244 // We position the base pointer to (reg_from + 1).
1245 int base_offset = kFirstRegisterOnStack -
1246 kWRegSize - (kWRegSize * reg_from);
1247 if (num_registers > kNumRegistersToUnroll) {
1248 Register base = x10;
1249 __ Add(base, frame_pointer(), base_offset);
1250
1251 Label loop;
1252 __ Mov(x11, num_registers);
1253 __ Bind(&loop);
1254 __ Str(twice_non_position_value(),
1255 MemOperand(base, -kPointerSize, PostIndex));
1256 __ Sub(x11, x11, 2);
1257 __ Cbnz(x11, &loop);
1258 } else {
1259 for (int i = reg_from; i <= reg_to; i += 2) {
1260 __ Str(twice_non_position_value(),
1261 MemOperand(frame_pointer(), base_offset));
1262 base_offset -= kWRegSize * 2;
1263 }
1264 }
1265 }
1266 }
1267
1268
1269 void RegExpMacroAssemblerARM64::WriteStackPointerToRegister(int reg) {
1270 __ Ldr(x10, MemOperand(frame_pointer(), kStackBase));
1271 __ Sub(x10, backtrack_stackpointer(), x10);
1272 if (masm_->emit_debug_code()) {
1273 __ Cmp(x10, Operand(w10, SXTW));
1274 // The stack offset needs to fit in a W register.
1275 __ Check(eq, kOffsetOutOfRange);
1276 }
1277 StoreRegister(reg, w10);
1278 }
1279
1280
1281 // Helper function for reading a value out of a stack frame.
1282 template <typename T>
1283 static T& frame_entry(Address re_frame, int frame_offset) {
1284 return *reinterpret_cast<T*>(re_frame + frame_offset);
1285 }
1286
1287
1288 template <typename T>
1289 static T* frame_entry_address(Address re_frame, int frame_offset) {
1290 return reinterpret_cast<T*>(re_frame + frame_offset);
1291 }
1292
1293
1294 int RegExpMacroAssemblerARM64::CheckStackGuardState(
1295 Address* return_address, Code* re_code, Address re_frame, int start_index,
1296 const byte** input_start, const byte** input_end) {
1297 return NativeRegExpMacroAssembler::CheckStackGuardState(
1298 frame_entry<Isolate*>(re_frame, kIsolate), start_index,
1299 frame_entry<int>(re_frame, kDirectCall) == 1, return_address, re_code,
1300 frame_entry_address<String*>(re_frame, kInput), input_start, input_end);
1301 }
1302
1303
1304 void RegExpMacroAssemblerARM64::CheckPosition(int cp_offset,
1305 Label* on_outside_input) {
1306 CompareAndBranchOrBacktrack(current_input_offset(),
1307 -cp_offset * char_size(),
1308 ge,
1309 on_outside_input);
1310 }
1311
1312
1313 bool RegExpMacroAssemblerARM64::CanReadUnaligned() {
1314 // TODO(pielan): See whether or not we should disable unaligned accesses.
1315 return !slow_safe();
1316 }
1317
1318
1319 // Private methods:
1320
1321 void RegExpMacroAssemblerARM64::CallCheckStackGuardState(Register scratch) {
1322 // Allocate space on the stack to store the return address. The
1323 // CheckStackGuardState C++ function will override it if the code
1324 // moved. Allocate extra space for 2 arguments passed by pointers.
1325 // AAPCS64 requires the stack to be 16 byte aligned.
1326 int alignment = masm_->ActivationFrameAlignment();
1327 DCHECK_EQ(alignment % 16, 0);
1328 int align_mask = (alignment / kXRegSize) - 1;
1329 int xreg_to_claim = (3 + align_mask) & ~align_mask;
1330
1331 DCHECK(csp.Is(__ StackPointer()));
1332 __ Claim(xreg_to_claim);
1333
1334 // CheckStackGuardState needs the end and start addresses of the input string.
1335 __ Poke(input_end(), 2 * kPointerSize);
1336 __ Add(x5, csp, 2 * kPointerSize);
1337 __ Poke(input_start(), kPointerSize);
1338 __ Add(x4, csp, kPointerSize);
1339
1340 __ Mov(w3, start_offset());
1341 // RegExp code frame pointer.
1342 __ Mov(x2, frame_pointer());
1343 // Code* of self.
1344 __ Mov(x1, Operand(masm_->CodeObject()));
1345
1346 // We need to pass a pointer to the return address as first argument.
1347 // The DirectCEntry stub will place the return address on the stack before
1348 // calling so the stack pointer will point to it.
1349 __ Mov(x0, csp);
1350
1351 ExternalReference check_stack_guard_state =
1352 ExternalReference::re_check_stack_guard_state(isolate());
1353 __ Mov(scratch, check_stack_guard_state);
1354 DirectCEntryStub stub(isolate());
1355 stub.GenerateCall(masm_, scratch);
1356
1357 // The input string may have been moved in memory, we need to reload it.
1358 __ Peek(input_start(), kPointerSize);
1359 __ Peek(input_end(), 2 * kPointerSize);
1360
1361 DCHECK(csp.Is(__ StackPointer()));
1362 __ Drop(xreg_to_claim);
1363
1364 // Reload the Code pointer.
1365 __ Mov(code_pointer(), Operand(masm_->CodeObject()));
1366 }
1367
1368 void RegExpMacroAssemblerARM64::BranchOrBacktrack(Condition condition,
1369 Label* to) {
1370 if (condition == al) { // Unconditional.
1371 if (to == NULL) {
1372 Backtrack();
1373 return;
1374 }
1375 __ B(to);
1376 return;
1377 }
1378 if (to == NULL) {
1379 to = &backtrack_label_;
1380 }
1381 __ B(condition, to);
1382 }
1383
1384 void RegExpMacroAssemblerARM64::CompareAndBranchOrBacktrack(Register reg,
1385 int immediate,
1386 Condition condition,
1387 Label* to) {
1388 if ((immediate == 0) && ((condition == eq) || (condition == ne))) {
1389 if (to == NULL) {
1390 to = &backtrack_label_;
1391 }
1392 if (condition == eq) {
1393 __ Cbz(reg, to);
1394 } else {
1395 __ Cbnz(reg, to);
1396 }
1397 } else {
1398 __ Cmp(reg, immediate);
1399 BranchOrBacktrack(condition, to);
1400 }
1401 }
1402
1403
1404 void RegExpMacroAssemblerARM64::CheckPreemption() {
1405 // Check for preemption.
1406 ExternalReference stack_limit =
1407 ExternalReference::address_of_stack_limit(isolate());
1408 __ Mov(x10, stack_limit);
1409 __ Ldr(x10, MemOperand(x10));
1410 DCHECK(csp.Is(__ StackPointer()));
1411 __ Cmp(csp, x10);
1412 CallIf(&check_preempt_label_, ls);
1413 }
1414
1415
1416 void RegExpMacroAssemblerARM64::CheckStackLimit() {
1417 ExternalReference stack_limit =
1418 ExternalReference::address_of_regexp_stack_limit(isolate());
1419 __ Mov(x10, stack_limit);
1420 __ Ldr(x10, MemOperand(x10));
1421 __ Cmp(backtrack_stackpointer(), x10);
1422 CallIf(&stack_overflow_label_, ls);
1423 }
1424
1425
1426 void RegExpMacroAssemblerARM64::Push(Register source) {
1427 DCHECK(source.Is32Bits());
1428 DCHECK(!source.is(backtrack_stackpointer()));
1429 __ Str(source,
1430 MemOperand(backtrack_stackpointer(),
1431 -static_cast<int>(kWRegSize),
1432 PreIndex));
1433 }
1434
1435
1436 void RegExpMacroAssemblerARM64::Pop(Register target) {
1437 DCHECK(target.Is32Bits());
1438 DCHECK(!target.is(backtrack_stackpointer()));
1439 __ Ldr(target,
1440 MemOperand(backtrack_stackpointer(), kWRegSize, PostIndex));
1441 }
1442
1443
1444 Register RegExpMacroAssemblerARM64::GetCachedRegister(int register_index) {
1445 DCHECK(register_index < kNumCachedRegisters);
1446 return Register::Create(register_index / 2, kXRegSizeInBits);
1447 }
1448
1449
1450 Register RegExpMacroAssemblerARM64::GetRegister(int register_index,
1451 Register maybe_result) {
1452 DCHECK(maybe_result.Is32Bits());
1453 DCHECK(register_index >= 0);
1454 if (num_registers_ <= register_index) {
1455 num_registers_ = register_index + 1;
1456 }
1457 Register result;
1458 RegisterState register_state = GetRegisterState(register_index);
1459 switch (register_state) {
1460 case STACKED:
1461 __ Ldr(maybe_result, register_location(register_index));
1462 result = maybe_result;
1463 break;
1464 case CACHED_LSW:
1465 result = GetCachedRegister(register_index).W();
1466 break;
1467 case CACHED_MSW:
1468 __ Lsr(maybe_result.X(), GetCachedRegister(register_index),
1469 kWRegSizeInBits);
1470 result = maybe_result;
1471 break;
1472 default:
1473 UNREACHABLE();
1474 break;
1475 }
1476 DCHECK(result.Is32Bits());
1477 return result;
1478 }
1479
1480
1481 void RegExpMacroAssemblerARM64::StoreRegister(int register_index,
1482 Register source) {
1483 DCHECK(source.Is32Bits());
1484 DCHECK(register_index >= 0);
1485 if (num_registers_ <= register_index) {
1486 num_registers_ = register_index + 1;
1487 }
1488
1489 Register cached_register;
1490 RegisterState register_state = GetRegisterState(register_index);
1491 switch (register_state) {
1492 case STACKED:
1493 __ Str(source, register_location(register_index));
1494 break;
1495 case CACHED_LSW:
1496 cached_register = GetCachedRegister(register_index);
1497 if (!source.Is(cached_register.W())) {
1498 __ Bfi(cached_register, source.X(), 0, kWRegSizeInBits);
1499 }
1500 break;
1501 case CACHED_MSW:
1502 cached_register = GetCachedRegister(register_index);
1503 __ Bfi(cached_register, source.X(), kWRegSizeInBits, kWRegSizeInBits);
1504 break;
1505 default:
1506 UNREACHABLE();
1507 break;
1508 }
1509 }
1510
1511
1512 void RegExpMacroAssemblerARM64::CallIf(Label* to, Condition condition) {
1513 Label skip_call;
1514 if (condition != al) __ B(&skip_call, NegateCondition(condition));
1515 __ Bl(to);
1516 __ Bind(&skip_call);
1517 }
1518
1519
1520 void RegExpMacroAssemblerARM64::RestoreLinkRegister() {
1521 DCHECK(csp.Is(__ StackPointer()));
1522 __ Pop(lr, xzr);
1523 __ Add(lr, lr, Operand(masm_->CodeObject()));
1524 }
1525
1526
1527 void RegExpMacroAssemblerARM64::SaveLinkRegister() {
1528 DCHECK(csp.Is(__ StackPointer()));
1529 __ Sub(lr, lr, Operand(masm_->CodeObject()));
1530 __ Push(xzr, lr);
1531 }
1532
1533
1534 MemOperand RegExpMacroAssemblerARM64::register_location(int register_index) {
1535 DCHECK(register_index < (1<<30));
1536 DCHECK(register_index >= kNumCachedRegisters);
1537 if (num_registers_ <= register_index) {
1538 num_registers_ = register_index + 1;
1539 }
1540 register_index -= kNumCachedRegisters;
1541 int offset = kFirstRegisterOnStack - register_index * kWRegSize;
1542 return MemOperand(frame_pointer(), offset);
1543 }
1544
1545 MemOperand RegExpMacroAssemblerARM64::capture_location(int register_index,
1546 Register scratch) {
1547 DCHECK(register_index < (1<<30));
1548 DCHECK(register_index < num_saved_registers_);
1549 DCHECK(register_index >= kNumCachedRegisters);
1550 DCHECK_EQ(register_index % 2, 0);
1551 register_index -= kNumCachedRegisters;
1552 int offset = kFirstCaptureOnStack - register_index * kWRegSize;
1553 // capture_location is used with Stp instructions to load/store 2 registers.
1554 // The immediate field in the encoding is limited to 7 bits (signed).
1555 if (is_int7(offset)) {
1556 return MemOperand(frame_pointer(), offset);
1557 } else {
1558 __ Add(scratch, frame_pointer(), offset);
1559 return MemOperand(scratch);
1560 }
1561 }
1562
1563 void RegExpMacroAssemblerARM64::LoadCurrentCharacterUnchecked(int cp_offset,
1564 int characters) {
1565 Register offset = current_input_offset();
1566
1567 // The ldr, str, ldrh, strh instructions can do unaligned accesses, if the CPU
1568 // and the operating system running on the target allow it.
1569 // If unaligned load/stores are not supported then this function must only
1570 // be used to load a single character at a time.
1571
1572 // ARMv8 supports unaligned accesses but V8 or the kernel can decide to
1573 // disable it.
1574 // TODO(pielan): See whether or not we should disable unaligned accesses.
1575 if (!CanReadUnaligned()) {
1576 DCHECK(characters == 1);
1577 }
1578
1579 if (cp_offset != 0) {
1580 if (masm_->emit_debug_code()) {
1581 __ Mov(x10, cp_offset * char_size());
1582 __ Add(x10, x10, Operand(current_input_offset(), SXTW));
1583 __ Cmp(x10, Operand(w10, SXTW));
1584 // The offset needs to fit in a W register.
1585 __ Check(eq, kOffsetOutOfRange);
1586 } else {
1587 __ Add(w10, current_input_offset(), cp_offset * char_size());
1588 }
1589 offset = w10;
1590 }
1591
1592 if (mode_ == LATIN1) {
1593 if (characters == 4) {
1594 __ Ldr(current_character(), MemOperand(input_end(), offset, SXTW));
1595 } else if (characters == 2) {
1596 __ Ldrh(current_character(), MemOperand(input_end(), offset, SXTW));
1597 } else {
1598 DCHECK(characters == 1);
1599 __ Ldrb(current_character(), MemOperand(input_end(), offset, SXTW));
1600 }
1601 } else {
1602 DCHECK(mode_ == UC16);
1603 if (characters == 2) {
1604 __ Ldr(current_character(), MemOperand(input_end(), offset, SXTW));
1605 } else {
1606 DCHECK(characters == 1);
1607 __ Ldrh(current_character(), MemOperand(input_end(), offset, SXTW));
1608 }
1609 }
1610 }
1611
1612 #endif // V8_INTERPRETED_REGEXP
1613
1614 } // namespace internal
1615 } // namespace v8
1616
1617 #endif // V8_TARGET_ARCH_ARM64
OLDNEW
« no previous file with comments | « src/arm64/regexp-macro-assembler-arm64.h ('k') | src/assembler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698