Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(188)

Side by Side Diff: src/arm/regexp-macro-assembler-arm.cc

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

Powered by Google App Engine
This is Rietveld 408576698