• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include "v8.h"
29 
30 #if defined(V8_TARGET_ARCH_ARM)
31 
32 #include "unicode.h"
33 #include "log.h"
34 #include "code-stubs.h"
35 #include "regexp-stack.h"
36 #include "macro-assembler.h"
37 #include "regexp-macro-assembler.h"
38 #include "arm/regexp-macro-assembler-arm.h"
39 
40 namespace v8 {
41 namespace internal {
42 
43 #ifndef V8_INTERPRETED_REGEXP
44 /*
45  * This assembler uses the following register assignment convention
46  * - r5 : Pointer to current code object (Code*) including heap object tag.
47  * - r6 : Current position in input, as negative offset from end of string.
48  *        Please notice that this is the byte offset, not the character offset!
49  * - r7 : Currently loaded character. Must be loaded using
50  *        LoadCurrentCharacter before using any of the dispatch methods.
51  * - r8 : points to tip of backtrack stack
52  * - r9 : Unused, might be used by C code and expected unchanged.
53  * - r10 : End of input (points to byte after last character in input).
54  * - r11 : Frame pointer. Used to access arguments, local variables and
55  *         RegExp registers.
56  * - r12 : IP register, used by assembler. Very volatile.
57  * - r13/sp : points to tip of C stack.
58  *
59  * The remaining registers are free for computations.
60  * Each call to a public method should retain this convention.
61  *
62  * The stack will have the following structure:
63  *  - fp[52]  Isolate* isolate   (Address of the current isolate)
64  *  - fp[48]  direct_call  (if 1, direct call from JavaScript code,
65  *                          if 0, call through the runtime system).
66  *  - fp[44]  stack_area_base (High end of the memory area to use as
67  *                             backtracking stack).
68  *  - fp[40]  int* capture_array (int[num_saved_registers_], for output).
69  *  - fp[36]  secondary link/return address used by native call.
70  *  --- sp when called ---
71  *  - fp[32]  return address (lr).
72  *  - fp[28]  old frame pointer (r11).
73  *  - fp[0..24]  backup of registers r4..r10.
74  *  --- frame pointer ----
75  *  - fp[-4]  end of input       (Address of end of string).
76  *  - fp[-8]  start of input     (Address of first character in string).
77  *  - fp[-12] start index        (character index of start).
78  *  - fp[-16] void* input_string (location of a handle containing the string).
79  *  - fp[-20] Offset of location before start of input (effectively character
80  *            position -1). Used to initialize capture registers to a
81  *            non-position.
82  *  - fp[-24] At start (if 1, we are starting at the start of the
83  *    string, otherwise 0)
84  *  - fp[-28] register 0         (Only positions must be stored in the first
85  *  -         register 1          num_saved_registers_ registers)
86  *  -         ...
87  *  -         register num_registers-1
88  *  --- sp ---
89  *
90  * The first num_saved_registers_ registers are initialized to point to
91  * "character -1" in the string (i.e., char_size() bytes before the first
92  * character of the string). The remaining registers start out as garbage.
93  *
94  * The data up to the return address must be placed there by the calling
95  * code and the remaining arguments are passed in registers, e.g. by calling the
96  * code entry as cast to a function with the signature:
97  * int (*match)(String* input_string,
98  *              int start_index,
99  *              Address start,
100  *              Address end,
101  *              Address secondary_return_address,  // Only used by native call.
102  *              int* capture_output_array,
103  *              byte* stack_area_base,
104  *              bool direct_call = false)
105  * The call is performed by NativeRegExpMacroAssembler::Execute()
106  * (in regexp-macro-assembler.cc) via the CALL_GENERATED_REGEXP_CODE macro
107  * in arm/simulator-arm.h.
108  * When calling as a non-direct call (i.e., from C++ code), the return address
109  * area is overwritten with the LR register by the RegExp code. When doing a
110  * direct call from generated code, the return address is placed there by
111  * the calling code, as in a normal exit frame.
112  */
113 
114 #define __ ACCESS_MASM(masm_)
115 
RegExpMacroAssemblerARM(Mode mode,int registers_to_save)116 RegExpMacroAssemblerARM::RegExpMacroAssemblerARM(
117     Mode mode,
118     int registers_to_save)
119     : masm_(new MacroAssembler(Isolate::Current(), NULL, kRegExpCodeSize)),
120       mode_(mode),
121       num_registers_(registers_to_save),
122       num_saved_registers_(registers_to_save),
123       entry_label_(),
124       start_label_(),
125       success_label_(),
126       backtrack_label_(),
127       exit_label_() {
128   ASSERT_EQ(0, registers_to_save % 2);
129   __ jmp(&entry_label_);   // We'll write the entry code later.
130   EmitBacktrackConstantPool();
131   __ bind(&start_label_);  // And then continue from here.
132 }
133 
134 
~RegExpMacroAssemblerARM()135 RegExpMacroAssemblerARM::~RegExpMacroAssemblerARM() {
136   delete masm_;
137   // Unuse labels in case we throw away the assembler without calling GetCode.
138   entry_label_.Unuse();
139   start_label_.Unuse();
140   success_label_.Unuse();
141   backtrack_label_.Unuse();
142   exit_label_.Unuse();
143   check_preempt_label_.Unuse();
144   stack_overflow_label_.Unuse();
145 }
146 
147 
stack_limit_slack()148 int RegExpMacroAssemblerARM::stack_limit_slack()  {
149   return RegExpStack::kStackLimitSlack;
150 }
151 
152 
AdvanceCurrentPosition(int by)153 void RegExpMacroAssemblerARM::AdvanceCurrentPosition(int by) {
154   if (by != 0) {
155     __ add(current_input_offset(),
156            current_input_offset(), Operand(by * char_size()));
157   }
158 }
159 
160 
AdvanceRegister(int reg,int by)161 void RegExpMacroAssemblerARM::AdvanceRegister(int reg, int by) {
162   ASSERT(reg >= 0);
163   ASSERT(reg < num_registers_);
164   if (by != 0) {
165     __ ldr(r0, register_location(reg));
166     __ add(r0, r0, Operand(by));
167     __ str(r0, register_location(reg));
168   }
169 }
170 
171 
Backtrack()172 void RegExpMacroAssemblerARM::Backtrack() {
173   CheckPreemption();
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 
190 
CheckCharacterGT(uc16 limit,Label * on_greater)191 void RegExpMacroAssemblerARM::CheckCharacterGT(uc16 limit, Label* on_greater) {
192   __ cmp(current_character(), Operand(limit));
193   BranchOrBacktrack(gt, on_greater);
194 }
195 
196 
CheckAtStart(Label * on_at_start)197 void RegExpMacroAssemblerARM::CheckAtStart(Label* on_at_start) {
198   Label not_at_start;
199   // Did we start the match at the start of the string at all?
200   __ ldr(r0, MemOperand(frame_pointer(), kAtStart));
201   __ cmp(r0, Operand(0, RelocInfo::NONE));
202   BranchOrBacktrack(eq, &not_at_start);
203 
204   // If we did, are we still at the start of the input?
205   __ ldr(r1, MemOperand(frame_pointer(), kInputStart));
206   __ add(r0, end_of_input_address(), Operand(current_input_offset()));
207   __ cmp(r0, r1);
208   BranchOrBacktrack(eq, on_at_start);
209   __ bind(&not_at_start);
210 }
211 
212 
CheckNotAtStart(Label * on_not_at_start)213 void RegExpMacroAssemblerARM::CheckNotAtStart(Label* on_not_at_start) {
214   // Did we start the match at the start of the string at all?
215   __ ldr(r0, MemOperand(frame_pointer(), kAtStart));
216   __ cmp(r0, Operand(0, RelocInfo::NONE));
217   BranchOrBacktrack(eq, on_not_at_start);
218   // If we did, are we still at the start of the input?
219   __ ldr(r1, MemOperand(frame_pointer(), kInputStart));
220   __ add(r0, end_of_input_address(), Operand(current_input_offset()));
221   __ cmp(r0, r1);
222   BranchOrBacktrack(ne, on_not_at_start);
223 }
224 
225 
CheckCharacterLT(uc16 limit,Label * on_less)226 void RegExpMacroAssemblerARM::CheckCharacterLT(uc16 limit, Label* on_less) {
227   __ cmp(current_character(), Operand(limit));
228   BranchOrBacktrack(lt, on_less);
229 }
230 
231 
CheckCharacters(Vector<const uc16> str,int cp_offset,Label * on_failure,bool check_end_of_string)232 void RegExpMacroAssemblerARM::CheckCharacters(Vector<const uc16> str,
233                                               int cp_offset,
234                                               Label* on_failure,
235                                               bool check_end_of_string) {
236   if (on_failure == NULL) {
237     // Instead of inlining a backtrack for each test, (re)use the global
238     // backtrack target.
239     on_failure = &backtrack_label_;
240   }
241 
242   if (check_end_of_string) {
243     // Is last character of required match inside string.
244     CheckPosition(cp_offset + str.length() - 1, on_failure);
245   }
246 
247   __ add(r0, end_of_input_address(), Operand(current_input_offset()));
248   if (cp_offset != 0) {
249     int byte_offset = cp_offset * char_size();
250     __ add(r0, r0, Operand(byte_offset));
251   }
252 
253   // r0 : Address of characters to match against str.
254   int stored_high_byte = 0;
255   for (int i = 0; i < str.length(); i++) {
256     if (mode_ == ASCII) {
257       __ ldrb(r1, MemOperand(r0, char_size(), PostIndex));
258       ASSERT(str[i] <= String::kMaxAsciiCharCode);
259       __ cmp(r1, Operand(str[i]));
260     } else {
261       __ ldrh(r1, MemOperand(r0, char_size(), PostIndex));
262       uc16 match_char = str[i];
263       int match_high_byte = (match_char >> 8);
264       if (match_high_byte == 0) {
265         __ cmp(r1, Operand(str[i]));
266       } else {
267         if (match_high_byte != stored_high_byte) {
268           __ mov(r2, Operand(match_high_byte));
269           stored_high_byte = match_high_byte;
270         }
271         __ add(r3, r2, Operand(match_char & 0xff));
272         __ cmp(r1, r3);
273       }
274     }
275     BranchOrBacktrack(ne, on_failure);
276   }
277 }
278 
279 
CheckGreedyLoop(Label * on_equal)280 void RegExpMacroAssemblerARM::CheckGreedyLoop(Label* on_equal) {
281   __ ldr(r0, MemOperand(backtrack_stackpointer(), 0));
282   __ cmp(current_input_offset(), r0);
283   __ add(backtrack_stackpointer(),
284          backtrack_stackpointer(), Operand(kPointerSize), LeaveCC, eq);
285   BranchOrBacktrack(eq, on_equal);
286 }
287 
288 
CheckNotBackReferenceIgnoreCase(int start_reg,Label * on_no_match)289 void RegExpMacroAssemblerARM::CheckNotBackReferenceIgnoreCase(
290     int start_reg,
291     Label* on_no_match) {
292   Label fallthrough;
293   __ ldr(r0, register_location(start_reg));  // Index of start of capture
294   __ ldr(r1, register_location(start_reg + 1));  // Index of end of capture
295   __ sub(r1, r1, r0, SetCC);  // Length of capture.
296 
297   // If length is zero, either the capture is empty or it is not participating.
298   // In either case succeed immediately.
299   __ b(eq, &fallthrough);
300 
301   // Check that there are enough characters left in the input.
302   __ cmn(r1, Operand(current_input_offset()));
303   BranchOrBacktrack(gt, on_no_match);
304 
305   if (mode_ == ASCII) {
306     Label success;
307     Label fail;
308     Label loop_check;
309 
310     // r0 - offset of start of capture
311     // r1 - length of capture
312     __ add(r0, r0, Operand(end_of_input_address()));
313     __ add(r2, end_of_input_address(), Operand(current_input_offset()));
314     __ add(r1, r0, Operand(r1));
315 
316     // r0 - Address of start of capture.
317     // r1 - Address of end of capture
318     // r2 - Address of current input position.
319 
320     Label loop;
321     __ bind(&loop);
322     __ ldrb(r3, MemOperand(r0, char_size(), PostIndex));
323     __ ldrb(r4, MemOperand(r2, char_size(), PostIndex));
324     __ cmp(r4, r3);
325     __ b(eq, &loop_check);
326 
327     // Mismatch, try case-insensitive match (converting letters to lower-case).
328     __ orr(r3, r3, Operand(0x20));  // Convert capture character to lower-case.
329     __ orr(r4, r4, Operand(0x20));  // Also convert input character.
330     __ cmp(r4, r3);
331     __ b(ne, &fail);
332     __ sub(r3, r3, Operand('a'));
333     __ cmp(r3, Operand('z' - 'a'));  // Is r3 a lowercase letter?
334     __ b(hi, &fail);
335 
336 
337     __ bind(&loop_check);
338     __ cmp(r0, r1);
339     __ b(lt, &loop);
340     __ jmp(&success);
341 
342     __ bind(&fail);
343     BranchOrBacktrack(al, on_no_match);
344 
345     __ bind(&success);
346     // Compute new value of character position after the matched part.
347     __ sub(current_input_offset(), r2, end_of_input_address());
348   } else {
349     ASSERT(mode_ == UC16);
350     int argument_count = 4;
351     __ PrepareCallCFunction(argument_count, r2);
352 
353     // r0 - offset of start of capture
354     // r1 - length of capture
355 
356     // Put arguments into arguments registers.
357     // Parameters are
358     //   r0: Address byte_offset1 - Address captured substring's start.
359     //   r1: Address byte_offset2 - Address of current character position.
360     //   r2: size_t byte_length - length of capture in bytes(!)
361     //   r3: Isolate* isolate
362 
363     // Address of start of capture.
364     __ add(r0, r0, Operand(end_of_input_address()));
365     // Length of capture.
366     __ mov(r2, Operand(r1));
367     // Save length in callee-save register for use on return.
368     __ mov(r4, Operand(r1));
369     // Address of current input position.
370     __ add(r1, current_input_offset(), Operand(end_of_input_address()));
371     // Isolate.
372     __ mov(r3, Operand(ExternalReference::isolate_address()));
373 
374     {
375       AllowExternalCallThatCantCauseGC scope(masm_);
376       ExternalReference function =
377           ExternalReference::re_case_insensitive_compare_uc16(masm_->isolate());
378       __ CallCFunction(function, argument_count);
379     }
380 
381     // Check if function returned non-zero for success or zero for failure.
382     __ cmp(r0, Operand(0, RelocInfo::NONE));
383     BranchOrBacktrack(eq, on_no_match);
384     // On success, increment position by length of capture.
385     __ add(current_input_offset(), current_input_offset(), Operand(r4));
386   }
387 
388   __ bind(&fallthrough);
389 }
390 
391 
CheckNotBackReference(int start_reg,Label * on_no_match)392 void RegExpMacroAssemblerARM::CheckNotBackReference(
393     int start_reg,
394     Label* on_no_match) {
395   Label fallthrough;
396   Label success;
397 
398   // Find length of back-referenced capture.
399   __ ldr(r0, register_location(start_reg));
400   __ ldr(r1, register_location(start_reg + 1));
401   __ sub(r1, r1, r0, SetCC);  // Length to check.
402   // Succeed on empty capture (including no capture).
403   __ b(eq, &fallthrough);
404 
405   // Check that there are enough characters left in the input.
406   __ cmn(r1, Operand(current_input_offset()));
407   BranchOrBacktrack(gt, on_no_match);
408 
409   // Compute pointers to match string and capture string
410   __ add(r0, r0, Operand(end_of_input_address()));
411   __ add(r2, end_of_input_address(), Operand(current_input_offset()));
412   __ add(r1, r1, Operand(r0));
413 
414   Label loop;
415   __ bind(&loop);
416   if (mode_ == ASCII) {
417     __ ldrb(r3, MemOperand(r0, char_size(), PostIndex));
418     __ ldrb(r4, MemOperand(r2, char_size(), PostIndex));
419   } else {
420     ASSERT(mode_ == UC16);
421     __ ldrh(r3, MemOperand(r0, char_size(), PostIndex));
422     __ ldrh(r4, MemOperand(r2, char_size(), PostIndex));
423   }
424   __ cmp(r3, r4);
425   BranchOrBacktrack(ne, on_no_match);
426   __ cmp(r0, r1);
427   __ b(lt, &loop);
428 
429   // Move current character position to position after match.
430   __ sub(current_input_offset(), r2, end_of_input_address());
431   __ bind(&fallthrough);
432 }
433 
434 
CheckNotRegistersEqual(int reg1,int reg2,Label * on_not_equal)435 void RegExpMacroAssemblerARM::CheckNotRegistersEqual(int reg1,
436                                                      int reg2,
437                                                      Label* on_not_equal) {
438   __ ldr(r0, register_location(reg1));
439   __ ldr(r1, register_location(reg2));
440   __ cmp(r0, r1);
441   BranchOrBacktrack(ne, on_not_equal);
442 }
443 
444 
CheckNotCharacter(unsigned c,Label * on_not_equal)445 void RegExpMacroAssemblerARM::CheckNotCharacter(unsigned c,
446                                                 Label* on_not_equal) {
447   __ cmp(current_character(), Operand(c));
448   BranchOrBacktrack(ne, on_not_equal);
449 }
450 
451 
CheckCharacterAfterAnd(uint32_t c,uint32_t mask,Label * on_equal)452 void RegExpMacroAssemblerARM::CheckCharacterAfterAnd(uint32_t c,
453                                                      uint32_t mask,
454                                                      Label* on_equal) {
455   __ and_(r0, current_character(), Operand(mask));
456   __ cmp(r0, Operand(c));
457   BranchOrBacktrack(eq, on_equal);
458 }
459 
460 
CheckNotCharacterAfterAnd(unsigned c,unsigned mask,Label * on_not_equal)461 void RegExpMacroAssemblerARM::CheckNotCharacterAfterAnd(unsigned c,
462                                                         unsigned mask,
463                                                         Label* on_not_equal) {
464   __ and_(r0, current_character(), Operand(mask));
465   __ cmp(r0, Operand(c));
466   BranchOrBacktrack(ne, on_not_equal);
467 }
468 
469 
CheckNotCharacterAfterMinusAnd(uc16 c,uc16 minus,uc16 mask,Label * on_not_equal)470 void RegExpMacroAssemblerARM::CheckNotCharacterAfterMinusAnd(
471     uc16 c,
472     uc16 minus,
473     uc16 mask,
474     Label* on_not_equal) {
475   ASSERT(minus < String::kMaxUtf16CodeUnit);
476   __ sub(r0, current_character(), Operand(minus));
477   __ and_(r0, r0, Operand(mask));
478   __ cmp(r0, Operand(c));
479   BranchOrBacktrack(ne, on_not_equal);
480 }
481 
482 
CheckSpecialCharacterClass(uc16 type,Label * on_no_match)483 bool RegExpMacroAssemblerARM::CheckSpecialCharacterClass(uc16 type,
484                                                          Label* on_no_match) {
485   // Range checks (c in min..max) are generally implemented by an unsigned
486   // (c - min) <= (max - min) check
487   switch (type) {
488   case 's':
489     // Match space-characters
490     if (mode_ == ASCII) {
491       // ASCII space characters are '\t'..'\r' and ' '.
492       Label success;
493       __ cmp(current_character(), Operand(' '));
494       __ b(eq, &success);
495       // Check range 0x09..0x0d
496       __ sub(r0, current_character(), Operand('\t'));
497       __ cmp(r0, Operand('\r' - '\t'));
498       BranchOrBacktrack(hi, on_no_match);
499       __ bind(&success);
500       return true;
501     }
502     return false;
503   case 'S':
504     // Match non-space characters.
505     if (mode_ == ASCII) {
506       // ASCII space characters are '\t'..'\r' and ' '.
507       __ cmp(current_character(), Operand(' '));
508       BranchOrBacktrack(eq, on_no_match);
509       __ sub(r0, current_character(), Operand('\t'));
510       __ cmp(r0, Operand('\r' - '\t'));
511       BranchOrBacktrack(ls, on_no_match);
512       return true;
513     }
514     return false;
515   case 'd':
516     // Match ASCII digits ('0'..'9')
517     __ sub(r0, current_character(), Operand('0'));
518     __ cmp(current_character(), Operand('9' - '0'));
519     BranchOrBacktrack(hi, on_no_match);
520     return true;
521   case 'D':
522     // Match non ASCII-digits
523     __ sub(r0, current_character(), Operand('0'));
524     __ cmp(r0, Operand('9' - '0'));
525     BranchOrBacktrack(ls, on_no_match);
526     return true;
527   case '.': {
528     // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
529     __ eor(r0, current_character(), Operand(0x01));
530     // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
531     __ sub(r0, r0, Operand(0x0b));
532     __ cmp(r0, Operand(0x0c - 0x0b));
533     BranchOrBacktrack(ls, on_no_match);
534     if (mode_ == UC16) {
535       // Compare original value to 0x2028 and 0x2029, using the already
536       // computed (current_char ^ 0x01 - 0x0b). I.e., check for
537       // 0x201d (0x2028 - 0x0b) or 0x201e.
538       __ sub(r0, r0, Operand(0x2028 - 0x0b));
539       __ cmp(r0, Operand(1));
540       BranchOrBacktrack(ls, on_no_match);
541     }
542     return true;
543   }
544   case 'n': {
545     // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
546     __ eor(r0, current_character(), Operand(0x01));
547     // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
548     __ sub(r0, r0, Operand(0x0b));
549     __ cmp(r0, Operand(0x0c - 0x0b));
550     if (mode_ == ASCII) {
551       BranchOrBacktrack(hi, on_no_match);
552     } else {
553       Label done;
554       __ b(ls, &done);
555       // Compare original value to 0x2028 and 0x2029, using the already
556       // computed (current_char ^ 0x01 - 0x0b). I.e., check for
557       // 0x201d (0x2028 - 0x0b) or 0x201e.
558       __ sub(r0, r0, Operand(0x2028 - 0x0b));
559       __ cmp(r0, Operand(1));
560       BranchOrBacktrack(hi, on_no_match);
561       __ bind(&done);
562     }
563     return true;
564   }
565   case 'w': {
566     if (mode_ != ASCII) {
567       // Table is 128 entries, so all ASCII characters can be tested.
568       __ cmp(current_character(), Operand('z'));
569       BranchOrBacktrack(hi, on_no_match);
570     }
571     ExternalReference map = ExternalReference::re_word_character_map();
572     __ mov(r0, Operand(map));
573     __ ldrb(r0, MemOperand(r0, current_character()));
574     __ cmp(r0, Operand(0));
575     BranchOrBacktrack(eq, on_no_match);
576     return true;
577   }
578   case 'W': {
579     Label done;
580     if (mode_ != ASCII) {
581       // Table is 128 entries, so all ASCII characters can be tested.
582       __ cmp(current_character(), Operand('z'));
583       __ b(hi, &done);
584     }
585     ExternalReference map = ExternalReference::re_word_character_map();
586     __ mov(r0, Operand(map));
587     __ ldrb(r0, MemOperand(r0, current_character()));
588     __ cmp(r0, Operand(0));
589     BranchOrBacktrack(ne, on_no_match);
590     if (mode_ != ASCII) {
591       __ bind(&done);
592     }
593     return true;
594   }
595   case '*':
596     // Match any character.
597     return true;
598   // No custom implementation (yet): s(UC16), S(UC16).
599   default:
600     return false;
601   }
602 }
603 
604 
Fail()605 void RegExpMacroAssemblerARM::Fail() {
606   __ mov(r0, Operand(FAILURE));
607   __ jmp(&exit_label_);
608 }
609 
610 
GetCode(Handle<String> source)611 Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
612   // Finalize code - write the entry point code now we know how many
613   // registers we need.
614 
615   // Entry code:
616   __ bind(&entry_label_);
617 
618   // Tell the system that we have a stack frame.  Because the type is MANUAL, no
619   // is generated.
620   FrameScope scope(masm_, StackFrame::MANUAL);
621 
622   // Actually emit code to start a new stack frame.
623   // Push arguments
624   // Save callee-save registers.
625   // Start new stack frame.
626   // Store link register in existing stack-cell.
627   // Order here should correspond to order of offset constants in header file.
628   RegList registers_to_retain = r4.bit() | r5.bit() | r6.bit() |
629       r7.bit() | r8.bit() | r9.bit() | r10.bit() | fp.bit();
630   RegList argument_registers = r0.bit() | r1.bit() | r2.bit() | r3.bit();
631   __ stm(db_w, sp, argument_registers | registers_to_retain | lr.bit());
632   // Set frame pointer in space for it if this is not a direct call
633   // from generated code.
634   __ add(frame_pointer(), sp, Operand(4 * kPointerSize));
635   __ push(r0);  // Make room for "position - 1" constant (value is irrelevant).
636   __ push(r0);  // Make room for "at start" constant (value is irrelevant).
637   // Check if we have space on the stack for registers.
638   Label stack_limit_hit;
639   Label stack_ok;
640 
641   ExternalReference stack_limit =
642       ExternalReference::address_of_stack_limit(masm_->isolate());
643   __ mov(r0, Operand(stack_limit));
644   __ ldr(r0, MemOperand(r0));
645   __ sub(r0, sp, r0, SetCC);
646   // Handle it if the stack pointer is already below the stack limit.
647   __ b(ls, &stack_limit_hit);
648   // Check if there is room for the variable number of registers above
649   // the stack limit.
650   __ cmp(r0, Operand(num_registers_ * kPointerSize));
651   __ b(hs, &stack_ok);
652   // Exit with OutOfMemory exception. There is not enough space on the stack
653   // for our working registers.
654   __ mov(r0, Operand(EXCEPTION));
655   __ jmp(&exit_label_);
656 
657   __ bind(&stack_limit_hit);
658   CallCheckStackGuardState(r0);
659   __ cmp(r0, Operand(0, RelocInfo::NONE));
660   // If returned value is non-zero, we exit with the returned value as result.
661   __ b(ne, &exit_label_);
662 
663   __ bind(&stack_ok);
664 
665   // Allocate space on stack for registers.
666   __ sub(sp, sp, Operand(num_registers_ * kPointerSize));
667   // Load string end.
668   __ ldr(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
669   // Load input start.
670   __ ldr(r0, MemOperand(frame_pointer(), kInputStart));
671   // Find negative length (offset of start relative to end).
672   __ sub(current_input_offset(), r0, end_of_input_address());
673   // Set r0 to address of char before start of the input string
674   // (effectively string position -1).
675   __ ldr(r1, MemOperand(frame_pointer(), kStartIndex));
676   __ sub(r0, current_input_offset(), Operand(char_size()));
677   __ sub(r0, r0, Operand(r1, LSL, (mode_ == UC16) ? 1 : 0));
678   // Store this value in a local variable, for use when clearing
679   // position registers.
680   __ str(r0, MemOperand(frame_pointer(), kInputStartMinusOne));
681 
682   // Determine whether the start index is zero, that is at the start of the
683   // string, and store that value in a local variable.
684   __ cmp(r1, Operand(0));
685   __ mov(r1, Operand(1), LeaveCC, eq);
686   __ mov(r1, Operand(0, RelocInfo::NONE), LeaveCC, ne);
687   __ str(r1, MemOperand(frame_pointer(), kAtStart));
688 
689   if (num_saved_registers_ > 0) {  // Always is, if generated from a regexp.
690     // Fill saved registers with initial value = start offset - 1
691 
692     // Address of register 0.
693     __ add(r1, frame_pointer(), Operand(kRegisterZero));
694     __ mov(r2, Operand(num_saved_registers_));
695     Label init_loop;
696     __ bind(&init_loop);
697     __ str(r0, MemOperand(r1, kPointerSize, NegPostIndex));
698     __ sub(r2, r2, Operand(1), SetCC);
699     __ b(ne, &init_loop);
700   }
701 
702   // Initialize backtrack stack pointer.
703   __ ldr(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackHighEnd));
704   // Initialize code pointer register
705   __ mov(code_pointer(), Operand(masm_->CodeObject()));
706   // Load previous char as initial value of current character register.
707   Label at_start;
708   __ ldr(r0, MemOperand(frame_pointer(), kAtStart));
709   __ cmp(r0, Operand(0, RelocInfo::NONE));
710   __ b(ne, &at_start);
711   LoadCurrentCharacterUnchecked(-1, 1);  // Load previous char.
712   __ jmp(&start_label_);
713   __ bind(&at_start);
714   __ mov(current_character(), Operand('\n'));
715   __ jmp(&start_label_);
716 
717 
718   // Exit code:
719   if (success_label_.is_linked()) {
720     // Save captures when successful.
721     __ bind(&success_label_);
722     if (num_saved_registers_ > 0) {
723       // copy captures to output
724       __ ldr(r1, MemOperand(frame_pointer(), kInputStart));
725       __ ldr(r0, MemOperand(frame_pointer(), kRegisterOutput));
726       __ ldr(r2, MemOperand(frame_pointer(), kStartIndex));
727       __ sub(r1, end_of_input_address(), r1);
728       // r1 is length of input in bytes.
729       if (mode_ == UC16) {
730         __ mov(r1, Operand(r1, LSR, 1));
731       }
732       // r1 is length of input in characters.
733       __ add(r1, r1, Operand(r2));
734       // r1 is length of string in characters.
735 
736       ASSERT_EQ(0, num_saved_registers_ % 2);
737       // Always an even number of capture registers. This allows us to
738       // unroll the loop once to add an operation between a load of a register
739       // and the following use of that register.
740       for (int i = 0; i < num_saved_registers_; i += 2) {
741         __ ldr(r2, register_location(i));
742         __ ldr(r3, register_location(i + 1));
743         if (mode_ == UC16) {
744           __ add(r2, r1, Operand(r2, ASR, 1));
745           __ add(r3, r1, Operand(r3, ASR, 1));
746         } else {
747           __ add(r2, r1, Operand(r2));
748           __ add(r3, r1, Operand(r3));
749         }
750         __ str(r2, MemOperand(r0, kPointerSize, PostIndex));
751         __ str(r3, MemOperand(r0, kPointerSize, PostIndex));
752       }
753     }
754     __ mov(r0, Operand(SUCCESS));
755   }
756   // Exit and return r0
757   __ bind(&exit_label_);
758   // Skip sp past regexp registers and local variables..
759   __ mov(sp, frame_pointer());
760   // Restore registers r4..r11 and return (restoring lr to pc).
761   __ ldm(ia_w, sp, registers_to_retain | pc.bit());
762 
763   // Backtrack code (branch target for conditional backtracks).
764   if (backtrack_label_.is_linked()) {
765     __ bind(&backtrack_label_);
766     Backtrack();
767   }
768 
769   Label exit_with_exception;
770 
771   // Preempt-code
772   if (check_preempt_label_.is_linked()) {
773     SafeCallTarget(&check_preempt_label_);
774 
775     CallCheckStackGuardState(r0);
776     __ cmp(r0, Operand(0, RelocInfo::NONE));
777     // If returning non-zero, we should end execution with the given
778     // result as return value.
779     __ b(ne, &exit_label_);
780 
781     // String might have moved: Reload end of string from frame.
782     __ ldr(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
783     SafeReturn();
784   }
785 
786   // Backtrack stack overflow code.
787   if (stack_overflow_label_.is_linked()) {
788     SafeCallTarget(&stack_overflow_label_);
789     // Reached if the backtrack-stack limit has been hit.
790     Label grow_failed;
791 
792     // Call GrowStack(backtrack_stackpointer(), &stack_base)
793     static const int num_arguments = 3;
794     __ PrepareCallCFunction(num_arguments, r0);
795     __ mov(r0, backtrack_stackpointer());
796     __ add(r1, frame_pointer(), Operand(kStackHighEnd));
797     __ mov(r2, Operand(ExternalReference::isolate_address()));
798     ExternalReference grow_stack =
799         ExternalReference::re_grow_stack(masm_->isolate());
800     __ CallCFunction(grow_stack, num_arguments);
801     // If return NULL, we have failed to grow the stack, and
802     // must exit with a stack-overflow exception.
803     __ cmp(r0, Operand(0, RelocInfo::NONE));
804     __ b(eq, &exit_with_exception);
805     // Otherwise use return value as new stack pointer.
806     __ mov(backtrack_stackpointer(), r0);
807     // Restore saved registers and continue.
808     SafeReturn();
809   }
810 
811   if (exit_with_exception.is_linked()) {
812     // If any of the code above needed to exit with an exception.
813     __ bind(&exit_with_exception);
814     // Exit with Result EXCEPTION(-1) to signal thrown exception.
815     __ mov(r0, Operand(EXCEPTION));
816     __ jmp(&exit_label_);
817   }
818 
819   CodeDesc code_desc;
820   masm_->GetCode(&code_desc);
821   Handle<Code> code = FACTORY->NewCode(code_desc,
822                                        Code::ComputeFlags(Code::REGEXP),
823                                        masm_->CodeObject());
824   PROFILE(Isolate::Current(), RegExpCodeCreateEvent(*code, *source));
825   return Handle<HeapObject>::cast(code);
826 }
827 
828 
GoTo(Label * to)829 void RegExpMacroAssemblerARM::GoTo(Label* to) {
830   BranchOrBacktrack(al, to);
831 }
832 
833 
IfRegisterGE(int reg,int comparand,Label * if_ge)834 void RegExpMacroAssemblerARM::IfRegisterGE(int reg,
835                                            int comparand,
836                                            Label* if_ge) {
837   __ ldr(r0, register_location(reg));
838   __ cmp(r0, Operand(comparand));
839   BranchOrBacktrack(ge, if_ge);
840 }
841 
842 
IfRegisterLT(int reg,int comparand,Label * if_lt)843 void RegExpMacroAssemblerARM::IfRegisterLT(int reg,
844                                            int comparand,
845                                            Label* if_lt) {
846   __ ldr(r0, register_location(reg));
847   __ cmp(r0, Operand(comparand));
848   BranchOrBacktrack(lt, if_lt);
849 }
850 
851 
IfRegisterEqPos(int reg,Label * if_eq)852 void RegExpMacroAssemblerARM::IfRegisterEqPos(int reg,
853                                               Label* if_eq) {
854   __ ldr(r0, register_location(reg));
855   __ cmp(r0, Operand(current_input_offset()));
856   BranchOrBacktrack(eq, if_eq);
857 }
858 
859 
860 RegExpMacroAssembler::IrregexpImplementation
Implementation()861     RegExpMacroAssemblerARM::Implementation() {
862   return kARMImplementation;
863 }
864 
865 
LoadCurrentCharacter(int cp_offset,Label * on_end_of_input,bool check_bounds,int characters)866 void RegExpMacroAssemblerARM::LoadCurrentCharacter(int cp_offset,
867                                                    Label* on_end_of_input,
868                                                    bool check_bounds,
869                                                    int characters) {
870   ASSERT(cp_offset >= -1);      // ^ and \b can look behind one character.
871   ASSERT(cp_offset < (1<<30));  // Be sane! (And ensure negation works)
872   if (check_bounds) {
873     CheckPosition(cp_offset + characters - 1, on_end_of_input);
874   }
875   LoadCurrentCharacterUnchecked(cp_offset, characters);
876 }
877 
878 
PopCurrentPosition()879 void RegExpMacroAssemblerARM::PopCurrentPosition() {
880   Pop(current_input_offset());
881 }
882 
883 
PopRegister(int register_index)884 void RegExpMacroAssemblerARM::PopRegister(int register_index) {
885   Pop(r0);
886   __ str(r0, register_location(register_index));
887 }
888 
889 
is_valid_memory_offset(int value)890 static bool is_valid_memory_offset(int value) {
891   if (value < 0) value = -value;
892   return value < (1<<12);
893 }
894 
895 
PushBacktrack(Label * label)896 void RegExpMacroAssemblerARM::PushBacktrack(Label* label) {
897   if (label->is_bound()) {
898     int target = label->pos();
899     __ mov(r0, Operand(target + Code::kHeaderSize - kHeapObjectTag));
900   } else {
901     int constant_offset = GetBacktrackConstantPoolEntry();
902     masm_->label_at_put(label, constant_offset);
903     // Reading pc-relative is based on the address 8 bytes ahead of
904     // the current opcode.
905     unsigned int offset_of_pc_register_read =
906       masm_->pc_offset() + Assembler::kPcLoadDelta;
907     int pc_offset_of_constant =
908       constant_offset - offset_of_pc_register_read;
909     ASSERT(pc_offset_of_constant < 0);
910     if (is_valid_memory_offset(pc_offset_of_constant)) {
911       Assembler::BlockConstPoolScope block_const_pool(masm_);
912       __ ldr(r0, MemOperand(pc, pc_offset_of_constant));
913     } else {
914       // Not a 12-bit offset, so it needs to be loaded from the constant
915       // pool.
916       Assembler::BlockConstPoolScope block_const_pool(masm_);
917       __ mov(r0, Operand(pc_offset_of_constant + Assembler::kInstrSize));
918       __ ldr(r0, MemOperand(pc, r0));
919     }
920   }
921   Push(r0);
922   CheckStackLimit();
923 }
924 
925 
PushCurrentPosition()926 void RegExpMacroAssemblerARM::PushCurrentPosition() {
927   Push(current_input_offset());
928 }
929 
930 
PushRegister(int register_index,StackCheckFlag check_stack_limit)931 void RegExpMacroAssemblerARM::PushRegister(int register_index,
932                                            StackCheckFlag check_stack_limit) {
933   __ ldr(r0, register_location(register_index));
934   Push(r0);
935   if (check_stack_limit) CheckStackLimit();
936 }
937 
938 
ReadCurrentPositionFromRegister(int reg)939 void RegExpMacroAssemblerARM::ReadCurrentPositionFromRegister(int reg) {
940   __ ldr(current_input_offset(), register_location(reg));
941 }
942 
943 
ReadStackPointerFromRegister(int reg)944 void RegExpMacroAssemblerARM::ReadStackPointerFromRegister(int reg) {
945   __ ldr(backtrack_stackpointer(), register_location(reg));
946   __ ldr(r0, MemOperand(frame_pointer(), kStackHighEnd));
947   __ add(backtrack_stackpointer(), backtrack_stackpointer(), Operand(r0));
948 }
949 
950 
SetCurrentPositionFromEnd(int by)951 void RegExpMacroAssemblerARM::SetCurrentPositionFromEnd(int by) {
952   Label after_position;
953   __ cmp(current_input_offset(), Operand(-by * char_size()));
954   __ b(ge, &after_position);
955   __ mov(current_input_offset(), Operand(-by * char_size()));
956   // On RegExp code entry (where this operation is used), the character before
957   // the current position is expected to be already loaded.
958   // We have advanced the position, so it's safe to read backwards.
959   LoadCurrentCharacterUnchecked(-1, 1);
960   __ bind(&after_position);
961 }
962 
963 
SetRegister(int register_index,int to)964 void RegExpMacroAssemblerARM::SetRegister(int register_index, int to) {
965   ASSERT(register_index >= num_saved_registers_);  // Reserved for positions!
966   __ mov(r0, Operand(to));
967   __ str(r0, register_location(register_index));
968 }
969 
970 
Succeed()971 void RegExpMacroAssemblerARM::Succeed() {
972   __ jmp(&success_label_);
973 }
974 
975 
WriteCurrentPositionToRegister(int reg,int cp_offset)976 void RegExpMacroAssemblerARM::WriteCurrentPositionToRegister(int reg,
977                                                              int cp_offset) {
978   if (cp_offset == 0) {
979     __ str(current_input_offset(), register_location(reg));
980   } else {
981     __ add(r0, current_input_offset(), Operand(cp_offset * char_size()));
982     __ str(r0, register_location(reg));
983   }
984 }
985 
986 
ClearRegisters(int reg_from,int reg_to)987 void RegExpMacroAssemblerARM::ClearRegisters(int reg_from, int reg_to) {
988   ASSERT(reg_from <= reg_to);
989   __ ldr(r0, MemOperand(frame_pointer(), kInputStartMinusOne));
990   for (int reg = reg_from; reg <= reg_to; reg++) {
991     __ str(r0, register_location(reg));
992   }
993 }
994 
995 
WriteStackPointerToRegister(int reg)996 void RegExpMacroAssemblerARM::WriteStackPointerToRegister(int reg) {
997   __ ldr(r1, MemOperand(frame_pointer(), kStackHighEnd));
998   __ sub(r0, backtrack_stackpointer(), r1);
999   __ str(r0, register_location(reg));
1000 }
1001 
1002 
1003 // Private methods:
1004 
CallCheckStackGuardState(Register scratch)1005 void RegExpMacroAssemblerARM::CallCheckStackGuardState(Register scratch) {
1006   static const int num_arguments = 3;
1007   __ PrepareCallCFunction(num_arguments, scratch);
1008   // RegExp code frame pointer.
1009   __ mov(r2, frame_pointer());
1010   // Code* of self.
1011   __ mov(r1, Operand(masm_->CodeObject()));
1012   // r0 becomes return address pointer.
1013   ExternalReference stack_guard_check =
1014       ExternalReference::re_check_stack_guard_state(masm_->isolate());
1015   CallCFunctionUsingStub(stack_guard_check, num_arguments);
1016 }
1017 
1018 
1019 // Helper function for reading a value out of a stack frame.
1020 template <typename T>
frame_entry(Address re_frame,int frame_offset)1021 static T& frame_entry(Address re_frame, int frame_offset) {
1022   return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset));
1023 }
1024 
1025 
CheckStackGuardState(Address * return_address,Code * re_code,Address re_frame)1026 int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address,
1027                                                   Code* re_code,
1028                                                   Address re_frame) {
1029   Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
1030   ASSERT(isolate == Isolate::Current());
1031   if (isolate->stack_guard()->IsStackOverflow()) {
1032     isolate->StackOverflow();
1033     return EXCEPTION;
1034   }
1035 
1036   // If not real stack overflow the stack guard was used to interrupt
1037   // execution for another purpose.
1038 
1039   // If this is a direct call from JavaScript retry the RegExp forcing the call
1040   // through the runtime system. Currently the direct call cannot handle a GC.
1041   if (frame_entry<int>(re_frame, kDirectCall) == 1) {
1042     return RETRY;
1043   }
1044 
1045   // Prepare for possible GC.
1046   HandleScope handles(isolate);
1047   Handle<Code> code_handle(re_code);
1048 
1049   Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
1050 
1051   // Current string.
1052   bool is_ascii = subject->IsAsciiRepresentationUnderneath();
1053 
1054   ASSERT(re_code->instruction_start() <= *return_address);
1055   ASSERT(*return_address <=
1056       re_code->instruction_start() + re_code->instruction_size());
1057 
1058   MaybeObject* result = Execution::HandleStackGuardInterrupt(isolate);
1059 
1060   if (*code_handle != re_code) {  // Return address no longer valid
1061     int delta = code_handle->address() - re_code->address();
1062     // Overwrite the return address on the stack.
1063     *return_address += delta;
1064   }
1065 
1066   if (result->IsException()) {
1067     return EXCEPTION;
1068   }
1069 
1070   Handle<String> subject_tmp = subject;
1071   int slice_offset = 0;
1072 
1073   // Extract the underlying string and the slice offset.
1074   if (StringShape(*subject_tmp).IsCons()) {
1075     subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first());
1076   } else if (StringShape(*subject_tmp).IsSliced()) {
1077     SlicedString* slice = SlicedString::cast(*subject_tmp);
1078     subject_tmp = Handle<String>(slice->parent());
1079     slice_offset = slice->offset();
1080   }
1081 
1082   // String might have changed.
1083   if (subject_tmp->IsAsciiRepresentation() != is_ascii) {
1084     // If we changed between an ASCII and an UC16 string, the specialized
1085     // code cannot be used, and we need to restart regexp matching from
1086     // scratch (including, potentially, compiling a new version of the code).
1087     return RETRY;
1088   }
1089 
1090   // Otherwise, the content of the string might have moved. It must still
1091   // be a sequential or external string with the same content.
1092   // Update the start and end pointers in the stack frame to the current
1093   // location (whether it has actually moved or not).
1094   ASSERT(StringShape(*subject_tmp).IsSequential() ||
1095       StringShape(*subject_tmp).IsExternal());
1096 
1097   // The original start address of the characters to match.
1098   const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
1099 
1100   // Find the current start address of the same character at the current string
1101   // position.
1102   int start_index = frame_entry<int>(re_frame, kStartIndex);
1103   const byte* new_address = StringCharacterPosition(*subject_tmp,
1104                                                     start_index + slice_offset);
1105 
1106   if (start_address != new_address) {
1107     // If there is a difference, update the object pointer and start and end
1108     // addresses in the RegExp stack frame to match the new value.
1109     const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
1110     int byte_length = static_cast<int>(end_address - start_address);
1111     frame_entry<const String*>(re_frame, kInputString) = *subject;
1112     frame_entry<const byte*>(re_frame, kInputStart) = new_address;
1113     frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
1114   } else if (frame_entry<const String*>(re_frame, kInputString) != *subject) {
1115     // Subject string might have been a ConsString that underwent
1116     // short-circuiting during GC. That will not change start_address but
1117     // will change pointer inside the subject handle.
1118     frame_entry<const String*>(re_frame, kInputString) = *subject;
1119   }
1120 
1121   return 0;
1122 }
1123 
1124 
register_location(int register_index)1125 MemOperand RegExpMacroAssemblerARM::register_location(int register_index) {
1126   ASSERT(register_index < (1<<30));
1127   if (num_registers_ <= register_index) {
1128     num_registers_ = register_index + 1;
1129   }
1130   return MemOperand(frame_pointer(),
1131                     kRegisterZero - register_index * kPointerSize);
1132 }
1133 
1134 
CheckPosition(int cp_offset,Label * on_outside_input)1135 void RegExpMacroAssemblerARM::CheckPosition(int cp_offset,
1136                                             Label* on_outside_input) {
1137   __ cmp(current_input_offset(), Operand(-cp_offset * char_size()));
1138   BranchOrBacktrack(ge, on_outside_input);
1139 }
1140 
1141 
BranchOrBacktrack(Condition condition,Label * to)1142 void RegExpMacroAssemblerARM::BranchOrBacktrack(Condition condition,
1143                                                 Label* to) {
1144   if (condition == al) {  // Unconditional.
1145     if (to == NULL) {
1146       Backtrack();
1147       return;
1148     }
1149     __ jmp(to);
1150     return;
1151   }
1152   if (to == NULL) {
1153     __ b(condition, &backtrack_label_);
1154     return;
1155   }
1156   __ b(condition, to);
1157 }
1158 
1159 
SafeCall(Label * to,Condition cond)1160 void RegExpMacroAssemblerARM::SafeCall(Label* to, Condition cond) {
1161   __ bl(to, cond);
1162 }
1163 
1164 
SafeReturn()1165 void RegExpMacroAssemblerARM::SafeReturn() {
1166   __ pop(lr);
1167   __ add(pc, lr, Operand(masm_->CodeObject()));
1168 }
1169 
1170 
SafeCallTarget(Label * name)1171 void RegExpMacroAssemblerARM::SafeCallTarget(Label* name) {
1172   __ bind(name);
1173   __ sub(lr, lr, Operand(masm_->CodeObject()));
1174   __ push(lr);
1175 }
1176 
1177 
Push(Register source)1178 void RegExpMacroAssemblerARM::Push(Register source) {
1179   ASSERT(!source.is(backtrack_stackpointer()));
1180   __ str(source,
1181          MemOperand(backtrack_stackpointer(), kPointerSize, NegPreIndex));
1182 }
1183 
1184 
Pop(Register target)1185 void RegExpMacroAssemblerARM::Pop(Register target) {
1186   ASSERT(!target.is(backtrack_stackpointer()));
1187   __ ldr(target,
1188          MemOperand(backtrack_stackpointer(), kPointerSize, PostIndex));
1189 }
1190 
1191 
CheckPreemption()1192 void RegExpMacroAssemblerARM::CheckPreemption() {
1193   // Check for preemption.
1194   ExternalReference stack_limit =
1195       ExternalReference::address_of_stack_limit(masm_->isolate());
1196   __ mov(r0, Operand(stack_limit));
1197   __ ldr(r0, MemOperand(r0));
1198   __ cmp(sp, r0);
1199   SafeCall(&check_preempt_label_, ls);
1200 }
1201 
1202 
CheckStackLimit()1203 void RegExpMacroAssemblerARM::CheckStackLimit() {
1204   ExternalReference stack_limit =
1205       ExternalReference::address_of_regexp_stack_limit(masm_->isolate());
1206   __ mov(r0, Operand(stack_limit));
1207   __ ldr(r0, MemOperand(r0));
1208   __ cmp(backtrack_stackpointer(), Operand(r0));
1209   SafeCall(&stack_overflow_label_, ls);
1210 }
1211 
1212 
EmitBacktrackConstantPool()1213 void RegExpMacroAssemblerARM::EmitBacktrackConstantPool() {
1214   __ CheckConstPool(false, false);
1215   Assembler::BlockConstPoolScope block_const_pool(masm_);
1216   backtrack_constant_pool_offset_ = masm_->pc_offset();
1217   for (int i = 0; i < kBacktrackConstantPoolSize; i++) {
1218     __ emit(0);
1219   }
1220 
1221   backtrack_constant_pool_capacity_ = kBacktrackConstantPoolSize;
1222 }
1223 
1224 
GetBacktrackConstantPoolEntry()1225 int RegExpMacroAssemblerARM::GetBacktrackConstantPoolEntry() {
1226   while (backtrack_constant_pool_capacity_ > 0) {
1227     int offset = backtrack_constant_pool_offset_;
1228     backtrack_constant_pool_offset_ += kPointerSize;
1229     backtrack_constant_pool_capacity_--;
1230     if (masm_->pc_offset() - offset < 2 * KB) {
1231       return offset;
1232     }
1233   }
1234   Label new_pool_skip;
1235   __ jmp(&new_pool_skip);
1236   EmitBacktrackConstantPool();
1237   __ bind(&new_pool_skip);
1238   int offset = backtrack_constant_pool_offset_;
1239   backtrack_constant_pool_offset_ += kPointerSize;
1240   backtrack_constant_pool_capacity_--;
1241   return offset;
1242 }
1243 
1244 
CallCFunctionUsingStub(ExternalReference function,int num_arguments)1245 void RegExpMacroAssemblerARM::CallCFunctionUsingStub(
1246     ExternalReference function,
1247     int num_arguments) {
1248   // Must pass all arguments in registers. The stub pushes on the stack.
1249   ASSERT(num_arguments <= 4);
1250   __ mov(code_pointer(), Operand(function));
1251   RegExpCEntryStub stub;
1252   __ CallStub(&stub);
1253   if (OS::ActivationFrameAlignment() != 0) {
1254     __ ldr(sp, MemOperand(sp, 0));
1255   }
1256   __ mov(code_pointer(), Operand(masm_->CodeObject()));
1257 }
1258 
1259 
LoadCurrentCharacterUnchecked(int cp_offset,int characters)1260 void RegExpMacroAssemblerARM::LoadCurrentCharacterUnchecked(int cp_offset,
1261                                                             int characters) {
1262   Register offset = current_input_offset();
1263   if (cp_offset != 0) {
1264     __ add(r0, current_input_offset(), Operand(cp_offset * char_size()));
1265     offset = r0;
1266   }
1267   // The ldr, str, ldrh, strh instructions can do unaligned accesses, if the CPU
1268   // and the operating system running on the target allow it.
1269   // If unaligned load/stores are not supported then this function must only
1270   // be used to load a single character at a time.
1271 #if !V8_TARGET_CAN_READ_UNALIGNED
1272   ASSERT(characters == 1);
1273 #endif
1274 
1275   if (mode_ == ASCII) {
1276     if (characters == 4) {
1277       __ ldr(current_character(), MemOperand(end_of_input_address(), offset));
1278     } else if (characters == 2) {
1279       __ ldrh(current_character(), MemOperand(end_of_input_address(), offset));
1280     } else {
1281       ASSERT(characters == 1);
1282       __ ldrb(current_character(), MemOperand(end_of_input_address(), offset));
1283     }
1284   } else {
1285     ASSERT(mode_ == UC16);
1286     if (characters == 2) {
1287       __ ldr(current_character(), MemOperand(end_of_input_address(), offset));
1288     } else {
1289       ASSERT(characters == 1);
1290       __ ldrh(current_character(), MemOperand(end_of_input_address(), offset));
1291     }
1292   }
1293 }
1294 
1295 
Generate(MacroAssembler * masm_)1296 void RegExpCEntryStub::Generate(MacroAssembler* masm_) {
1297   int stack_alignment = OS::ActivationFrameAlignment();
1298   if (stack_alignment < kPointerSize) stack_alignment = kPointerSize;
1299   // Stack is already aligned for call, so decrement by alignment
1300   // to make room for storing the link register.
1301   __ str(lr, MemOperand(sp, stack_alignment, NegPreIndex));
1302   __ mov(r0, sp);
1303   __ Call(r5);
1304   __ ldr(pc, MemOperand(sp, stack_alignment, PostIndex));
1305 }
1306 
1307 #undef __
1308 
1309 #endif  // V8_INTERPRETED_REGEXP
1310 
1311 }}  // namespace v8::internal
1312 
1313 #endif  // V8_TARGET_ARCH_ARM
1314