v8  3.25.30(node0.11.13)
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 V8_TARGET_ARCH_ARM
31 
32 #include "cpu-profiler.h"
33 #include "unicode.h"
34 #include "log.h"
35 #include "code-stubs.h"
36 #include "regexp-stack.h"
37 #include "macro-assembler.h"
38 #include "regexp-macro-assembler.h"
40 
41 namespace v8 {
42 namespace internal {
43 
44 #ifndef V8_INTERPRETED_REGEXP
45 /*
46  * This assembler uses the following register assignment convention
47  * - r4 : Temporarily stores the index of capture start after a matching pass
48  * for a global regexp.
49  * - r5 : Pointer to current code object (Code*) including heap object tag.
50  * - r6 : Current position in input, as negative offset from end of string.
51  * Please notice that this is the byte offset, not the character offset!
52  * - r7 : Currently loaded character. Must be loaded using
53  * LoadCurrentCharacter before using any of the dispatch methods.
54  * - r8 : Points to tip of backtrack stack
55  * - r9 : Unused, might be used by C code and expected unchanged.
56  * - r10 : End of input (points to byte after last character in input).
57  * - r11 : Frame pointer. Used to access arguments, local variables and
58  * RegExp registers.
59  * - r12 : IP register, used by assembler. Very volatile.
60  * - r13/sp : Points to tip of C stack.
61  *
62  * The remaining registers are free for computations.
63  * Each call to a public method should retain this convention.
64  *
65  * The stack will have the following structure:
66  * - fp[56] Isolate* isolate (address of the current isolate)
67  * - fp[52] direct_call (if 1, direct call from JavaScript code,
68  * if 0, call through the runtime system).
69  * - fp[48] stack_area_base (high end of the memory area to use as
70  * backtracking stack).
71  * - fp[44] capture array size (may fit multiple sets of matches)
72  * - fp[40] int* capture_array (int[num_saved_registers_], for output).
73  * - fp[36] secondary link/return address used by native call.
74  * --- sp when called ---
75  * - fp[32] return address (lr).
76  * - fp[28] old frame pointer (r11).
77  * - fp[0..24] backup of registers r4..r10.
78  * --- frame pointer ----
79  * - fp[-4] end of input (address of end of string).
80  * - fp[-8] start of input (address of first character in string).
81  * - fp[-12] start index (character index of start).
82  * - fp[-16] void* input_string (location of a handle containing the string).
83  * - fp[-20] success counter (only for global regexps to count matches).
84  * - fp[-24] Offset of location before start of input (effectively character
85  * position -1). Used to initialize capture registers to a
86  * non-position.
87  * - fp[-28] At start (if 1, we are starting at the start of the
88  * string, otherwise 0)
89  * - fp[-32] register 0 (Only positions must be stored in the first
90  * - register 1 num_saved_registers_ registers)
91  * - ...
92  * - register num_registers-1
93  * --- sp ---
94  *
95  * The first num_saved_registers_ registers are initialized to point to
96  * "character -1" in the string (i.e., char_size() bytes before the first
97  * character of the string). The remaining registers start out as garbage.
98  *
99  * The data up to the return address must be placed there by the calling
100  * code and the remaining arguments are passed in registers, e.g. by calling the
101  * code entry as cast to a function with the signature:
102  * int (*match)(String* input_string,
103  * int start_index,
104  * Address start,
105  * Address end,
106  * Address secondary_return_address, // Only used by native call.
107  * int* capture_output_array,
108  * byte* stack_area_base,
109  * bool direct_call = false)
110  * The call is performed by NativeRegExpMacroAssembler::Execute()
111  * (in regexp-macro-assembler.cc) via the CALL_GENERATED_REGEXP_CODE macro
112  * in arm/simulator-arm.h.
113  * When calling as a non-direct call (i.e., from C++ code), the return address
114  * area is overwritten with the LR register by the RegExp code. When doing a
115  * direct call from generated code, the return address is placed there by
116  * the calling code, as in a normal exit frame.
117  */
118 
119 #define __ ACCESS_MASM(masm_)
120 
122  Mode mode,
123  int registers_to_save,
124  Zone* zone)
125  : NativeRegExpMacroAssembler(zone),
126  masm_(new MacroAssembler(zone->isolate(), NULL, kRegExpCodeSize)),
127  mode_(mode),
128  num_registers_(registers_to_save),
129  num_saved_registers_(registers_to_save),
130  entry_label_(),
131  start_label_(),
132  success_label_(),
133  backtrack_label_(),
134  exit_label_() {
135  ASSERT_EQ(0, registers_to_save % 2);
136  __ jmp(&entry_label_); // We'll write the entry code later.
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::Zero());
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::Zero());
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::CheckGreedyLoop(Label* on_equal) {
239  __ ldr(r0, MemOperand(backtrack_stackpointer(), 0));
240  __ cmp(current_input_offset(), r0);
241  __ add(backtrack_stackpointer(),
242  backtrack_stackpointer(), Operand(kPointerSize), LeaveCC, eq);
243  BranchOrBacktrack(eq, on_equal);
244 }
245 
246 
247 void RegExpMacroAssemblerARM::CheckNotBackReferenceIgnoreCase(
248  int start_reg,
249  Label* on_no_match) {
250  Label fallthrough;
251  __ ldr(r0, register_location(start_reg)); // Index of start of capture
252  __ ldr(r1, register_location(start_reg + 1)); // Index of end of capture
253  __ sub(r1, r1, r0, SetCC); // Length of capture.
254 
255  // If length is zero, either the capture is empty or it is not participating.
256  // In either case succeed immediately.
257  __ b(eq, &fallthrough);
258 
259  // Check that there are enough characters left in the input.
260  __ cmn(r1, Operand(current_input_offset()));
261  BranchOrBacktrack(gt, on_no_match);
262 
263  if (mode_ == ASCII) {
264  Label success;
265  Label fail;
266  Label loop_check;
267 
268  // r0 - offset of start of capture
269  // r1 - length of capture
270  __ add(r0, r0, Operand(end_of_input_address()));
271  __ add(r2, end_of_input_address(), Operand(current_input_offset()));
272  __ add(r1, r0, Operand(r1));
273 
274  // r0 - Address of start of capture.
275  // r1 - Address of end of capture
276  // r2 - Address of current input position.
277 
278  Label loop;
279  __ bind(&loop);
280  __ ldrb(r3, MemOperand(r0, char_size(), PostIndex));
281  __ ldrb(r4, MemOperand(r2, char_size(), PostIndex));
282  __ cmp(r4, r3);
283  __ b(eq, &loop_check);
284 
285  // Mismatch, try case-insensitive match (converting letters to lower-case).
286  __ orr(r3, r3, Operand(0x20)); // Convert capture character to lower-case.
287  __ orr(r4, r4, Operand(0x20)); // Also convert input character.
288  __ cmp(r4, r3);
289  __ b(ne, &fail);
290  __ sub(r3, r3, Operand('a'));
291  __ cmp(r3, Operand('z' - 'a')); // Is r3 a lowercase letter?
292  __ b(ls, &loop_check); // In range 'a'-'z'.
293  // Latin-1: Check for values in range [224,254] but not 247.
294  __ sub(r3, r3, Operand(224 - 'a'));
295  __ cmp(r3, Operand(254 - 224));
296  __ b(hi, &fail); // Weren't Latin-1 letters.
297  __ cmp(r3, Operand(247 - 224)); // Check for 247.
298  __ b(eq, &fail);
299 
300  __ bind(&loop_check);
301  __ cmp(r0, r1);
302  __ b(lt, &loop);
303  __ jmp(&success);
304 
305  __ bind(&fail);
306  BranchOrBacktrack(al, on_no_match);
307 
308  __ bind(&success);
309  // Compute new value of character position after the matched part.
310  __ sub(current_input_offset(), r2, end_of_input_address());
311  } else {
312  ASSERT(mode_ == UC16);
313  int argument_count = 4;
314  __ PrepareCallCFunction(argument_count, r2);
315 
316  // r0 - offset of start of capture
317  // r1 - length of capture
318 
319  // Put arguments into arguments registers.
320  // Parameters are
321  // r0: Address byte_offset1 - Address captured substring's start.
322  // r1: Address byte_offset2 - Address of current character position.
323  // r2: size_t byte_length - length of capture in bytes(!)
324  // r3: Isolate* isolate
325 
326  // Address of start of capture.
327  __ add(r0, r0, Operand(end_of_input_address()));
328  // Length of capture.
329  __ mov(r2, Operand(r1));
330  // Save length in callee-save register for use on return.
331  __ mov(r4, Operand(r1));
332  // Address of current input position.
333  __ add(r1, current_input_offset(), Operand(end_of_input_address()));
334  // Isolate.
335  __ mov(r3, Operand(ExternalReference::isolate_address(isolate())));
336 
337  {
338  AllowExternalCallThatCantCauseGC scope(masm_);
339  ExternalReference function =
340  ExternalReference::re_case_insensitive_compare_uc16(isolate());
341  __ CallCFunction(function, argument_count);
342  }
343 
344  // Check if function returned non-zero for success or zero for failure.
345  __ cmp(r0, Operand::Zero());
346  BranchOrBacktrack(eq, on_no_match);
347  // On success, increment position by length of capture.
348  __ add(current_input_offset(), current_input_offset(), Operand(r4));
349  }
350 
351  __ bind(&fallthrough);
352 }
353 
354 
355 void RegExpMacroAssemblerARM::CheckNotBackReference(
356  int start_reg,
357  Label* on_no_match) {
358  Label fallthrough;
359  Label success;
360 
361  // Find length of back-referenced capture.
362  __ ldr(r0, register_location(start_reg));
363  __ ldr(r1, register_location(start_reg + 1));
364  __ sub(r1, r1, r0, SetCC); // Length to check.
365  // Succeed on empty capture (including no capture).
366  __ b(eq, &fallthrough);
367 
368  // Check that there are enough characters left in the input.
369  __ cmn(r1, Operand(current_input_offset()));
370  BranchOrBacktrack(gt, on_no_match);
371 
372  // Compute pointers to match string and capture string
373  __ add(r0, r0, Operand(end_of_input_address()));
374  __ add(r2, end_of_input_address(), Operand(current_input_offset()));
375  __ add(r1, r1, Operand(r0));
376 
377  Label loop;
378  __ bind(&loop);
379  if (mode_ == ASCII) {
380  __ ldrb(r3, MemOperand(r0, char_size(), PostIndex));
381  __ ldrb(r4, MemOperand(r2, char_size(), PostIndex));
382  } else {
383  ASSERT(mode_ == UC16);
384  __ ldrh(r3, MemOperand(r0, char_size(), PostIndex));
385  __ ldrh(r4, MemOperand(r2, char_size(), PostIndex));
386  }
387  __ cmp(r3, r4);
388  BranchOrBacktrack(ne, on_no_match);
389  __ cmp(r0, r1);
390  __ b(lt, &loop);
391 
392  // Move current character position to position after match.
393  __ sub(current_input_offset(), r2, end_of_input_address());
394  __ bind(&fallthrough);
395 }
396 
397 
398 void RegExpMacroAssemblerARM::CheckNotCharacter(unsigned c,
399  Label* on_not_equal) {
400  __ cmp(current_character(), Operand(c));
401  BranchOrBacktrack(ne, on_not_equal);
402 }
403 
404 
405 void RegExpMacroAssemblerARM::CheckCharacterAfterAnd(uint32_t c,
406  uint32_t mask,
407  Label* on_equal) {
408  if (c == 0) {
409  __ tst(current_character(), Operand(mask));
410  } else {
411  __ and_(r0, current_character(), Operand(mask));
412  __ cmp(r0, Operand(c));
413  }
414  BranchOrBacktrack(eq, on_equal);
415 }
416 
417 
418 void RegExpMacroAssemblerARM::CheckNotCharacterAfterAnd(unsigned c,
419  unsigned mask,
420  Label* on_not_equal) {
421  if (c == 0) {
422  __ tst(current_character(), Operand(mask));
423  } else {
424  __ and_(r0, current_character(), Operand(mask));
425  __ cmp(r0, Operand(c));
426  }
427  BranchOrBacktrack(ne, on_not_equal);
428 }
429 
430 
431 void RegExpMacroAssemblerARM::CheckNotCharacterAfterMinusAnd(
432  uc16 c,
433  uc16 minus,
434  uc16 mask,
435  Label* on_not_equal) {
436  ASSERT(minus < String::kMaxUtf16CodeUnit);
437  __ sub(r0, current_character(), Operand(minus));
438  __ and_(r0, r0, Operand(mask));
439  __ cmp(r0, Operand(c));
440  BranchOrBacktrack(ne, on_not_equal);
441 }
442 
443 
444 void RegExpMacroAssemblerARM::CheckCharacterInRange(
445  uc16 from,
446  uc16 to,
447  Label* on_in_range) {
448  __ sub(r0, current_character(), Operand(from));
449  __ cmp(r0, Operand(to - from));
450  BranchOrBacktrack(ls, on_in_range); // Unsigned lower-or-same condition.
451 }
452 
453 
454 void RegExpMacroAssemblerARM::CheckCharacterNotInRange(
455  uc16 from,
456  uc16 to,
457  Label* on_not_in_range) {
458  __ sub(r0, current_character(), Operand(from));
459  __ cmp(r0, Operand(to - from));
460  BranchOrBacktrack(hi, on_not_in_range); // Unsigned higher condition.
461 }
462 
463 
464 void RegExpMacroAssemblerARM::CheckBitInTable(
465  Handle<ByteArray> table,
466  Label* on_bit_set) {
467  __ mov(r0, Operand(table));
468  if (mode_ != ASCII || kTableMask != String::kMaxOneByteCharCode) {
469  __ and_(r1, current_character(), Operand(kTableSize - 1));
470  __ add(r1, r1, Operand(ByteArray::kHeaderSize - kHeapObjectTag));
471  } else {
472  __ add(r1,
473  current_character(),
474  Operand(ByteArray::kHeaderSize - kHeapObjectTag));
475  }
476  __ ldrb(r0, MemOperand(r0, r1));
477  __ cmp(r0, Operand::Zero());
478  BranchOrBacktrack(ne, on_bit_set);
479 }
480 
481 
482 bool RegExpMacroAssemblerARM::CheckSpecialCharacterClass(uc16 type,
483  Label* on_no_match) {
484  // Range checks (c in min..max) are generally implemented by an unsigned
485  // (c - min) <= (max - min) check
486  switch (type) {
487  case 's':
488  // Match space-characters
489  if (mode_ == ASCII) {
490  // One byte space characters are '\t'..'\r', ' ' and \u00a0.
491  Label success;
492  __ cmp(current_character(), Operand(' '));
493  __ b(eq, &success);
494  // Check range 0x09..0x0d
495  __ sub(r0, current_character(), Operand('\t'));
496  __ cmp(r0, Operand('\r' - '\t'));
497  __ b(ls, &success);
498  // \u00a0 (NBSP).
499  __ cmp(r0, Operand(0x00a0 - '\t'));
500  BranchOrBacktrack(ne, on_no_match);
501  __ bind(&success);
502  return true;
503  }
504  return false;
505  case 'S':
506  // The emitted code for generic character classes is good enough.
507  return false;
508  case 'd':
509  // Match ASCII digits ('0'..'9')
510  __ sub(r0, current_character(), Operand('0'));
511  __ cmp(r0, Operand('9' - '0'));
512  BranchOrBacktrack(hi, on_no_match);
513  return true;
514  case 'D':
515  // Match non ASCII-digits
516  __ sub(r0, current_character(), Operand('0'));
517  __ cmp(r0, Operand('9' - '0'));
518  BranchOrBacktrack(ls, on_no_match);
519  return true;
520  case '.': {
521  // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
522  __ eor(r0, current_character(), Operand(0x01));
523  // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
524  __ sub(r0, r0, Operand(0x0b));
525  __ cmp(r0, Operand(0x0c - 0x0b));
526  BranchOrBacktrack(ls, on_no_match);
527  if (mode_ == UC16) {
528  // Compare original value to 0x2028 and 0x2029, using the already
529  // computed (current_char ^ 0x01 - 0x0b). I.e., check for
530  // 0x201d (0x2028 - 0x0b) or 0x201e.
531  __ sub(r0, r0, Operand(0x2028 - 0x0b));
532  __ cmp(r0, Operand(1));
533  BranchOrBacktrack(ls, on_no_match);
534  }
535  return true;
536  }
537  case 'n': {
538  // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
539  __ eor(r0, current_character(), Operand(0x01));
540  // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
541  __ sub(r0, r0, Operand(0x0b));
542  __ cmp(r0, Operand(0x0c - 0x0b));
543  if (mode_ == ASCII) {
544  BranchOrBacktrack(hi, on_no_match);
545  } else {
546  Label done;
547  __ b(ls, &done);
548  // Compare original value to 0x2028 and 0x2029, using the already
549  // computed (current_char ^ 0x01 - 0x0b). I.e., check for
550  // 0x201d (0x2028 - 0x0b) or 0x201e.
551  __ sub(r0, r0, Operand(0x2028 - 0x0b));
552  __ cmp(r0, Operand(1));
553  BranchOrBacktrack(hi, on_no_match);
554  __ bind(&done);
555  }
556  return true;
557  }
558  case 'w': {
559  if (mode_ != ASCII) {
560  // Table is 128 entries, so all ASCII characters can be tested.
561  __ cmp(current_character(), Operand('z'));
562  BranchOrBacktrack(hi, on_no_match);
563  }
564  ExternalReference map = ExternalReference::re_word_character_map();
565  __ mov(r0, Operand(map));
566  __ ldrb(r0, MemOperand(r0, current_character()));
567  __ cmp(r0, Operand::Zero());
568  BranchOrBacktrack(eq, on_no_match);
569  return true;
570  }
571  case 'W': {
572  Label done;
573  if (mode_ != ASCII) {
574  // Table is 128 entries, so all ASCII characters can be tested.
575  __ cmp(current_character(), Operand('z'));
576  __ b(hi, &done);
577  }
578  ExternalReference map = ExternalReference::re_word_character_map();
579  __ mov(r0, Operand(map));
580  __ ldrb(r0, MemOperand(r0, current_character()));
581  __ cmp(r0, Operand::Zero());
582  BranchOrBacktrack(ne, on_no_match);
583  if (mode_ != ASCII) {
584  __ bind(&done);
585  }
586  return true;
587  }
588  case '*':
589  // Match any character.
590  return true;
591  // No custom implementation (yet): s(UC16), S(UC16).
592  default:
593  return false;
594  }
595 }
596 
597 
599  __ mov(r0, Operand(FAILURE));
600  __ jmp(&exit_label_);
601 }
602 
603 
604 Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
605  Label return_r0;
606  // Finalize code - write the entry point code now we know how many
607  // registers we need.
608 
609  // Entry code:
610  __ bind(&entry_label_);
611 
612  // Tell the system that we have a stack frame. Because the type is MANUAL, no
613  // is generated.
614  FrameScope scope(masm_, StackFrame::MANUAL);
615 
616  // Actually emit code to start a new stack frame.
617  // Push arguments
618  // Save callee-save registers.
619  // Start new stack frame.
620  // Store link register in existing stack-cell.
621  // Order here should correspond to order of offset constants in header file.
622  RegList registers_to_retain = r4.bit() | r5.bit() | r6.bit() |
623  r7.bit() | r8.bit() | r9.bit() | r10.bit() | fp.bit();
624  RegList argument_registers = r0.bit() | r1.bit() | r2.bit() | r3.bit();
625  __ stm(db_w, sp, argument_registers | registers_to_retain | lr.bit());
626  // Set frame pointer in space for it if this is not a direct call
627  // from generated code.
628  __ add(frame_pointer(), sp, Operand(4 * kPointerSize));
629  __ mov(r0, Operand::Zero());
630  __ push(r0); // Make room for success counter and initialize it to 0.
631  __ push(r0); // Make room for "position - 1" constant (value is irrelevant).
632  // Check if we have space on the stack for registers.
633  Label stack_limit_hit;
634  Label stack_ok;
635 
636  ExternalReference stack_limit =
637  ExternalReference::address_of_stack_limit(isolate());
638  __ mov(r0, Operand(stack_limit));
639  __ ldr(r0, MemOperand(r0));
640  __ sub(r0, sp, r0, SetCC);
641  // Handle it if the stack pointer is already below the stack limit.
642  __ b(ls, &stack_limit_hit);
643  // Check if there is room for the variable number of registers above
644  // the stack limit.
645  __ cmp(r0, Operand(num_registers_ * kPointerSize));
646  __ b(hs, &stack_ok);
647  // Exit with OutOfMemory exception. There is not enough space on the stack
648  // for our working registers.
649  __ mov(r0, Operand(EXCEPTION));
650  __ jmp(&return_r0);
651 
652  __ bind(&stack_limit_hit);
653  CallCheckStackGuardState(r0);
654  __ cmp(r0, Operand::Zero());
655  // If returned value is non-zero, we exit with the returned value as result.
656  __ b(ne, &return_r0);
657 
658  __ bind(&stack_ok);
659 
660  // Allocate space on stack for registers.
661  __ sub(sp, sp, Operand(num_registers_ * kPointerSize));
662  // Load string end.
663  __ ldr(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
664  // Load input start.
665  __ ldr(r0, MemOperand(frame_pointer(), kInputStart));
666  // Find negative length (offset of start relative to end).
667  __ sub(current_input_offset(), r0, end_of_input_address());
668  // Set r0 to address of char before start of the input string
669  // (effectively string position -1).
670  __ ldr(r1, MemOperand(frame_pointer(), kStartIndex));
671  __ sub(r0, current_input_offset(), Operand(char_size()));
672  __ sub(r0, r0, Operand(r1, LSL, (mode_ == UC16) ? 1 : 0));
673  // Store this value in a local variable, for use when clearing
674  // position registers.
675  __ str(r0, MemOperand(frame_pointer(), kInputStartMinusOne));
676 
677  // Initialize code pointer register
678  __ mov(code_pointer(), Operand(masm_->CodeObject()));
679 
680  Label load_char_start_regexp, start_regexp;
681  // Load newline if index is at start, previous character otherwise.
682  __ cmp(r1, Operand::Zero());
683  __ b(ne, &load_char_start_regexp);
684  __ mov(current_character(), Operand('\n'), LeaveCC, eq);
685  __ jmp(&start_regexp);
686 
687  // Global regexp restarts matching here.
688  __ bind(&load_char_start_regexp);
689  // Load previous char as initial value of current character register.
690  LoadCurrentCharacterUnchecked(-1, 1);
691  __ bind(&start_regexp);
692 
693  // Initialize on-stack registers.
694  if (num_saved_registers_ > 0) { // Always is, if generated from a regexp.
695  // Fill saved registers with initial value = start offset - 1
696  if (num_saved_registers_ > 8) {
697  // Address of register 0.
698  __ add(r1, frame_pointer(), Operand(kRegisterZero));
699  __ mov(r2, Operand(num_saved_registers_));
700  Label init_loop;
701  __ bind(&init_loop);
703  __ sub(r2, r2, Operand(1), SetCC);
704  __ b(ne, &init_loop);
705  } else {
706  for (int i = 0; i < num_saved_registers_; i++) {
707  __ str(r0, register_location(i));
708  }
709  }
710  }
711 
712  // Initialize backtrack stack pointer.
713  __ ldr(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackHighEnd));
714 
715  __ jmp(&start_label_);
716 
717  // Exit code:
718  if (success_label_.is_linked()) {
719  // Save captures when successful.
720  __ bind(&success_label_);
721  if (num_saved_registers_ > 0) {
722  // copy captures to output
723  __ ldr(r1, MemOperand(frame_pointer(), kInputStart));
724  __ ldr(r0, MemOperand(frame_pointer(), kRegisterOutput));
725  __ ldr(r2, MemOperand(frame_pointer(), kStartIndex));
726  __ sub(r1, end_of_input_address(), r1);
727  // r1 is length of input in bytes.
728  if (mode_ == UC16) {
729  __ mov(r1, Operand(r1, LSR, 1));
730  }
731  // r1 is length of input in characters.
732  __ add(r1, r1, Operand(r2));
733  // r1 is length of string in characters.
734 
735  ASSERT_EQ(0, num_saved_registers_ % 2);
736  // Always an even number of capture registers. This allows us to
737  // unroll the loop once to add an operation between a load of a register
738  // and the following use of that register.
739  for (int i = 0; i < num_saved_registers_; i += 2) {
740  __ ldr(r2, register_location(i));
741  __ ldr(r3, register_location(i + 1));
742  if (i == 0 && global_with_zero_length_check()) {
743  // Keep capture start in r4 for the zero-length check later.
744  __ mov(r4, r2);
745  }
746  if (mode_ == UC16) {
747  __ add(r2, r1, Operand(r2, ASR, 1));
748  __ add(r3, r1, Operand(r3, ASR, 1));
749  } else {
750  __ add(r2, r1, Operand(r2));
751  __ add(r3, r1, Operand(r3));
752  }
755  }
756  }
757 
758  if (global()) {
759  // Restart matching if the regular expression is flagged as global.
760  __ ldr(r0, MemOperand(frame_pointer(), kSuccessfulCaptures));
761  __ ldr(r1, MemOperand(frame_pointer(), kNumOutputRegisters));
762  __ ldr(r2, MemOperand(frame_pointer(), kRegisterOutput));
763  // Increment success counter.
764  __ add(r0, r0, Operand(1));
765  __ str(r0, MemOperand(frame_pointer(), kSuccessfulCaptures));
766  // Capture results have been stored, so the number of remaining global
767  // output registers is reduced by the number of stored captures.
768  __ sub(r1, r1, Operand(num_saved_registers_));
769  // Check whether we have enough room for another set of capture results.
770  __ cmp(r1, Operand(num_saved_registers_));
771  __ b(lt, &return_r0);
772 
773  __ str(r1, MemOperand(frame_pointer(), kNumOutputRegisters));
774  // Advance the location for output.
775  __ add(r2, r2, Operand(num_saved_registers_ * kPointerSize));
776  __ str(r2, MemOperand(frame_pointer(), kRegisterOutput));
777 
778  // Prepare r0 to initialize registers with its value in the next run.
779  __ ldr(r0, MemOperand(frame_pointer(), kInputStartMinusOne));
780 
781  if (global_with_zero_length_check()) {
782  // Special case for zero-length matches.
783  // r4: capture start index
784  __ cmp(current_input_offset(), r4);
785  // Not a zero-length match, restart.
786  __ b(ne, &load_char_start_regexp);
787  // Offset from the end is zero if we already reached the end.
788  __ cmp(current_input_offset(), Operand::Zero());
789  __ b(eq, &exit_label_);
790  // Advance current position after a zero-length match.
791  __ add(current_input_offset(),
792  current_input_offset(),
793  Operand((mode_ == UC16) ? 2 : 1));
794  }
795 
796  __ b(&load_char_start_regexp);
797  } else {
798  __ mov(r0, Operand(SUCCESS));
799  }
800  }
801 
802  // Exit and return r0
803  __ bind(&exit_label_);
804  if (global()) {
805  __ ldr(r0, MemOperand(frame_pointer(), kSuccessfulCaptures));
806  }
807 
808  __ bind(&return_r0);
809  // Skip sp past regexp registers and local variables..
810  __ mov(sp, frame_pointer());
811  // Restore registers r4..r11 and return (restoring lr to pc).
812  __ ldm(ia_w, sp, registers_to_retain | pc.bit());
813 
814  // Backtrack code (branch target for conditional backtracks).
815  if (backtrack_label_.is_linked()) {
816  __ bind(&backtrack_label_);
817  Backtrack();
818  }
819 
820  Label exit_with_exception;
821 
822  // Preempt-code
823  if (check_preempt_label_.is_linked()) {
824  SafeCallTarget(&check_preempt_label_);
825 
826  CallCheckStackGuardState(r0);
827  __ cmp(r0, Operand::Zero());
828  // If returning non-zero, we should end execution with the given
829  // result as return value.
830  __ b(ne, &return_r0);
831 
832  // String might have moved: Reload end of string from frame.
833  __ ldr(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
834  SafeReturn();
835  }
836 
837  // Backtrack stack overflow code.
838  if (stack_overflow_label_.is_linked()) {
839  SafeCallTarget(&stack_overflow_label_);
840  // Reached if the backtrack-stack limit has been hit.
841  Label grow_failed;
842 
843  // Call GrowStack(backtrack_stackpointer(), &stack_base)
844  static const int num_arguments = 3;
845  __ PrepareCallCFunction(num_arguments, r0);
846  __ mov(r0, backtrack_stackpointer());
847  __ add(r1, frame_pointer(), Operand(kStackHighEnd));
848  __ mov(r2, Operand(ExternalReference::isolate_address(isolate())));
849  ExternalReference grow_stack =
850  ExternalReference::re_grow_stack(isolate());
851  __ CallCFunction(grow_stack, num_arguments);
852  // If return NULL, we have failed to grow the stack, and
853  // must exit with a stack-overflow exception.
854  __ cmp(r0, Operand::Zero());
855  __ b(eq, &exit_with_exception);
856  // Otherwise use return value as new stack pointer.
857  __ mov(backtrack_stackpointer(), r0);
858  // Restore saved registers and continue.
859  SafeReturn();
860  }
861 
862  if (exit_with_exception.is_linked()) {
863  // If any of the code above needed to exit with an exception.
864  __ bind(&exit_with_exception);
865  // Exit with Result EXCEPTION(-1) to signal thrown exception.
866  __ mov(r0, Operand(EXCEPTION));
867  __ jmp(&return_r0);
868  }
869 
870  CodeDesc code_desc;
871  masm_->GetCode(&code_desc);
872  Handle<Code> code = isolate()->factory()->NewCode(
873  code_desc, Code::ComputeFlags(Code::REGEXP), masm_->CodeObject());
874  PROFILE(masm_->isolate(), RegExpCodeCreateEvent(*code, *source));
875  return Handle<HeapObject>::cast(code);
876 }
877 
878 
879 void RegExpMacroAssemblerARM::GoTo(Label* to) {
880  BranchOrBacktrack(al, to);
881 }
882 
883 
884 void RegExpMacroAssemblerARM::IfRegisterGE(int reg,
885  int comparand,
886  Label* if_ge) {
887  __ ldr(r0, register_location(reg));
888  __ cmp(r0, Operand(comparand));
889  BranchOrBacktrack(ge, if_ge);
890 }
891 
892 
893 void RegExpMacroAssemblerARM::IfRegisterLT(int reg,
894  int comparand,
895  Label* if_lt) {
896  __ ldr(r0, register_location(reg));
897  __ cmp(r0, Operand(comparand));
898  BranchOrBacktrack(lt, if_lt);
899 }
900 
901 
902 void RegExpMacroAssemblerARM::IfRegisterEqPos(int reg,
903  Label* if_eq) {
904  __ ldr(r0, register_location(reg));
905  __ cmp(r0, Operand(current_input_offset()));
906  BranchOrBacktrack(eq, if_eq);
907 }
908 
909 
910 RegExpMacroAssembler::IrregexpImplementation
911  RegExpMacroAssemblerARM::Implementation() {
912  return kARMImplementation;
913 }
914 
915 
916 void RegExpMacroAssemblerARM::LoadCurrentCharacter(int cp_offset,
917  Label* on_end_of_input,
918  bool check_bounds,
919  int characters) {
920  ASSERT(cp_offset >= -1); // ^ and \b can look behind one character.
921  ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works)
922  if (check_bounds) {
923  CheckPosition(cp_offset + characters - 1, on_end_of_input);
924  }
925  LoadCurrentCharacterUnchecked(cp_offset, characters);
926 }
927 
928 
929 void RegExpMacroAssemblerARM::PopCurrentPosition() {
930  Pop(current_input_offset());
931 }
932 
933 
934 void RegExpMacroAssemblerARM::PopRegister(int register_index) {
935  Pop(r0);
936  __ str(r0, register_location(register_index));
937 }
938 
939 
940 void RegExpMacroAssemblerARM::PushBacktrack(Label* label) {
941  __ mov_label_offset(r0, label);
942  Push(r0);
943  CheckStackLimit();
944 }
945 
946 
947 void RegExpMacroAssemblerARM::PushCurrentPosition() {
948  Push(current_input_offset());
949 }
950 
951 
952 void RegExpMacroAssemblerARM::PushRegister(int register_index,
953  StackCheckFlag check_stack_limit) {
954  __ ldr(r0, register_location(register_index));
955  Push(r0);
956  if (check_stack_limit) CheckStackLimit();
957 }
958 
959 
960 void RegExpMacroAssemblerARM::ReadCurrentPositionFromRegister(int reg) {
961  __ ldr(current_input_offset(), register_location(reg));
962 }
963 
964 
965 void RegExpMacroAssemblerARM::ReadStackPointerFromRegister(int reg) {
966  __ ldr(backtrack_stackpointer(), register_location(reg));
967  __ ldr(r0, MemOperand(frame_pointer(), kStackHighEnd));
968  __ add(backtrack_stackpointer(), backtrack_stackpointer(), Operand(r0));
969 }
970 
971 
972 void RegExpMacroAssemblerARM::SetCurrentPositionFromEnd(int by) {
973  Label after_position;
974  __ cmp(current_input_offset(), Operand(-by * char_size()));
975  __ b(ge, &after_position);
976  __ mov(current_input_offset(), Operand(-by * char_size()));
977  // On RegExp code entry (where this operation is used), the character before
978  // the current position is expected to be already loaded.
979  // We have advanced the position, so it's safe to read backwards.
980  LoadCurrentCharacterUnchecked(-1, 1);
981  __ bind(&after_position);
982 }
983 
984 
985 void RegExpMacroAssemblerARM::SetRegister(int register_index, int to) {
986  ASSERT(register_index >= num_saved_registers_); // Reserved for positions!
987  __ mov(r0, Operand(to));
988  __ str(r0, register_location(register_index));
989 }
990 
991 
992 bool RegExpMacroAssemblerARM::Succeed() {
993  __ jmp(&success_label_);
994  return global();
995 }
996 
997 
998 void RegExpMacroAssemblerARM::WriteCurrentPositionToRegister(int reg,
999  int cp_offset) {
1000  if (cp_offset == 0) {
1001  __ str(current_input_offset(), register_location(reg));
1002  } else {
1003  __ add(r0, current_input_offset(), Operand(cp_offset * char_size()));
1004  __ str(r0, register_location(reg));
1005  }
1006 }
1007 
1008 
1009 void RegExpMacroAssemblerARM::ClearRegisters(int reg_from, int reg_to) {
1010  ASSERT(reg_from <= reg_to);
1011  __ ldr(r0, MemOperand(frame_pointer(), kInputStartMinusOne));
1012  for (int reg = reg_from; reg <= reg_to; reg++) {
1013  __ str(r0, register_location(reg));
1014  }
1015 }
1016 
1017 
1018 void RegExpMacroAssemblerARM::WriteStackPointerToRegister(int reg) {
1019  __ ldr(r1, MemOperand(frame_pointer(), kStackHighEnd));
1020  __ sub(r0, backtrack_stackpointer(), r1);
1021  __ str(r0, register_location(reg));
1022 }
1023 
1024 
1025 // Private methods:
1026 
1027 void RegExpMacroAssemblerARM::CallCheckStackGuardState(Register scratch) {
1028  __ PrepareCallCFunction(3, scratch);
1029 
1030  // RegExp code frame pointer.
1031  __ mov(r2, frame_pointer());
1032  // Code* of self.
1033  __ mov(r1, Operand(masm_->CodeObject()));
1034 
1035  // We need to make room for the return address on the stack.
1036  int stack_alignment = OS::ActivationFrameAlignment();
1037  ASSERT(IsAligned(stack_alignment, kPointerSize));
1038  __ sub(sp, sp, Operand(stack_alignment));
1039 
1040  // r0 will point to the return address, placed by DirectCEntry.
1041  __ mov(r0, sp);
1042 
1043  ExternalReference stack_guard_check =
1044  ExternalReference::re_check_stack_guard_state(isolate());
1045  __ mov(ip, Operand(stack_guard_check));
1046  DirectCEntryStub stub;
1047  stub.GenerateCall(masm_, ip);
1048 
1049  // Drop the return address from the stack.
1050  __ add(sp, sp, Operand(stack_alignment));
1051 
1052  ASSERT(stack_alignment != 0);
1053  __ ldr(sp, MemOperand(sp, 0));
1054 
1055  __ mov(code_pointer(), Operand(masm_->CodeObject()));
1056 }
1057 
1058 
1059 // Helper function for reading a value out of a stack frame.
1060 template <typename T>
1061 static T& frame_entry(Address re_frame, int frame_offset) {
1062  return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset));
1063 }
1064 
1065 
1066 int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address,
1067  Code* re_code,
1068  Address re_frame) {
1069  Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
1070  if (isolate->stack_guard()->IsStackOverflow()) {
1071  isolate->StackOverflow();
1072  return EXCEPTION;
1073  }
1074 
1075  // If not real stack overflow the stack guard was used to interrupt
1076  // execution for another purpose.
1077 
1078  // If this is a direct call from JavaScript retry the RegExp forcing the call
1079  // through the runtime system. Currently the direct call cannot handle a GC.
1080  if (frame_entry<int>(re_frame, kDirectCall) == 1) {
1081  return RETRY;
1082  }
1083 
1084  // Prepare for possible GC.
1085  HandleScope handles(isolate);
1086  Handle<Code> code_handle(re_code);
1087 
1088  Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
1089 
1090  // Current string.
1091  bool is_ascii = subject->IsOneByteRepresentationUnderneath();
1092 
1093  ASSERT(re_code->instruction_start() <= *return_address);
1094  ASSERT(*return_address <=
1095  re_code->instruction_start() + re_code->instruction_size());
1096 
1097  MaybeObject* result = Execution::HandleStackGuardInterrupt(isolate);
1098 
1099  if (*code_handle != re_code) { // Return address no longer valid
1100  int delta = code_handle->address() - re_code->address();
1101  // Overwrite the return address on the stack.
1102  *return_address += delta;
1103  }
1104 
1105  if (result->IsException()) {
1106  return EXCEPTION;
1107  }
1108 
1109  Handle<String> subject_tmp = subject;
1110  int slice_offset = 0;
1111 
1112  // Extract the underlying string and the slice offset.
1113  if (StringShape(*subject_tmp).IsCons()) {
1114  subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first());
1115  } else if (StringShape(*subject_tmp).IsSliced()) {
1116  SlicedString* slice = SlicedString::cast(*subject_tmp);
1117  subject_tmp = Handle<String>(slice->parent());
1118  slice_offset = slice->offset();
1119  }
1120 
1121  // String might have changed.
1122  if (subject_tmp->IsOneByteRepresentation() != is_ascii) {
1123  // If we changed between an ASCII and an UC16 string, the specialized
1124  // code cannot be used, and we need to restart regexp matching from
1125  // scratch (including, potentially, compiling a new version of the code).
1126  return RETRY;
1127  }
1128 
1129  // Otherwise, the content of the string might have moved. It must still
1130  // be a sequential or external string with the same content.
1131  // Update the start and end pointers in the stack frame to the current
1132  // location (whether it has actually moved or not).
1133  ASSERT(StringShape(*subject_tmp).IsSequential() ||
1134  StringShape(*subject_tmp).IsExternal());
1135 
1136  // The original start address of the characters to match.
1137  const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
1138 
1139  // Find the current start address of the same character at the current string
1140  // position.
1141  int start_index = frame_entry<int>(re_frame, kStartIndex);
1142  const byte* new_address = StringCharacterPosition(*subject_tmp,
1143  start_index + slice_offset);
1144 
1145  if (start_address != new_address) {
1146  // If there is a difference, update the object pointer and start and end
1147  // addresses in the RegExp stack frame to match the new value.
1148  const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
1149  int byte_length = static_cast<int>(end_address - start_address);
1150  frame_entry<const String*>(re_frame, kInputString) = *subject;
1151  frame_entry<const byte*>(re_frame, kInputStart) = new_address;
1152  frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
1153  } else if (frame_entry<const String*>(re_frame, kInputString) != *subject) {
1154  // Subject string might have been a ConsString that underwent
1155  // short-circuiting during GC. That will not change start_address but
1156  // will change pointer inside the subject handle.
1157  frame_entry<const String*>(re_frame, kInputString) = *subject;
1158  }
1159 
1160  return 0;
1161 }
1162 
1163 
1164 MemOperand RegExpMacroAssemblerARM::register_location(int register_index) {
1165  ASSERT(register_index < (1<<30));
1166  if (num_registers_ <= register_index) {
1167  num_registers_ = register_index + 1;
1168  }
1169  return MemOperand(frame_pointer(),
1170  kRegisterZero - register_index * kPointerSize);
1171 }
1172 
1173 
1174 void RegExpMacroAssemblerARM::CheckPosition(int cp_offset,
1175  Label* on_outside_input) {
1176  __ cmp(current_input_offset(), Operand(-cp_offset * char_size()));
1177  BranchOrBacktrack(ge, on_outside_input);
1178 }
1179 
1180 
1181 void RegExpMacroAssemblerARM::BranchOrBacktrack(Condition condition,
1182  Label* to) {
1183  if (condition == al) { // Unconditional.
1184  if (to == NULL) {
1185  Backtrack();
1186  return;
1187  }
1188  __ jmp(to);
1189  return;
1190  }
1191  if (to == NULL) {
1192  __ b(condition, &backtrack_label_);
1193  return;
1194  }
1195  __ b(condition, to);
1196 }
1197 
1198 
1199 void RegExpMacroAssemblerARM::SafeCall(Label* to, Condition cond) {
1200  __ bl(to, cond);
1201 }
1202 
1203 
1204 void RegExpMacroAssemblerARM::SafeReturn() {
1205  __ pop(lr);
1206  __ add(pc, lr, Operand(masm_->CodeObject()));
1207 }
1208 
1209 
1210 void RegExpMacroAssemblerARM::SafeCallTarget(Label* name) {
1211  __ bind(name);
1212  __ sub(lr, lr, Operand(masm_->CodeObject()));
1213  __ push(lr);
1214 }
1215 
1216 
1217 void RegExpMacroAssemblerARM::Push(Register source) {
1218  ASSERT(!source.is(backtrack_stackpointer()));
1219  __ str(source,
1220  MemOperand(backtrack_stackpointer(), kPointerSize, NegPreIndex));
1221 }
1222 
1223 
1224 void RegExpMacroAssemblerARM::Pop(Register target) {
1225  ASSERT(!target.is(backtrack_stackpointer()));
1226  __ ldr(target,
1227  MemOperand(backtrack_stackpointer(), kPointerSize, PostIndex));
1228 }
1229 
1230 
1231 void RegExpMacroAssemblerARM::CheckPreemption() {
1232  // Check for preemption.
1233  ExternalReference stack_limit =
1234  ExternalReference::address_of_stack_limit(isolate());
1235  __ mov(r0, Operand(stack_limit));
1236  __ ldr(r0, MemOperand(r0));
1237  __ cmp(sp, r0);
1238  SafeCall(&check_preempt_label_, ls);
1239 }
1240 
1241 
1242 void RegExpMacroAssemblerARM::CheckStackLimit() {
1243  ExternalReference stack_limit =
1244  ExternalReference::address_of_regexp_stack_limit(isolate());
1245  __ mov(r0, Operand(stack_limit));
1246  __ ldr(r0, MemOperand(r0));
1247  __ cmp(backtrack_stackpointer(), Operand(r0));
1248  SafeCall(&stack_overflow_label_, ls);
1249 }
1250 
1251 
1252 bool RegExpMacroAssemblerARM::CanReadUnaligned() {
1253  return CpuFeatures::IsSupported(UNALIGNED_ACCESSES) && !slow_safe();
1254 }
1255 
1256 
1257 void RegExpMacroAssemblerARM::LoadCurrentCharacterUnchecked(int cp_offset,
1258  int characters) {
1259  Register offset = current_input_offset();
1260  if (cp_offset != 0) {
1261  // r4 is not being used to store the capture start index at this point.
1262  __ add(r4, current_input_offset(), Operand(cp_offset * char_size()));
1263  offset = r4;
1264  }
1265  // The ldr, str, ldrh, strh instructions can do unaligned accesses, if the CPU
1266  // and the operating system running on the target allow it.
1267  // If unaligned load/stores are not supported then this function must only
1268  // be used to load a single character at a time.
1269  if (!CanReadUnaligned()) {
1270  ASSERT(characters == 1);
1271  }
1272 
1273  if (mode_ == ASCII) {
1274  if (characters == 4) {
1275  __ ldr(current_character(), MemOperand(end_of_input_address(), offset));
1276  } else if (characters == 2) {
1277  __ ldrh(current_character(), MemOperand(end_of_input_address(), offset));
1278  } else {
1279  ASSERT(characters == 1);
1280  __ ldrb(current_character(), MemOperand(end_of_input_address(), offset));
1281  }
1282  } else {
1283  ASSERT(mode_ == UC16);
1284  if (characters == 2) {
1285  __ ldr(current_character(), MemOperand(end_of_input_address(), offset));
1286  } else {
1287  ASSERT(characters == 1);
1288  __ ldrh(current_character(), MemOperand(end_of_input_address(), offset));
1289  }
1290  }
1291 }
1292 
1293 
1294 #undef __
1295 
1296 #endif // V8_INTERPRETED_REGEXP
1297 
1298 }} // namespace v8::internal
1299 
1300 #endif // V8_TARGET_ARCH_ARM
byte * Address
Definition: globals.h:186
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter NULL
Definition: flags.cc:269
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter NULL
void Fail(const v8::FunctionCallbackInfo< v8::Value > &args)
unsigned char byte
Definition: disasm.h:33
#define PROFILE(IsolateGetter, Call)
Definition: cpu-profiler.h:194
const Register r3
const Register r6
uint32_t RegList
Definition: frames.h:41
#define ASSERT(condition)
Definition: checks.h:329
const Register r2
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes number of stack frames inspected by the profiler percentage of ICs that must have type info to allow optimization 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 VFP3 instructions if available enable use of NEON instructions if 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 d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long expose natives in global object expose freeBuffer extension expose gc extension under the specified name expose externalize string extension number of stack frames to capture disable builtin natives files print name of functions for which code is generated use random jit cookie to mask large constants trace lazy optimization use adaptive optimizations always try to OSR functions trace optimize function deoptimization minimum length for automatic enable preparsing maximum number of optimization attempts before giving up cache prototype transitions trace debugging JSON request response trace out of bounds accesses to external arrays trace_js_array_abuse automatically set the debug break flag when debugger commands are in the queue abort by crashing maximum length of function source code printed in a stack trace max size of the new max size of the old max size of executable always perform global GCs print one trace line following each garbage collection do not print trace line after scavenger collection print statistics of the maximum memory committed for the heap in name
const Register sp
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes number of stack frames inspected by the profiler percentage of ICs that must have type info to allow optimization 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 VFP3 instructions if available enable use of NEON instructions if 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 d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long mode(MIPS only)") DEFINE_string(expose_natives_as
const Register ip
const Register r9
const int kPointerSize
Definition: globals.h:268
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf map
const int kHeapObjectTag
Definition: v8.h:5473
bool IsAligned(T value, U alignment)
Definition: utils.h:211
#define __
const Register pc
const Register r0
#define T(name, string, precedence)
Definition: token.cc:48
const Register lr
const Register r1
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes number of stack frames inspected by the profiler percentage of ICs that must have type info to allow optimization extra verbose compilation tracing generate extra code(assertions) for debugging") DEFINE_bool(code_comments
uint16_t uc16
Definition: globals.h:309
const Register r8
#define ASSERT_EQ(v1, v2)
Definition: checks.h:330
RegExpMacroAssemblerARM(Mode mode, int registers_to_save, Zone *zone)
const Register r10
const Register fp
const Register r5
const Register r4
const Register r7