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