1 // Copyright 2012 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 #if V8_TARGET_ARCH_ARM
6 
7 #include "src/regexp/arm/regexp-macro-assembler-arm.h"
8 
9 #include "src/codegen/arm/assembler-arm-inl.h"
10 #include "src/codegen/macro-assembler.h"
11 #include "src/heap/factory.h"
12 #include "src/logging/log.h"
13 #include "src/objects/code-inl.h"
14 #include "src/regexp/regexp-stack.h"
15 #include "src/snapshot/embedded/embedded-data-inl.h"
16 
17 namespace v8 {
18 namespace internal {
19 
20 /*
21  * This assembler uses the following register assignment convention
22  * - r4 : Temporarily stores the index of capture start after a matching pass
23  *        for a global regexp.
24  * - r5 : Pointer to current Code object including heap object tag.
25  * - r6 : Current position in input, as negative offset from end of string.
26  *        Please notice that this is the byte offset, not the character offset!
27  * - r7 : Currently loaded character. Must be loaded using
28  *        LoadCurrentCharacter before using any of the dispatch methods.
29  * - r8 : Points to tip of backtrack stack
30  * - r9 : Unused, might be used by C code and expected unchanged.
31  * - r10 : End of input (points to byte after last character in input).
32  * - r11 : Frame pointer. Used to access arguments, local variables and
33  *         RegExp registers.
34  * - r12 : IP register, used by assembler. Very volatile.
35  * - r13/sp : Points to tip of C stack.
36  *
37  * The remaining registers are free for computations.
38  * Each call to a public method should retain this convention.
39  *
40  * The stack will have the following structure:
41  *  - fp[52]  Address regexp     (address of the JSRegExp object; unused in
42  *                                native code, passed to match signature of
43  *                                the interpreter)
44  *  - fp[48]  Isolate* isolate   (address of the current isolate)
45  *  - fp[44]  direct_call        (if 1, direct call from JavaScript code,
46  *                                if 0, call through the runtime system).
47  *  - fp[40]  capture array size (may fit multiple sets of matches)
48  *  - fp[36]  int* capture_array (int[num_saved_registers_], for output).
49  *  --- sp when called ---
50  *  - fp[32]  return address     (lr).
51  *  - fp[28]  old frame pointer  (r11).
52  *  - fp[0..24]  backup of registers r4..r10.
53  *  --- frame pointer ----
54  *  - fp[-4]  end of input       (address of end of string).
55  *  - fp[-8]  start of input     (address of first character in string).
56  *  - fp[-12] start index        (character index of start).
57  *  - fp[-16] void* input_string (location of a handle containing the string).
58  *  - fp[-20] success counter    (only for global regexps to count matches).
59  *  - fp[-24] Offset of location before start of input (effectively character
60  *            string start - 1). Used to initialize capture registers to a
61  *            non-position.
62  *  - fp[-28] At start (if 1, we are starting at the start of the
63  *    string, otherwise 0)
64  *  - fp[-32] register 0         (Only positions must be stored in the first
65  *  -         register 1          num_saved_registers_ registers)
66  *  -         ...
67  *  -         register num_registers-1
68  *  --- sp ---
69  *
70  * The first num_saved_registers_ registers are initialized to point to
71  * "character -1" in the string (i.e., char_size() bytes before the first
72  * character of the string). The remaining registers start out as garbage.
73  *
74  * The data up to the return address must be placed there by the calling
75  * code and the remaining arguments are passed in registers, e.g. by calling the
76  * code entry as cast to a function with the signature:
77  * int (*match)(String input_string,
78  *              int start_index,
79  *              Address start,
80  *              Address end,
81  *              int* capture_output_array,
82  *              int num_capture_registers,
83  *              bool direct_call = false,
84  *              Isolate* isolate,
85  *              Address regexp);
86  * The call is performed by NativeRegExpMacroAssembler::Execute()
87  * (in regexp-macro-assembler.cc) via the GeneratedCode wrapper.
88  */
89 
90 #define __ ACCESS_MASM(masm_)
91 
92 const int RegExpMacroAssemblerARM::kRegExpCodeSize;
93 
RegExpMacroAssemblerARM(Isolate* isolate, Zone* zone, Mode mode, int registers_to_save)94 RegExpMacroAssemblerARM::RegExpMacroAssemblerARM(Isolate* isolate, Zone* zone,
95                                                  Mode mode,
96                                                  int registers_to_save)
97     : NativeRegExpMacroAssembler(isolate, zone),
98       masm_(std::make_unique<MacroAssembler>(
99           isolate, CodeObjectRequired::kYes,
100           NewAssemblerBuffer(kRegExpCodeSize))),
101       no_root_array_scope_(masm_.get()),
102       mode_(mode),
103       num_registers_(registers_to_save),
104       num_saved_registers_(registers_to_save),
105       entry_label_(),
106       start_label_(),
107       success_label_(),
108       backtrack_label_(),
109       exit_label_() {
110   DCHECK_EQ(0, registers_to_save % 2);
111   __ jmp(&entry_label_);   // We'll write the entry code later.
112   __ bind(&start_label_);  // And then continue from here.
113 }
114 
115 RegExpMacroAssemblerARM::~RegExpMacroAssemblerARM() = default;
116 
AbortedCodeGeneration()117 void RegExpMacroAssemblerARM::AbortedCodeGeneration() {
118   masm_->AbortedCodeGeneration();
119   // Unuse labels in case we throw away the assembler without calling GetCode.
120   entry_label_.Unuse();
121   start_label_.Unuse();
122   success_label_.Unuse();
123   backtrack_label_.Unuse();
124   exit_label_.Unuse();
125   check_preempt_label_.Unuse();
126   stack_overflow_label_.Unuse();
127   fallback_label_.Unuse();
128 }
129 
stack_limit_slack()130 int RegExpMacroAssemblerARM::stack_limit_slack()  {
131   return RegExpStack::kStackLimitSlack;
132 }
133 
134 
AdvanceCurrentPosition(int by)135 void RegExpMacroAssemblerARM::AdvanceCurrentPosition(int by) {
136   if (by != 0) {
137     __ add(current_input_offset(),
138            current_input_offset(), Operand(by * char_size()));
139   }
140 }
141 
142 
AdvanceRegister(int reg, int by)143 void RegExpMacroAssemblerARM::AdvanceRegister(int reg, int by) {
144   DCHECK_LE(0, reg);
145   DCHECK_GT(num_registers_, reg);
146   if (by != 0) {
147     __ ldr(r0, register_location(reg));
148     __ add(r0, r0, Operand(by));
149     __ str(r0, register_location(reg));
150   }
151 }
152 
153 
Backtrack()154 void RegExpMacroAssemblerARM::Backtrack() {
155   CheckPreemption();
156   if (has_backtrack_limit()) {
157     Label next;
158     __ ldr(r0, MemOperand(frame_pointer(), kBacktrackCount));
159     __ add(r0, r0, Operand(1));
160     __ str(r0, MemOperand(frame_pointer(), kBacktrackCount));
161     __ cmp(r0, Operand(backtrack_limit()));
162     __ b(ne, &next);
163 
164     // Backtrack limit exceeded.
165     if (can_fallback()) {
166       __ jmp(&fallback_label_);
167     } else {
168       // Can't fallback, so we treat it as a failed match.
169       Fail();
170     }
171 
172     __ bind(&next);
173   }
174   // Pop Code offset from backtrack stack, add Code and jump to location.
175   Pop(r0);
176   __ add(pc, r0, Operand(code_pointer()));
177 }
178 
179 
Bind(Label* label)180 void RegExpMacroAssemblerARM::Bind(Label* label) {
181   __ bind(label);
182 }
183 
184 
CheckCharacter(uint32_t c, Label* on_equal)185 void RegExpMacroAssemblerARM::CheckCharacter(uint32_t c, Label* on_equal) {
186   __ cmp(current_character(), Operand(c));
187   BranchOrBacktrack(eq, on_equal);
188 }
189 
CheckCharacterGT(base::uc16 limit, Label* on_greater)190 void RegExpMacroAssemblerARM::CheckCharacterGT(base::uc16 limit,
191                                                Label* on_greater) {
192   __ cmp(current_character(), Operand(limit));
193   BranchOrBacktrack(gt, on_greater);
194 }
195 
CheckAtStart(int cp_offset, Label* on_at_start)196 void RegExpMacroAssemblerARM::CheckAtStart(int cp_offset, Label* on_at_start) {
197   __ ldr(r1, MemOperand(frame_pointer(), kStringStartMinusOne));
198   __ add(r0, current_input_offset(),
199          Operand(-char_size() + cp_offset * char_size()));
200   __ cmp(r0, r1);
201   BranchOrBacktrack(eq, on_at_start);
202 }
203 
CheckNotAtStart(int cp_offset, Label* on_not_at_start)204 void RegExpMacroAssemblerARM::CheckNotAtStart(int cp_offset,
205                                               Label* on_not_at_start) {
206   __ ldr(r1, MemOperand(frame_pointer(), kStringStartMinusOne));
207   __ add(r0, current_input_offset(),
208          Operand(-char_size() + cp_offset * char_size()));
209   __ cmp(r0, r1);
210   BranchOrBacktrack(ne, on_not_at_start);
211 }
212 
CheckCharacterLT(base::uc16 limit, Label* on_less)213 void RegExpMacroAssemblerARM::CheckCharacterLT(base::uc16 limit,
214                                                Label* on_less) {
215   __ cmp(current_character(), Operand(limit));
216   BranchOrBacktrack(lt, on_less);
217 }
218 
CheckGreedyLoop(Label* on_equal)219 void RegExpMacroAssemblerARM::CheckGreedyLoop(Label* on_equal) {
220   __ ldr(r0, MemOperand(backtrack_stackpointer(), 0));
221   __ cmp(current_input_offset(), r0);
222   __ add(backtrack_stackpointer(),
223          backtrack_stackpointer(), Operand(kPointerSize), LeaveCC, eq);
224   BranchOrBacktrack(eq, on_equal);
225 }
226 
CheckNotBackReferenceIgnoreCase( int start_reg, bool read_backward, bool unicode, Label* on_no_match)227 void RegExpMacroAssemblerARM::CheckNotBackReferenceIgnoreCase(
228     int start_reg, bool read_backward, bool unicode, Label* on_no_match) {
229   Label fallthrough;
230   __ ldr(r0, register_location(start_reg));  // Index of start of capture
231   __ ldr(r1, register_location(start_reg + 1));  // Index of end of capture
232   __ sub(r1, r1, r0, SetCC);  // Length of capture.
233 
234   // At this point, the capture registers are either both set or both cleared.
235   // If the capture length is zero, then the capture is either empty or cleared.
236   // Fall through in both cases.
237   __ b(eq, &fallthrough);
238 
239   // Check that there are enough characters left in the input.
240   if (read_backward) {
241     __ ldr(r3, MemOperand(frame_pointer(), kStringStartMinusOne));
242     __ add(r3, r3, r1);
243     __ cmp(current_input_offset(), r3);
244     BranchOrBacktrack(le, on_no_match);
245   } else {
246     __ cmn(r1, Operand(current_input_offset()));
247     BranchOrBacktrack(gt, on_no_match);
248   }
249 
250   if (mode_ == LATIN1) {
251     Label success;
252     Label fail;
253     Label loop_check;
254 
255     // r0 - offset of start of capture
256     // r1 - length of capture
257     __ add(r0, r0, end_of_input_address());
258     __ add(r2, end_of_input_address(), current_input_offset());
259     if (read_backward) {
260       __ sub(r2, r2, r1);  // Offset by length when matching backwards.
261     }
262     __ add(r1, r0, r1);
263 
264     // r0 - Address of start of capture.
265     // r1 - Address of end of capture
266     // r2 - Address of current input position.
267 
268     Label loop;
269     __ bind(&loop);
270     __ ldrb(r3, MemOperand(r0, char_size(), PostIndex));
271     __ ldrb(r4, MemOperand(r2, char_size(), PostIndex));
272     __ cmp(r4, r3);
273     __ b(eq, &loop_check);
274 
275     // Mismatch, try case-insensitive match (converting letters to lower-case).
276     __ orr(r3, r3, Operand(0x20));  // Convert capture character to lower-case.
277     __ orr(r4, r4, Operand(0x20));  // Also convert input character.
278     __ cmp(r4, r3);
279     __ b(ne, &fail);
280     __ sub(r3, r3, Operand('a'));
281     __ cmp(r3, Operand('z' - 'a'));  // Is r3 a lowercase letter?
282     __ b(ls, &loop_check);  // In range 'a'-'z'.
283     // Latin-1: Check for values in range [224,254] but not 247.
284     __ sub(r3, r3, Operand(224 - 'a'));
285     __ cmp(r3, Operand(254 - 224));
286     __ b(hi, &fail);  // Weren't Latin-1 letters.
287     __ cmp(r3, Operand(247 - 224));  // Check for 247.
288     __ b(eq, &fail);
289 
290     __ bind(&loop_check);
291     __ cmp(r0, r1);
292     __ b(lt, &loop);
293     __ jmp(&success);
294 
295     __ bind(&fail);
296     BranchOrBacktrack(al, on_no_match);
297 
298     __ bind(&success);
299     // Compute new value of character position after the matched part.
300     __ sub(current_input_offset(), r2, end_of_input_address());
301     if (read_backward) {
302       __ ldr(r0, register_location(start_reg));  // Index of start of capture
303       __ ldr(r1, register_location(start_reg + 1));  // Index of end of capture
304       __ add(current_input_offset(), current_input_offset(), r0);
305       __ sub(current_input_offset(), current_input_offset(), r1);
306     }
307   } else {
308     DCHECK(mode_ == UC16);
309     int argument_count = 4;
310     __ PrepareCallCFunction(argument_count);
311 
312     // r0 - offset of start of capture
313     // r1 - length of capture
314 
315     // Put arguments into arguments registers.
316     // Parameters are
317     //   r0: Address byte_offset1 - Address captured substring's start.
318     //   r1: Address byte_offset2 - Address of current character position.
319     //   r2: size_t byte_length - length of capture in bytes(!)
320     //   r3: Isolate* isolate.
321 
322     // Address of start of capture.
323     __ add(r0, r0, Operand(end_of_input_address()));
324     // Length of capture.
325     __ mov(r2, Operand(r1));
326     // Save length in callee-save register for use on return.
327     __ mov(r4, Operand(r1));
328     // Address of current input position.
329     __ add(r1, current_input_offset(), end_of_input_address());
330     if (read_backward) {
331       __ sub(r1, r1, r4);
332     }
333     // Isolate.
334     __ mov(r3, Operand(ExternalReference::isolate_address(isolate())));
335 
336     {
337       AllowExternalCallThatCantCauseGC scope(masm_.get());
338       ExternalReference function =
339           unicode
340               ? ExternalReference::re_case_insensitive_compare_unicode()
341               : ExternalReference::re_case_insensitive_compare_non_unicode();
342       __ CallCFunction(function, argument_count);
343     }
344 
345     // Check if function returned non-zero for success or zero for failure.
346     __ cmp(r0, Operand::Zero());
347     BranchOrBacktrack(eq, on_no_match);
348 
349     // On success, advance position by length of capture.
350     if (read_backward) {
351       __ sub(current_input_offset(), current_input_offset(), r4);
352     } else {
353       __ add(current_input_offset(), current_input_offset(), r4);
354     }
355   }
356 
357   __ bind(&fallthrough);
358 }
359 
CheckNotBackReference(int start_reg, bool read_backward, Label* on_no_match)360 void RegExpMacroAssemblerARM::CheckNotBackReference(int start_reg,
361                                                     bool read_backward,
362                                                     Label* on_no_match) {
363   Label fallthrough;
364 
365   // Find length of back-referenced capture.
366   __ ldr(r0, register_location(start_reg));
367   __ ldr(r1, register_location(start_reg + 1));
368   __ sub(r1, r1, r0, SetCC);  // Length to check.
369 
370   // At this point, the capture registers are either both set or both cleared.
371   // If the capture length is zero, then the capture is either empty or cleared.
372   // Fall through in both cases.
373   __ b(eq, &fallthrough);
374 
375   // Check that there are enough characters left in the input.
376   if (read_backward) {
377     __ ldr(r3, MemOperand(frame_pointer(), kStringStartMinusOne));
378     __ add(r3, r3, r1);
379     __ cmp(current_input_offset(), r3);
380     BranchOrBacktrack(le, on_no_match);
381   } else {
382     __ cmn(r1, Operand(current_input_offset()));
383     BranchOrBacktrack(gt, on_no_match);
384   }
385 
386   // r0 - offset of start of capture
387   // r1 - length of capture
388   __ add(r0, r0, end_of_input_address());
389   __ add(r2, end_of_input_address(), current_input_offset());
390   if (read_backward) {
391     __ sub(r2, r2, r1);  // Offset by length when matching backwards.
392   }
393   __ add(r1, r0, r1);
394 
395   Label loop;
396   __ bind(&loop);
397   if (mode_ == LATIN1) {
398     __ ldrb(r3, MemOperand(r0, char_size(), PostIndex));
399     __ ldrb(r4, MemOperand(r2, char_size(), PostIndex));
400   } else {
401     DCHECK(mode_ == UC16);
402     __ ldrh(r3, MemOperand(r0, char_size(), PostIndex));
403     __ ldrh(r4, MemOperand(r2, char_size(), PostIndex));
404   }
405   __ cmp(r3, r4);
406   BranchOrBacktrack(ne, on_no_match);
407   __ cmp(r0, r1);
408   __ b(lt, &loop);
409 
410   // Move current character position to position after match.
411   __ sub(current_input_offset(), r2, end_of_input_address());
412   if (read_backward) {
413     __ ldr(r0, register_location(start_reg));      // Index of start of capture
414     __ ldr(r1, register_location(start_reg + 1));  // Index of end of capture
415     __ add(current_input_offset(), current_input_offset(), r0);
416     __ sub(current_input_offset(), current_input_offset(), r1);
417   }
418 
419   __ bind(&fallthrough);
420 }
421 
422 
CheckNotCharacter(unsigned c, Label* on_not_equal)423 void RegExpMacroAssemblerARM::CheckNotCharacter(unsigned c,
424                                                 Label* on_not_equal) {
425   __ cmp(current_character(), Operand(c));
426   BranchOrBacktrack(ne, on_not_equal);
427 }
428 
429 
CheckCharacterAfterAnd(uint32_t c, uint32_t mask, Label* on_equal)430 void RegExpMacroAssemblerARM::CheckCharacterAfterAnd(uint32_t c,
431                                                      uint32_t mask,
432                                                      Label* on_equal) {
433   if (c == 0) {
434     __ tst(current_character(), Operand(mask));
435   } else {
436     __ and_(r0, current_character(), Operand(mask));
437     __ cmp(r0, Operand(c));
438   }
439   BranchOrBacktrack(eq, on_equal);
440 }
441 
442 
CheckNotCharacterAfterAnd(unsigned c, unsigned mask, Label* on_not_equal)443 void RegExpMacroAssemblerARM::CheckNotCharacterAfterAnd(unsigned c,
444                                                         unsigned mask,
445                                                         Label* on_not_equal) {
446   if (c == 0) {
447     __ tst(current_character(), Operand(mask));
448   } else {
449     __ and_(r0, current_character(), Operand(mask));
450     __ cmp(r0, Operand(c));
451   }
452   BranchOrBacktrack(ne, on_not_equal);
453 }
454 
CheckNotCharacterAfterMinusAnd( base::uc16 c, base::uc16 minus, base::uc16 mask, Label* on_not_equal)455 void RegExpMacroAssemblerARM::CheckNotCharacterAfterMinusAnd(
456     base::uc16 c, base::uc16 minus, base::uc16 mask, Label* on_not_equal) {
457   DCHECK_GT(String::kMaxUtf16CodeUnit, minus);
458   __ sub(r0, current_character(), Operand(minus));
459   __ and_(r0, r0, Operand(mask));
460   __ cmp(r0, Operand(c));
461   BranchOrBacktrack(ne, on_not_equal);
462 }
463 
CheckCharacterInRange(base::uc16 from, base::uc16 to, Label* on_in_range)464 void RegExpMacroAssemblerARM::CheckCharacterInRange(base::uc16 from,
465                                                     base::uc16 to,
466                                                     Label* on_in_range) {
467   __ sub(r0, current_character(), Operand(from));
468   __ cmp(r0, Operand(to - from));
469   BranchOrBacktrack(ls, on_in_range);  // Unsigned lower-or-same condition.
470 }
471 
CheckCharacterNotInRange(base::uc16 from, base::uc16 to, Label* on_not_in_range)472 void RegExpMacroAssemblerARM::CheckCharacterNotInRange(base::uc16 from,
473                                                        base::uc16 to,
474                                                        Label* on_not_in_range) {
475   __ sub(r0, current_character(), Operand(from));
476   __ cmp(r0, Operand(to - from));
477   BranchOrBacktrack(hi, on_not_in_range);  // Unsigned higher condition.
478 }
479 
CallIsCharacterInRangeArray( const ZoneList<CharacterRange>* ranges)480 void RegExpMacroAssemblerARM::CallIsCharacterInRangeArray(
481     const ZoneList<CharacterRange>* ranges) {
482   static const int kNumArguments = 3;
483   __ PrepareCallCFunction(kNumArguments);
484 
485   __ mov(r0, current_character());
486   __ mov(r1, Operand(GetOrAddRangeArray(ranges)));
487   __ mov(r2, Operand(ExternalReference::isolate_address(isolate())));
488 
489   {
490     // We have a frame (set up in GetCode), but the assembler doesn't know.
491     FrameScope scope(masm_.get(), StackFrame::MANUAL);
492     __ CallCFunction(ExternalReference::re_is_character_in_range_array(),
493                      kNumArguments);
494   }
495 
496   __ mov(code_pointer(), Operand(masm_->CodeObject()));
497 }
498 
CheckCharacterInRangeArray( const ZoneList<CharacterRange>* ranges, Label* on_in_range)499 bool RegExpMacroAssemblerARM::CheckCharacterInRangeArray(
500     const ZoneList<CharacterRange>* ranges, Label* on_in_range) {
501   CallIsCharacterInRangeArray(ranges);
502   __ cmp(r0, Operand::Zero());
503   BranchOrBacktrack(ne, on_in_range);
504   return true;
505 }
506 
CheckCharacterNotInRangeArray( const ZoneList<CharacterRange>* ranges, Label* on_not_in_range)507 bool RegExpMacroAssemblerARM::CheckCharacterNotInRangeArray(
508     const ZoneList<CharacterRange>* ranges, Label* on_not_in_range) {
509   CallIsCharacterInRangeArray(ranges);
510   __ cmp(r0, Operand::Zero());
511   BranchOrBacktrack(eq, on_not_in_range);
512   return true;
513 }
514 
CheckBitInTable( Handle<ByteArray> table, Label* on_bit_set)515 void RegExpMacroAssemblerARM::CheckBitInTable(
516     Handle<ByteArray> table,
517     Label* on_bit_set) {
518   __ mov(r0, Operand(table));
519   if (mode_ != LATIN1 || kTableMask != String::kMaxOneByteCharCode) {
520     __ and_(r1, current_character(), Operand(kTableSize - 1));
521     __ add(r1, r1, Operand(ByteArray::kHeaderSize - kHeapObjectTag));
522   } else {
523     __ add(r1,
524            current_character(),
525            Operand(ByteArray::kHeaderSize - kHeapObjectTag));
526   }
527   __ ldrb(r0, MemOperand(r0, r1));
528   __ cmp(r0, Operand::Zero());
529   BranchOrBacktrack(ne, on_bit_set);
530 }
531 
CheckSpecialCharacterClass( StandardCharacterSet type, Label* on_no_match)532 bool RegExpMacroAssemblerARM::CheckSpecialCharacterClass(
533     StandardCharacterSet type, Label* on_no_match) {
534   // Range checks (c in min..max) are generally implemented by an unsigned
535   // (c - min) <= (max - min) check
536   // TODO(jgruber): No custom implementation (yet): s(UC16), S(UC16).
537   switch (type) {
538     case StandardCharacterSet::kWhitespace:
539       // Match space-characters.
540       if (mode_ == LATIN1) {
541         // One byte space characters are '\t'..'\r', ' ' and \u00a0.
542         Label success;
543         __ cmp(current_character(), Operand(' '));
544         __ b(eq, &success);
545         // Check range 0x09..0x0D.
546         __ sub(r0, current_character(), Operand('\t'));
547         __ cmp(r0, Operand('\r' - '\t'));
548         __ b(ls, &success);
549         // \u00a0 (NBSP).
550         __ cmp(r0, Operand(0x00A0 - '\t'));
551         BranchOrBacktrack(ne, on_no_match);
552         __ bind(&success);
553         return true;
554       }
555       return false;
556     case StandardCharacterSet::kNotWhitespace:
557       // The emitted code for generic character classes is good enough.
558       return false;
559     case StandardCharacterSet::kDigit:
560       // Match ASCII digits ('0'..'9')
561       __ sub(r0, current_character(), Operand('0'));
562       __ cmp(r0, Operand('9' - '0'));
563       BranchOrBacktrack(hi, on_no_match);
564       return true;
565     case StandardCharacterSet::kNotDigit:
566       // Match non ASCII-digits
567       __ sub(r0, current_character(), Operand('0'));
568       __ cmp(r0, Operand('9' - '0'));
569       BranchOrBacktrack(ls, on_no_match);
570       return true;
571     case StandardCharacterSet::kNotLineTerminator: {
572       // Match non-newlines (not 0x0A('\n'), 0x0D('\r'), 0x2028 and 0x2029)
573       __ eor(r0, current_character(), Operand(0x01));
574       // See if current character is '\n'^1 or '\r'^1, i.e., 0x0B or 0x0C
575       __ sub(r0, r0, Operand(0x0B));
576       __ cmp(r0, Operand(0x0C - 0x0B));
577       BranchOrBacktrack(ls, on_no_match);
578       if (mode_ == UC16) {
579         // Compare original value to 0x2028 and 0x2029, using the already
580         // computed (current_char ^ 0x01 - 0x0B). I.e., check for
581         // 0x201D (0x2028 - 0x0B) or 0x201E.
582         __ sub(r0, r0, Operand(0x2028 - 0x0B));
583         __ cmp(r0, Operand(1));
584         BranchOrBacktrack(ls, on_no_match);
585       }
586       return true;
587     }
588     case StandardCharacterSet::kLineTerminator: {
589       // Match newlines (0x0A('\n'), 0x0D('\r'), 0x2028 and 0x2029)
590       __ eor(r0, current_character(), Operand(0x01));
591       // See if current character is '\n'^1 or '\r'^1, i.e., 0x0B or 0x0C
592       __ sub(r0, r0, Operand(0x0B));
593       __ cmp(r0, Operand(0x0C - 0x0B));
594       if (mode_ == LATIN1) {
595         BranchOrBacktrack(hi, on_no_match);
596       } else {
597         Label done;
598         __ b(ls, &done);
599         // Compare original value to 0x2028 and 0x2029, using the already
600         // computed (current_char ^ 0x01 - 0x0B). I.e., check for
601         // 0x201D (0x2028 - 0x0B) or 0x201E.
602         __ sub(r0, r0, Operand(0x2028 - 0x0B));
603         __ cmp(r0, Operand(1));
604         BranchOrBacktrack(hi, on_no_match);
605         __ bind(&done);
606       }
607       return true;
608     }
609     case StandardCharacterSet::kWord: {
610       if (mode_ != LATIN1) {
611         // Table is 256 entries, so all Latin1 characters can be tested.
612         __ cmp(current_character(), Operand('z'));
613         BranchOrBacktrack(hi, on_no_match);
614       }
615       ExternalReference map = ExternalReference::re_word_character_map();
616       __ mov(r0, Operand(map));
617       __ ldrb(r0, MemOperand(r0, current_character()));
618       __ cmp(r0, Operand::Zero());
619       BranchOrBacktrack(eq, on_no_match);
620       return true;
621     }
622     case StandardCharacterSet::kNotWord: {
623       Label done;
624       if (mode_ != LATIN1) {
625         // Table is 256 entries, so all Latin1 characters can be tested.
626         __ cmp(current_character(), Operand('z'));
627         __ b(hi, &done);
628       }
629       ExternalReference map = ExternalReference::re_word_character_map();
630       __ mov(r0, Operand(map));
631       __ ldrb(r0, MemOperand(r0, current_character()));
632       __ cmp(r0, Operand::Zero());
633       BranchOrBacktrack(ne, on_no_match);
634       if (mode_ != LATIN1) {
635         __ bind(&done);
636       }
637       return true;
638     }
639     case StandardCharacterSet::kEverything:
640       // Match any character.
641       return true;
642   }
643 }
644 
Fail()645 void RegExpMacroAssemblerARM::Fail() {
646   __ mov(r0, Operand(FAILURE));
647   __ jmp(&exit_label_);
648 }
649 
LoadRegExpStackPointerFromMemory(Register dst)650 void RegExpMacroAssemblerARM::LoadRegExpStackPointerFromMemory(Register dst) {
651   ExternalReference ref =
652       ExternalReference::address_of_regexp_stack_stack_pointer(isolate());
653   __ mov(dst, Operand(ref));
654   __ ldr(dst, MemOperand(dst));
655 }
656 
StoreRegExpStackPointerToMemory( Register src, Register scratch)657 void RegExpMacroAssemblerARM::StoreRegExpStackPointerToMemory(
658     Register src, Register scratch) {
659   ExternalReference ref =
660       ExternalReference::address_of_regexp_stack_stack_pointer(isolate());
661   __ mov(scratch, Operand(ref));
662   __ str(src, MemOperand(scratch));
663 }
664 
PushRegExpBasePointer(Register stack_pointer, Register scratch)665 void RegExpMacroAssemblerARM::PushRegExpBasePointer(Register stack_pointer,
666                                                     Register scratch) {
667   ExternalReference ref =
668       ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
669   __ mov(scratch, Operand(ref));
670   __ ldr(scratch, MemOperand(scratch));
671   __ sub(scratch, stack_pointer, scratch);
672   __ str(scratch, MemOperand(frame_pointer(), kRegExpStackBasePointer));
673 }
674 
PopRegExpBasePointer(Register stack_pointer_out, Register scratch)675 void RegExpMacroAssemblerARM::PopRegExpBasePointer(Register stack_pointer_out,
676                                                    Register scratch) {
677   ExternalReference ref =
678       ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
679   __ ldr(stack_pointer_out,
680          MemOperand(frame_pointer(), kRegExpStackBasePointer));
681   __ mov(scratch, Operand(ref));
682   __ ldr(scratch, MemOperand(scratch));
683   __ add(stack_pointer_out, stack_pointer_out, scratch);
684   StoreRegExpStackPointerToMemory(stack_pointer_out, scratch);
685 }
686 
GetCode(Handle<String> source)687 Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
688   Label return_r0;
689   // Finalize code - write the entry point code now we know how many
690   // registers we need.
691 
692   // Entry code:
693   __ bind(&entry_label_);
694 
695   // Tell the system that we have a stack frame.  Because the type is MANUAL, no
696   // is generated.
697   FrameScope scope(masm_.get(), StackFrame::MANUAL);
698 
699   // Actually emit code to start a new stack frame.
700   // Push arguments
701   // Save callee-save registers.
702   // Start new stack frame.
703   // Store link register in existing stack-cell.
704   // Order here should correspond to order of offset constants in header file.
705   RegList registers_to_retain = {r4, r5, r6, r7, r8, r9, r10, fp};
706   RegList argument_registers = {r0, r1, r2, r3};
707   __ stm(db_w, sp, argument_registers | registers_to_retain | lr);
708   // Set frame pointer in space for it if this is not a direct call
709   // from generated code.
710   __ add(frame_pointer(), sp, Operand(4 * kPointerSize));
711 
712   STATIC_ASSERT(kSuccessfulCaptures == kInputString - kSystemPointerSize);
713   __ mov(r0, Operand::Zero());
714   __ push(r0);  // Make room for success counter and initialize it to 0.
715   STATIC_ASSERT(kStringStartMinusOne ==
716                 kSuccessfulCaptures - kSystemPointerSize);
717   __ push(r0);  // Make room for "string start - 1" constant.
718   STATIC_ASSERT(kBacktrackCount == kStringStartMinusOne - kSystemPointerSize);
719   __ push(r0);  // The backtrack counter.
720   STATIC_ASSERT(kRegExpStackBasePointer ==
721                 kBacktrackCount - kSystemPointerSize);
722   __ push(r0);  // The regexp stack base ptr.
723 
724   // Initialize backtrack stack pointer. It must not be clobbered from here on.
725   // Note the backtrack_stackpointer is callee-saved.
726   STATIC_ASSERT(backtrack_stackpointer() == r8);
727   LoadRegExpStackPointerFromMemory(backtrack_stackpointer());
728 
729   // Store the regexp base pointer - we'll later restore it / write it to
730   // memory when returning from this irregexp code object.
731   PushRegExpBasePointer(backtrack_stackpointer(), r1);
732 
733   {
734     // Check if we have space on the stack for registers.
735     Label stack_limit_hit, stack_ok;
736 
737     ExternalReference stack_limit =
738         ExternalReference::address_of_jslimit(isolate());
739     __ mov(r0, Operand(stack_limit));
740     __ ldr(r0, MemOperand(r0));
741     __ sub(r0, sp, r0, SetCC);
742     // Handle it if the stack pointer is already below the stack limit.
743     __ b(ls, &stack_limit_hit);
744     // Check if there is room for the variable number of registers above
745     // the stack limit.
746     __ cmp(r0, Operand(num_registers_ * kPointerSize));
747     __ b(hs, &stack_ok);
748     // Exit with OutOfMemory exception. There is not enough space on the stack
749     // for our working registers.
750     __ mov(r0, Operand(EXCEPTION));
751     __ jmp(&return_r0);
752 
753     __ bind(&stack_limit_hit);
754     CallCheckStackGuardState();
755     __ cmp(r0, Operand::Zero());
756     // If returned value is non-zero, we exit with the returned value as result.
757     __ b(ne, &return_r0);
758 
759     __ bind(&stack_ok);
760   }
761 
762   // Allocate space on stack for registers.
763   __ AllocateStackSpace(num_registers_ * kPointerSize);
764   // Load string end.
765   __ ldr(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
766   // Load input start.
767   __ ldr(r0, MemOperand(frame_pointer(), kInputStart));
768   // Find negative length (offset of start relative to end).
769   __ sub(current_input_offset(), r0, end_of_input_address());
770   // Set r0 to address of char before start of the input string
771   // (effectively string position -1).
772   __ ldr(r1, MemOperand(frame_pointer(), kStartIndex));
773   __ sub(r0, current_input_offset(), Operand(char_size()));
774   __ sub(r0, r0, Operand(r1, LSL, (mode_ == UC16) ? 1 : 0));
775   // Store this value in a local variable, for use when clearing
776   // position registers.
777   __ str(r0, MemOperand(frame_pointer(), kStringStartMinusOne));
778 
779   // Initialize code pointer register
780   __ mov(code_pointer(), Operand(masm_->CodeObject()));
781 
782   Label load_char_start_regexp;
783   {
784     Label start_regexp;
785     // Load newline if index is at start, previous character otherwise.
786     __ cmp(r1, Operand::Zero());
787     __ b(ne, &load_char_start_regexp);
788     __ mov(current_character(), Operand('\n'), LeaveCC, eq);
789     __ jmp(&start_regexp);
790 
791     // Global regexp restarts matching here.
792     __ bind(&load_char_start_regexp);
793     // Load previous char as initial value of current character register.
794     LoadCurrentCharacterUnchecked(-1, 1);
795     __ bind(&start_regexp);
796   }
797 
798   // Initialize on-stack registers.
799   if (num_saved_registers_ > 0) {  // Always is, if generated from a regexp.
800     // Fill saved registers with initial value = start offset - 1
801     if (num_saved_registers_ > 8) {
802       // Address of register 0.
803       __ add(r1, frame_pointer(), Operand(kRegisterZero));
804       __ mov(r2, Operand(num_saved_registers_));
805       Label init_loop;
806       __ bind(&init_loop);
807       __ str(r0, MemOperand(r1, kPointerSize, NegPostIndex));
808       __ sub(r2, r2, Operand(1), SetCC);
809       __ b(ne, &init_loop);
810     } else {
811       for (int i = 0; i < num_saved_registers_; i++) {
812         __ str(r0, register_location(i));
813       }
814     }
815   }
816 
817   __ jmp(&start_label_);
818 
819   // Exit code:
820   if (success_label_.is_linked()) {
821     // Save captures when successful.
822     __ bind(&success_label_);
823     if (num_saved_registers_ > 0) {
824       // copy captures to output
825       __ ldr(r1, MemOperand(frame_pointer(), kInputStart));
826       __ ldr(r0, MemOperand(frame_pointer(), kRegisterOutput));
827       __ ldr(r2, MemOperand(frame_pointer(), kStartIndex));
828       __ sub(r1, end_of_input_address(), r1);
829       // r1 is length of input in bytes.
830       if (mode_ == UC16) {
831         __ mov(r1, Operand(r1, LSR, 1));
832       }
833       // r1 is length of input in characters.
834       __ add(r1, r1, Operand(r2));
835       // r1 is length of string in characters.
836 
837       DCHECK_EQ(0, num_saved_registers_ % 2);
838       // Always an even number of capture registers. This allows us to
839       // unroll the loop once to add an operation between a load of a register
840       // and the following use of that register.
841       for (int i = 0; i < num_saved_registers_; i += 2) {
842         __ ldr(r2, register_location(i));
843         __ ldr(r3, register_location(i + 1));
844         if (i == 0 && global_with_zero_length_check()) {
845           // Keep capture start in r4 for the zero-length check later.
846           __ mov(r4, r2);
847         }
848         if (mode_ == UC16) {
849           __ add(r2, r1, Operand(r2, ASR, 1));
850           __ add(r3, r1, Operand(r3, ASR, 1));
851         } else {
852           __ add(r2, r1, Operand(r2));
853           __ add(r3, r1, Operand(r3));
854         }
855         __ str(r2, MemOperand(r0, kPointerSize, PostIndex));
856         __ str(r3, MemOperand(r0, kPointerSize, PostIndex));
857       }
858     }
859 
860     if (global()) {
861       // Restart matching if the regular expression is flagged as global.
862       __ ldr(r0, MemOperand(frame_pointer(), kSuccessfulCaptures));
863       __ ldr(r1, MemOperand(frame_pointer(), kNumOutputRegisters));
864       __ ldr(r2, MemOperand(frame_pointer(), kRegisterOutput));
865       // Increment success counter.
866       __ add(r0, r0, Operand(1));
867       __ str(r0, MemOperand(frame_pointer(), kSuccessfulCaptures));
868       // Capture results have been stored, so the number of remaining global
869       // output registers is reduced by the number of stored captures.
870       __ sub(r1, r1, Operand(num_saved_registers_));
871       // Check whether we have enough room for another set of capture results.
872       __ cmp(r1, Operand(num_saved_registers_));
873       __ b(lt, &return_r0);
874 
875       __ str(r1, MemOperand(frame_pointer(), kNumOutputRegisters));
876       // Advance the location for output.
877       __ add(r2, r2, Operand(num_saved_registers_ * kPointerSize));
878       __ str(r2, MemOperand(frame_pointer(), kRegisterOutput));
879 
880       // Prepare r0 to initialize registers with its value in the next run.
881       __ ldr(r0, MemOperand(frame_pointer(), kStringStartMinusOne));
882 
883       // Restore the original regexp stack pointer value (effectively, pop the
884       // stored base pointer).
885       PopRegExpBasePointer(backtrack_stackpointer(), r2);
886 
887       if (global_with_zero_length_check()) {
888         // Special case for zero-length matches.
889         // r4: capture start index
890         __ cmp(current_input_offset(), r4);
891         // Not a zero-length match, restart.
892         __ b(ne, &load_char_start_regexp);
893         // Offset from the end is zero if we already reached the end.
894         __ cmp(current_input_offset(), Operand::Zero());
895         __ b(eq, &exit_label_);
896         // Advance current position after a zero-length match.
897         Label advance;
898         __ bind(&advance);
899         __ add(current_input_offset(), current_input_offset(),
900                Operand((mode_ == UC16) ? 2 : 1));
901         if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
902       }
903 
904       __ b(&load_char_start_regexp);
905     } else {
906       __ mov(r0, Operand(SUCCESS));
907     }
908   }
909 
910   // Exit and return r0
911   __ bind(&exit_label_);
912   if (global()) {
913     __ ldr(r0, MemOperand(frame_pointer(), kSuccessfulCaptures));
914   }
915 
916   __ bind(&return_r0);
917   // Restore the original regexp stack pointer value (effectively, pop the
918   // stored base pointer).
919   PopRegExpBasePointer(backtrack_stackpointer(), r2);
920 
921   // Skip sp past regexp registers and local variables..
922   __ mov(sp, frame_pointer());
923   // Restore registers r4..r11 and return (restoring lr to pc).
924   __ ldm(ia_w, sp, registers_to_retain | pc);
925 
926   // Backtrack code (branch target for conditional backtracks).
927   if (backtrack_label_.is_linked()) {
928     __ bind(&backtrack_label_);
929     Backtrack();
930   }
931 
932   Label exit_with_exception;
933 
934   // Preempt-code
935   if (check_preempt_label_.is_linked()) {
936     SafeCallTarget(&check_preempt_label_);
937 
938     StoreRegExpStackPointerToMemory(backtrack_stackpointer(), r1);
939 
940     CallCheckStackGuardState();
941     __ cmp(r0, Operand::Zero());
942     // If returning non-zero, we should end execution with the given
943     // result as return value.
944     __ b(ne, &return_r0);
945 
946     LoadRegExpStackPointerFromMemory(backtrack_stackpointer());
947 
948     // String might have moved: Reload end of string from frame.
949     __ ldr(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
950     SafeReturn();
951   }
952 
953   // Backtrack stack overflow code.
954   if (stack_overflow_label_.is_linked()) {
955     SafeCallTarget(&stack_overflow_label_);
956     // Reached if the backtrack-stack limit has been hit.
957 
958     // Call GrowStack(isolate).
959 
960     StoreRegExpStackPointerToMemory(backtrack_stackpointer(), r1);
961 
962     static constexpr int kNumArguments = 1;
963     __ PrepareCallCFunction(kNumArguments);
964     __ mov(r0, Operand(ExternalReference::isolate_address(isolate())));
965     ExternalReference grow_stack = ExternalReference::re_grow_stack();
966     __ CallCFunction(grow_stack, kNumArguments);
967     // If nullptr is returned, we have failed to grow the stack, and must exit
968     // with a stack-overflow exception.
969     __ cmp(r0, Operand::Zero());
970     __ b(eq, &exit_with_exception);
971     // Otherwise use return value as new stack pointer.
972     __ mov(backtrack_stackpointer(), r0);
973     // Restore saved registers and continue.
974     SafeReturn();
975   }
976 
977   if (exit_with_exception.is_linked()) {
978     // If any of the code above needed to exit with an exception.
979     __ bind(&exit_with_exception);
980     // Exit with Result EXCEPTION(-1) to signal thrown exception.
981     __ mov(r0, Operand(EXCEPTION));
982     __ jmp(&return_r0);
983   }
984 
985   if (fallback_label_.is_linked()) {
986     __ bind(&fallback_label_);
987     __ mov(r0, Operand(FALLBACK_TO_EXPERIMENTAL));
988     __ jmp(&return_r0);
989   }
990 
991   CodeDesc code_desc;
992   masm_->GetCode(isolate(), &code_desc);
993   Handle<Code> code =
994       Factory::CodeBuilder(isolate(), code_desc, CodeKind::REGEXP)
995           .set_self_reference(masm_->CodeObject())
996           .Build();
997   PROFILE(masm_->isolate(),
998           RegExpCodeCreateEvent(Handle<AbstractCode>::cast(code), source));
999   return Handle<HeapObject>::cast(code);
1000 }
1001 
1002 
GoTo(Label* to)1003 void RegExpMacroAssemblerARM::GoTo(Label* to) {
1004   BranchOrBacktrack(al, to);
1005 }
1006 
1007 
IfRegisterGE(int reg, int comparand, Label* if_ge)1008 void RegExpMacroAssemblerARM::IfRegisterGE(int reg,
1009                                            int comparand,
1010                                            Label* if_ge) {
1011   __ ldr(r0, register_location(reg));
1012   __ cmp(r0, Operand(comparand));
1013   BranchOrBacktrack(ge, if_ge);
1014 }
1015 
1016 
IfRegisterLT(int reg, int comparand, Label* if_lt)1017 void RegExpMacroAssemblerARM::IfRegisterLT(int reg,
1018                                            int comparand,
1019                                            Label* if_lt) {
1020   __ ldr(r0, register_location(reg));
1021   __ cmp(r0, Operand(comparand));
1022   BranchOrBacktrack(lt, if_lt);
1023 }
1024 
1025 
IfRegisterEqPos(int reg, Label* if_eq)1026 void RegExpMacroAssemblerARM::IfRegisterEqPos(int reg,
1027                                               Label* if_eq) {
1028   __ ldr(r0, register_location(reg));
1029   __ cmp(r0, Operand(current_input_offset()));
1030   BranchOrBacktrack(eq, if_eq);
1031 }
1032 
1033 
1034 RegExpMacroAssembler::IrregexpImplementation
Implementation()1035     RegExpMacroAssemblerARM::Implementation() {
1036   return kARMImplementation;
1037 }
1038 
1039 
PopCurrentPosition()1040 void RegExpMacroAssemblerARM::PopCurrentPosition() {
1041   Pop(current_input_offset());
1042 }
1043 
1044 
PopRegister(int register_index)1045 void RegExpMacroAssemblerARM::PopRegister(int register_index) {
1046   Pop(r0);
1047   __ str(r0, register_location(register_index));
1048 }
1049 
1050 
PushBacktrack(Label* label)1051 void RegExpMacroAssemblerARM::PushBacktrack(Label* label) {
1052   __ mov_label_offset(r0, label);
1053   Push(r0);
1054   CheckStackLimit();
1055 }
1056 
1057 
PushCurrentPosition()1058 void RegExpMacroAssemblerARM::PushCurrentPosition() {
1059   Push(current_input_offset());
1060 }
1061 
1062 
PushRegister(int register_index, StackCheckFlag check_stack_limit)1063 void RegExpMacroAssemblerARM::PushRegister(int register_index,
1064                                            StackCheckFlag check_stack_limit) {
1065   __ ldr(r0, register_location(register_index));
1066   Push(r0);
1067   if (check_stack_limit) CheckStackLimit();
1068 }
1069 
1070 
ReadCurrentPositionFromRegister(int reg)1071 void RegExpMacroAssemblerARM::ReadCurrentPositionFromRegister(int reg) {
1072   __ ldr(current_input_offset(), register_location(reg));
1073 }
1074 
WriteStackPointerToRegister(int reg)1075 void RegExpMacroAssemblerARM::WriteStackPointerToRegister(int reg) {
1076   ExternalReference ref =
1077       ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
1078   __ mov(r1, Operand(ref));
1079   __ ldr(r1, MemOperand(r1));
1080   __ sub(r0, backtrack_stackpointer(), r1);
1081   __ str(r0, register_location(reg));
1082 }
1083 
ReadStackPointerFromRegister(int reg)1084 void RegExpMacroAssemblerARM::ReadStackPointerFromRegister(int reg) {
1085   ExternalReference ref =
1086       ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
1087   __ mov(r0, Operand(ref));
1088   __ ldr(r0, MemOperand(r0));
1089   __ ldr(backtrack_stackpointer(), register_location(reg));
1090   __ add(backtrack_stackpointer(), backtrack_stackpointer(), r0);
1091 }
1092 
SetCurrentPositionFromEnd(int by)1093 void RegExpMacroAssemblerARM::SetCurrentPositionFromEnd(int by) {
1094   Label after_position;
1095   __ cmp(current_input_offset(), Operand(-by * char_size()));
1096   __ b(ge, &after_position);
1097   __ mov(current_input_offset(), Operand(-by * char_size()));
1098   // On RegExp code entry (where this operation is used), the character before
1099   // the current position is expected to be already loaded.
1100   // We have advanced the position, so it's safe to read backwards.
1101   LoadCurrentCharacterUnchecked(-1, 1);
1102   __ bind(&after_position);
1103 }
1104 
1105 
SetRegister(int register_index, int to)1106 void RegExpMacroAssemblerARM::SetRegister(int register_index, int to) {
1107   DCHECK(register_index >= num_saved_registers_);  // Reserved for positions!
1108   __ mov(r0, Operand(to));
1109   __ str(r0, register_location(register_index));
1110 }
1111 
1112 
Succeed()1113 bool RegExpMacroAssemblerARM::Succeed() {
1114   __ jmp(&success_label_);
1115   return global();
1116 }
1117 
1118 
WriteCurrentPositionToRegister(int reg, int cp_offset)1119 void RegExpMacroAssemblerARM::WriteCurrentPositionToRegister(int reg,
1120                                                              int cp_offset) {
1121   if (cp_offset == 0) {
1122     __ str(current_input_offset(), register_location(reg));
1123   } else {
1124     __ add(r0, current_input_offset(), Operand(cp_offset * char_size()));
1125     __ str(r0, register_location(reg));
1126   }
1127 }
1128 
1129 
ClearRegisters(int reg_from, int reg_to)1130 void RegExpMacroAssemblerARM::ClearRegisters(int reg_from, int reg_to) {
1131   DCHECK(reg_from <= reg_to);
1132   __ ldr(r0, MemOperand(frame_pointer(), kStringStartMinusOne));
1133   for (int reg = reg_from; reg <= reg_to; reg++) {
1134     __ str(r0, register_location(reg));
1135   }
1136 }
1137 
1138 // Private methods:
1139 
CallCheckStackGuardState()1140 void RegExpMacroAssemblerARM::CallCheckStackGuardState() {
1141   DCHECK(!isolate()->IsGeneratingEmbeddedBuiltins());
1142   DCHECK(!masm_->options().isolate_independent_code);
1143 
1144   __ PrepareCallCFunction(3);
1145 
1146   // RegExp code frame pointer.
1147   __ mov(r2, frame_pointer());
1148   // Code of self.
1149   __ mov(r1, Operand(masm_->CodeObject()));
1150 
1151   // We need to make room for the return address on the stack.
1152   int stack_alignment = base::OS::ActivationFrameAlignment();
1153   DCHECK(IsAligned(stack_alignment, kPointerSize));
1154   __ AllocateStackSpace(stack_alignment);
1155 
1156   // r0 will point to the return address, placed by DirectCEntry.
1157   __ mov(r0, sp);
1158 
1159   ExternalReference stack_guard_check =
1160       ExternalReference::re_check_stack_guard_state();
1161   __ mov(ip, Operand(stack_guard_check));
1162 
1163   EmbeddedData d = EmbeddedData::FromBlob();
1164   Address entry = d.InstructionStartOfBuiltin(Builtin::kDirectCEntry);
1165   __ mov(lr, Operand(entry, RelocInfo::OFF_HEAP_TARGET));
1166   __ Call(lr);
1167 
1168   // Drop the return address from the stack.
1169   __ add(sp, sp, Operand(stack_alignment));
1170 
1171   DCHECK_NE(0, stack_alignment);
1172   __ ldr(sp, MemOperand(sp, 0));
1173 
1174   __ mov(code_pointer(), Operand(masm_->CodeObject()));
1175 }
1176 
1177 
1178 // Helper function for reading a value out of a stack frame.
1179 template <typename T>
frame_entry(Address re_frame, int frame_offset)1180 static T& frame_entry(Address re_frame, int frame_offset) {
1181   return reinterpret_cast<T&>(Memory<int32_t>(re_frame + frame_offset));
1182 }
1183 
1184 
1185 template <typename T>
frame_entry_address(Address re_frame, int frame_offset)1186 static T* frame_entry_address(Address re_frame, int frame_offset) {
1187   return reinterpret_cast<T*>(re_frame + frame_offset);
1188 }
1189 
CheckStackGuardState(Address* return_address, Address raw_code, Address re_frame)1190 int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address,
1191                                                   Address raw_code,
1192                                                   Address re_frame) {
1193   Code re_code = Code::cast(Object(raw_code));
1194   return NativeRegExpMacroAssembler::CheckStackGuardState(
1195       frame_entry<Isolate*>(re_frame, kIsolate),
1196       frame_entry<int>(re_frame, kStartIndex),
1197       static_cast<RegExp::CallOrigin>(frame_entry<int>(re_frame, kDirectCall)),
1198       return_address, re_code,
1199       frame_entry_address<Address>(re_frame, kInputString),
1200       frame_entry_address<const byte*>(re_frame, kInputStart),
1201       frame_entry_address<const byte*>(re_frame, kInputEnd));
1202 }
1203 
1204 
register_location(int register_index)1205 MemOperand RegExpMacroAssemblerARM::register_location(int register_index) {
1206   DCHECK(register_index < (1<<30));
1207   if (num_registers_ <= register_index) {
1208     num_registers_ = register_index + 1;
1209   }
1210   return MemOperand(frame_pointer(),
1211                     kRegisterZero - register_index * kPointerSize);
1212 }
1213 
1214 
1215 void RegExpMacroAssemblerARM::CheckPosition(int cp_offset,
1216                                             Label* on_outside_input) {
1217   if (cp_offset >= 0) {
1218     __ cmp(current_input_offset(), Operand(-cp_offset * char_size()));
1219     BranchOrBacktrack(ge, on_outside_input);
1220   } else {
1221     __ ldr(r1, MemOperand(frame_pointer(), kStringStartMinusOne));
1222     __ add(r0, current_input_offset(), Operand(cp_offset * char_size()));
1223     __ cmp(r0, r1);
1224     BranchOrBacktrack(le, on_outside_input);
1225   }
1226 }
1227 
1228 
1229 void RegExpMacroAssemblerARM::BranchOrBacktrack(Condition condition,
1230                                                 Label* to) {
1231   if (condition == al) {  // Unconditional.
1232     if (to == nullptr) {
1233       Backtrack();
1234       return;
1235     }
1236     __ jmp(to);
1237     return;
1238   }
1239   if (to == nullptr) {
1240     __ b(condition, &backtrack_label_);
1241     return;
1242   }
1243   __ b(condition, to);
1244 }
1245 
1246 
1247 void RegExpMacroAssemblerARM::SafeCall(Label* to, Condition cond) {
1248   __ bl(to, cond);
1249 }
1250 
1251 
1252 void RegExpMacroAssemblerARM::SafeReturn() {
1253   __ pop(lr);
1254   __ add(pc, lr, Operand(masm_->CodeObject()));
1255 }
1256 
1257 
1258 void RegExpMacroAssemblerARM::SafeCallTarget(Label* name) {
1259   __ bind(name);
1260   __ sub(lr, lr, Operand(masm_->CodeObject()));
1261   __ push(lr);
1262 }
1263 
1264 
1265 void RegExpMacroAssemblerARM::Push(Register source) {
1266   DCHECK(source != backtrack_stackpointer());
1267   __ str(source,
1268          MemOperand(backtrack_stackpointer(), kPointerSize, NegPreIndex));
1269 }
1270 
1271 
1272 void RegExpMacroAssemblerARM::Pop(Register target) {
1273   DCHECK(target != backtrack_stackpointer());
1274   __ ldr(target,
1275          MemOperand(backtrack_stackpointer(), kPointerSize, PostIndex));
1276 }
1277 
1278 
1279 void RegExpMacroAssemblerARM::CheckPreemption() {
1280   // Check for preemption.
1281   ExternalReference stack_limit =
1282       ExternalReference::address_of_jslimit(isolate());
1283   __ mov(r0, Operand(stack_limit));
1284   __ ldr(r0, MemOperand(r0));
1285   __ cmp(sp, r0);
1286   SafeCall(&check_preempt_label_, ls);
1287 }
1288 
1289 
1290 void RegExpMacroAssemblerARM::CheckStackLimit() {
1291   ExternalReference stack_limit =
1292       ExternalReference::address_of_regexp_stack_limit_address(isolate());
1293   __ mov(r0, Operand(stack_limit));
1294   __ ldr(r0, MemOperand(r0));
1295   __ cmp(backtrack_stackpointer(), Operand(r0));
1296   SafeCall(&stack_overflow_label_, ls);
1297 }
1298 
1299 
1300 void RegExpMacroAssemblerARM::LoadCurrentCharacterUnchecked(int cp_offset,
1301                                                             int characters) {
1302   Register offset = current_input_offset();
1303   if (cp_offset != 0) {
1304     // r4 is not being used to store the capture start index at this point.
1305     __ add(r4, current_input_offset(), Operand(cp_offset * char_size()));
1306     offset = r4;
1307   }
1308   // The ldr, str, ldrh, strh instructions can do unaligned accesses, if the CPU
1309   // and the operating system running on the target allow it.
1310   // If unaligned load/stores are not supported then this function must only
1311   // be used to load a single character at a time.
1312   if (!CanReadUnaligned()) {
1313     DCHECK_EQ(1, characters);
1314   }
1315 
1316   if (mode_ == LATIN1) {
1317     if (characters == 4) {
1318       __ ldr(current_character(), MemOperand(end_of_input_address(), offset));
1319     } else if (characters == 2) {
1320       __ ldrh(current_character(), MemOperand(end_of_input_address(), offset));
1321     } else {
1322       DCHECK_EQ(1, characters);
1323       __ ldrb(current_character(), MemOperand(end_of_input_address(), offset));
1324     }
1325   } else {
1326     DCHECK(mode_ == UC16);
1327     if (characters == 2) {
1328       __ ldr(current_character(), MemOperand(end_of_input_address(), offset));
1329     } else {
1330       DCHECK_EQ(1, characters);
1331       __ ldrh(current_character(), MemOperand(end_of_input_address(), offset));
1332     }
1333   }
1334 }
1335 
1336 
1337 #undef __
1338 
1339 }  // namespace internal
1340 }  // namespace v8
1341 
1342 #endif  // V8_TARGET_ARCH_ARM
1343