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