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