blob: 1c59823436460946891cf82b27b0f93acfc6ea37 [file] [log] [blame]
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001// Copyright 2009 the V8 project authors. All rights reserved.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002// 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
ager@chromium.orga74f0da2008-12-03 16:05:52 +000028#include "v8.h"
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000029
30#if defined(V8_TARGET_ARCH_ARM)
31
ager@chromium.org18ad94b2009-09-02 08:22:29 +000032#include "unicode.h"
33#include "log.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000034#include "code-stubs.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000035#include "regexp-stack.h"
36#include "macro-assembler.h"
ager@chromium.orga74f0da2008-12-03 16:05:52 +000037#include "regexp-macro-assembler.h"
ager@chromium.org3a37e9b2009-04-27 09:26:21 +000038#include "arm/regexp-macro-assembler-arm.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000039
kasperl@chromium.org71affb52009-05-26 05:44:31 +000040namespace v8 {
41namespace internal {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000042
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000043#ifndef V8_INTERPRETED_REGEXP
ager@chromium.org18ad94b2009-09-02 08:22:29 +000044/*
45 * This assembler uses the following register assignment convention
46 * - r5 : Pointer to current code object (Code*) including heap object tag.
47 * - r6 : Current position in input, as negative offset from end of string.
48 * Please notice that this is the byte offset, not the character offset!
49 * - r7 : Currently loaded character. Must be loaded using
50 * LoadCurrentCharacter before using any of the dispatch methods.
51 * - r8 : points to tip of backtrack stack
52 * - r9 : Unused, might be used by C code and expected unchanged.
53 * - r10 : End of input (points to byte after last character in input).
54 * - r11 : Frame pointer. Used to access arguments, local variables and
55 * RegExp registers.
56 * - r12 : IP register, used by assembler. Very volatile.
57 * - r13/sp : points to tip of C stack.
58 *
59 * The remaining registers are free for computations.
ager@chromium.org18ad94b2009-09-02 08:22:29 +000060 * Each call to a public method should retain this convention.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000061 *
ager@chromium.org18ad94b2009-09-02 08:22:29 +000062 * The stack will have the following structure:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000063 * - fp[52] Isolate* isolate (Address of the current isolate)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000064 * - fp[48] direct_call (if 1, direct call from JavaScript code,
65 * if 0, call through the runtime system).
66 * - fp[44] stack_area_base (High end of the memory area to use as
67 * backtracking stack).
68 * - fp[40] int* capture_array (int[num_saved_registers_], for output).
69 * - fp[36] secondary link/return address used by native call.
70 * --- sp when called ---
71 * - fp[32] return address (lr).
72 * - fp[28] old frame pointer (r11).
73 * - fp[0..24] backup of registers r4..r10.
74 * --- frame pointer ----
75 * - fp[-4] end of input (Address of end of string).
76 * - fp[-8] start of input (Address of first character in string).
77 * - fp[-12] start index (character index of start).
78 * - fp[-16] void* input_string (location of a handle containing the string).
79 * - fp[-20] Offset of location before start of input (effectively character
80 * position -1). Used to initialize capture registers to a
81 * non-position.
82 * - fp[-24] At start (if 1, we are starting at the start of the
83 * string, otherwise 0)
84 * - fp[-28] register 0 (Only positions must be stored in the first
85 * - register 1 num_saved_registers_ registers)
86 * - ...
87 * - register num_registers-1
88 * --- sp ---
ager@chromium.org18ad94b2009-09-02 08:22:29 +000089 *
90 * The first num_saved_registers_ registers are initialized to point to
91 * "character -1" in the string (i.e., char_size() bytes before the first
92 * character of the string). The remaining registers start out as garbage.
93 *
94 * The data up to the return address must be placed there by the calling
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000095 * code and the remaining arguments are passed in registers, e.g. by calling the
96 * code entry as cast to a function with the signature:
ager@chromium.org18ad94b2009-09-02 08:22:29 +000097 * int (*match)(String* input_string,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000098 * int start_index,
ager@chromium.org18ad94b2009-09-02 08:22:29 +000099 * Address start,
100 * Address end,
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000101 * Address secondary_return_address, // Only used by native call.
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000102 * int* capture_output_array,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000103 * byte* stack_area_base,
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000104 * bool direct_call = false)
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000105 * The call is performed by NativeRegExpMacroAssembler::Execute()
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000106 * (in regexp-macro-assembler.cc) via the CALL_GENERATED_REGEXP_CODE macro
107 * in arm/simulator-arm.h.
108 * When calling as a non-direct call (i.e., from C++ code), the return address
109 * area is overwritten with the LR register by the RegExp code. When doing a
110 * direct call from generated code, the return address is placed there by
111 * the calling code, as in a normal exit frame.
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000112 */
113
114#define __ ACCESS_MASM(masm_)
115
116RegExpMacroAssemblerARM::RegExpMacroAssemblerARM(
117 Mode mode,
118 int registers_to_save)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000119 : masm_(new MacroAssembler(Isolate::Current(), NULL, kRegExpCodeSize)),
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000120 mode_(mode),
121 num_registers_(registers_to_save),
122 num_saved_registers_(registers_to_save),
123 entry_label_(),
124 start_label_(),
125 success_label_(),
126 backtrack_label_(),
127 exit_label_() {
128 ASSERT_EQ(0, registers_to_save % 2);
129 __ jmp(&entry_label_); // We'll write the entry code later.
130 EmitBacktrackConstantPool();
131 __ bind(&start_label_); // And then continue from here.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000132}
133
134
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000135RegExpMacroAssemblerARM::~RegExpMacroAssemblerARM() {
136 delete masm_;
137 // Unuse labels in case we throw away the assembler without calling GetCode.
138 entry_label_.Unuse();
139 start_label_.Unuse();
140 success_label_.Unuse();
141 backtrack_label_.Unuse();
142 exit_label_.Unuse();
143 check_preempt_label_.Unuse();
144 stack_overflow_label_.Unuse();
145}
146
147
148int RegExpMacroAssemblerARM::stack_limit_slack() {
149 return RegExpStack::kStackLimitSlack;
150}
151
152
153void RegExpMacroAssemblerARM::AdvanceCurrentPosition(int by) {
154 if (by != 0) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000155 __ add(current_input_offset(),
156 current_input_offset(), Operand(by * char_size()));
157 }
158}
159
160
161void RegExpMacroAssemblerARM::AdvanceRegister(int reg, int by) {
162 ASSERT(reg >= 0);
163 ASSERT(reg < num_registers_);
164 if (by != 0) {
165 __ ldr(r0, register_location(reg));
166 __ add(r0, r0, Operand(by));
167 __ str(r0, register_location(reg));
168 }
169}
170
171
172void RegExpMacroAssemblerARM::Backtrack() {
173 CheckPreemption();
174 // Pop Code* offset from backtrack stack, add Code* and jump to location.
175 Pop(r0);
ager@chromium.org357bf652010-04-12 11:30:10 +0000176 __ add(pc, r0, Operand(code_pointer()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000177}
178
179
180void RegExpMacroAssemblerARM::Bind(Label* label) {
181 __ bind(label);
182}
183
184
185void RegExpMacroAssemblerARM::CheckCharacter(uint32_t c, Label* on_equal) {
186 __ cmp(current_character(), Operand(c));
187 BranchOrBacktrack(eq, on_equal);
188}
189
190
191void RegExpMacroAssemblerARM::CheckCharacterGT(uc16 limit, Label* on_greater) {
192 __ cmp(current_character(), Operand(limit));
193 BranchOrBacktrack(gt, on_greater);
194}
195
196
197void RegExpMacroAssemblerARM::CheckAtStart(Label* on_at_start) {
198 Label not_at_start;
199 // Did we start the match at the start of the string at all?
200 __ ldr(r0, MemOperand(frame_pointer(), kAtStart));
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000201 __ cmp(r0, Operand(0, RelocInfo::NONE));
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000202 BranchOrBacktrack(eq, &not_at_start);
203
204 // If we did, are we still at the start of the input?
205 __ ldr(r1, MemOperand(frame_pointer(), kInputStart));
206 __ add(r0, end_of_input_address(), Operand(current_input_offset()));
207 __ cmp(r0, r1);
208 BranchOrBacktrack(eq, on_at_start);
209 __ bind(&not_at_start);
210}
211
212
213void RegExpMacroAssemblerARM::CheckNotAtStart(Label* on_not_at_start) {
214 // Did we start the match at the start of the string at all?
215 __ ldr(r0, MemOperand(frame_pointer(), kAtStart));
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000216 __ cmp(r0, Operand(0, RelocInfo::NONE));
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000217 BranchOrBacktrack(eq, on_not_at_start);
218 // If we did, are we still at the start of the input?
219 __ ldr(r1, MemOperand(frame_pointer(), kInputStart));
220 __ add(r0, end_of_input_address(), Operand(current_input_offset()));
221 __ cmp(r0, r1);
222 BranchOrBacktrack(ne, on_not_at_start);
223}
224
225
226void RegExpMacroAssemblerARM::CheckCharacterLT(uc16 limit, Label* on_less) {
227 __ cmp(current_character(), Operand(limit));
228 BranchOrBacktrack(lt, on_less);
229}
230
231
232void RegExpMacroAssemblerARM::CheckCharacters(Vector<const uc16> str,
233 int cp_offset,
234 Label* on_failure,
235 bool check_end_of_string) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000236 if (on_failure == NULL) {
ager@chromium.orga1645e22009-09-09 19:27:10 +0000237 // Instead of inlining a backtrack for each test, (re)use the global
238 // backtrack target.
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000239 on_failure = &backtrack_label_;
240 }
241
ager@chromium.orga1645e22009-09-09 19:27:10 +0000242 if (check_end_of_string) {
243 // Is last character of required match inside string.
244 CheckPosition(cp_offset + str.length() - 1, on_failure);
245 }
246
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000247 __ add(r0, end_of_input_address(), Operand(current_input_offset()));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000248 if (cp_offset != 0) {
249 int byte_offset = cp_offset * char_size();
250 __ add(r0, r0, Operand(byte_offset));
251 }
252
253 // r0 : Address of characters to match against str.
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000254 int stored_high_byte = 0;
255 for (int i = 0; i < str.length(); i++) {
256 if (mode_ == ASCII) {
257 __ ldrb(r1, MemOperand(r0, char_size(), PostIndex));
ager@chromium.orga1645e22009-09-09 19:27:10 +0000258 ASSERT(str[i] <= String::kMaxAsciiCharCode);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000259 __ cmp(r1, Operand(str[i]));
260 } else {
261 __ ldrh(r1, MemOperand(r0, char_size(), PostIndex));
262 uc16 match_char = str[i];
263 int match_high_byte = (match_char >> 8);
264 if (match_high_byte == 0) {
265 __ cmp(r1, Operand(str[i]));
266 } else {
267 if (match_high_byte != stored_high_byte) {
268 __ mov(r2, Operand(match_high_byte));
269 stored_high_byte = match_high_byte;
270 }
271 __ add(r3, r2, Operand(match_char & 0xff));
272 __ cmp(r1, r3);
273 }
274 }
275 BranchOrBacktrack(ne, on_failure);
276 }
277}
278
279
280void RegExpMacroAssemblerARM::CheckGreedyLoop(Label* on_equal) {
281 __ ldr(r0, MemOperand(backtrack_stackpointer(), 0));
282 __ cmp(current_input_offset(), r0);
283 __ add(backtrack_stackpointer(),
284 backtrack_stackpointer(), Operand(kPointerSize), LeaveCC, eq);
285 BranchOrBacktrack(eq, on_equal);
286}
287
288
289void RegExpMacroAssemblerARM::CheckNotBackReferenceIgnoreCase(
290 int start_reg,
291 Label* on_no_match) {
292 Label fallthrough;
293 __ ldr(r0, register_location(start_reg)); // Index of start of capture
294 __ ldr(r1, register_location(start_reg + 1)); // Index of end of capture
295 __ sub(r1, r1, r0, SetCC); // Length of capture.
296
297 // If length is zero, either the capture is empty or it is not participating.
298 // In either case succeed immediately.
299 __ b(eq, &fallthrough);
300
301 // Check that there are enough characters left in the input.
302 __ cmn(r1, Operand(current_input_offset()));
303 BranchOrBacktrack(gt, on_no_match);
304
305 if (mode_ == ASCII) {
306 Label success;
307 Label fail;
308 Label loop_check;
309
310 // r0 - offset of start of capture
311 // r1 - length of capture
312 __ add(r0, r0, Operand(end_of_input_address()));
313 __ add(r2, end_of_input_address(), Operand(current_input_offset()));
314 __ add(r1, r0, Operand(r1));
315
316 // r0 - Address of start of capture.
317 // r1 - Address of end of capture
318 // r2 - Address of current input position.
319
320 Label loop;
321 __ bind(&loop);
322 __ ldrb(r3, MemOperand(r0, char_size(), PostIndex));
323 __ ldrb(r4, MemOperand(r2, char_size(), PostIndex));
324 __ cmp(r4, r3);
325 __ b(eq, &loop_check);
326
327 // Mismatch, try case-insensitive match (converting letters to lower-case).
328 __ orr(r3, r3, Operand(0x20)); // Convert capture character to lower-case.
329 __ orr(r4, r4, Operand(0x20)); // Also convert input character.
330 __ cmp(r4, r3);
331 __ b(ne, &fail);
332 __ sub(r3, r3, Operand('a'));
333 __ cmp(r3, Operand('z' - 'a')); // Is r3 a lowercase letter?
334 __ b(hi, &fail);
335
336
337 __ bind(&loop_check);
338 __ cmp(r0, r1);
339 __ b(lt, &loop);
340 __ jmp(&success);
341
342 __ bind(&fail);
343 BranchOrBacktrack(al, on_no_match);
344
345 __ bind(&success);
346 // Compute new value of character position after the matched part.
347 __ sub(current_input_offset(), r2, end_of_input_address());
348 } else {
349 ASSERT(mode_ == UC16);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000350 int argument_count = 4;
ager@chromium.org357bf652010-04-12 11:30:10 +0000351 __ PrepareCallCFunction(argument_count, r2);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000352
353 // r0 - offset of start of capture
354 // r1 - length of capture
355
356 // Put arguments into arguments registers.
357 // Parameters are
358 // r0: Address byte_offset1 - Address captured substring's start.
359 // r1: Address byte_offset2 - Address of current character position.
360 // r2: size_t byte_length - length of capture in bytes(!)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000361 // r3: Isolate* isolate
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000362
363 // Address of start of capture.
364 __ add(r0, r0, Operand(end_of_input_address()));
365 // Length of capture.
366 __ mov(r2, Operand(r1));
367 // Save length in callee-save register for use on return.
368 __ mov(r4, Operand(r1));
369 // Address of current input position.
370 __ add(r1, current_input_offset(), Operand(end_of_input_address()));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000371 // Isolate.
372 __ mov(r3, Operand(ExternalReference::isolate_address()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000373
374 ExternalReference function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000375 ExternalReference::re_case_insensitive_compare_uc16(masm_->isolate());
ager@chromium.org357bf652010-04-12 11:30:10 +0000376 __ CallCFunction(function, argument_count);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000377
378 // Check if function returned non-zero for success or zero for failure.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000379 __ cmp(r0, Operand(0, RelocInfo::NONE));
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000380 BranchOrBacktrack(eq, on_no_match);
381 // On success, increment position by length of capture.
382 __ add(current_input_offset(), current_input_offset(), Operand(r4));
383 }
384
385 __ bind(&fallthrough);
386}
387
388
389void RegExpMacroAssemblerARM::CheckNotBackReference(
390 int start_reg,
391 Label* on_no_match) {
392 Label fallthrough;
393 Label success;
394
395 // Find length of back-referenced capture.
396 __ ldr(r0, register_location(start_reg));
397 __ ldr(r1, register_location(start_reg + 1));
398 __ sub(r1, r1, r0, SetCC); // Length to check.
399 // Succeed on empty capture (including no capture).
400 __ b(eq, &fallthrough);
401
402 // Check that there are enough characters left in the input.
403 __ cmn(r1, Operand(current_input_offset()));
404 BranchOrBacktrack(gt, on_no_match);
405
406 // Compute pointers to match string and capture string
407 __ add(r0, r0, Operand(end_of_input_address()));
408 __ add(r2, end_of_input_address(), Operand(current_input_offset()));
409 __ add(r1, r1, Operand(r0));
410
411 Label loop;
412 __ bind(&loop);
413 if (mode_ == ASCII) {
414 __ ldrb(r3, MemOperand(r0, char_size(), PostIndex));
415 __ ldrb(r4, MemOperand(r2, char_size(), PostIndex));
416 } else {
417 ASSERT(mode_ == UC16);
418 __ ldrh(r3, MemOperand(r0, char_size(), PostIndex));
419 __ ldrh(r4, MemOperand(r2, char_size(), PostIndex));
420 }
421 __ cmp(r3, r4);
422 BranchOrBacktrack(ne, on_no_match);
423 __ cmp(r0, r1);
424 __ b(lt, &loop);
425
426 // Move current character position to position after match.
427 __ sub(current_input_offset(), r2, end_of_input_address());
428 __ bind(&fallthrough);
429}
430
431
432void RegExpMacroAssemblerARM::CheckNotRegistersEqual(int reg1,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000433 int reg2,
434 Label* on_not_equal) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000435 __ ldr(r0, register_location(reg1));
436 __ ldr(r1, register_location(reg2));
437 __ cmp(r0, r1);
438 BranchOrBacktrack(ne, on_not_equal);
439}
440
441
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000442void RegExpMacroAssemblerARM::CheckNotCharacter(unsigned c,
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000443 Label* on_not_equal) {
444 __ cmp(current_character(), Operand(c));
445 BranchOrBacktrack(ne, on_not_equal);
446}
447
448
449void RegExpMacroAssemblerARM::CheckCharacterAfterAnd(uint32_t c,
450 uint32_t mask,
451 Label* on_equal) {
452 __ and_(r0, current_character(), Operand(mask));
453 __ cmp(r0, Operand(c));
454 BranchOrBacktrack(eq, on_equal);
455}
456
457
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000458void RegExpMacroAssemblerARM::CheckNotCharacterAfterAnd(unsigned c,
459 unsigned mask,
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000460 Label* on_not_equal) {
461 __ and_(r0, current_character(), Operand(mask));
462 __ cmp(r0, Operand(c));
463 BranchOrBacktrack(ne, on_not_equal);
464}
465
466
467void RegExpMacroAssemblerARM::CheckNotCharacterAfterMinusAnd(
468 uc16 c,
469 uc16 minus,
470 uc16 mask,
471 Label* on_not_equal) {
472 ASSERT(minus < String::kMaxUC16CharCode);
473 __ sub(r0, current_character(), Operand(minus));
474 __ and_(r0, r0, Operand(mask));
475 __ cmp(r0, Operand(c));
476 BranchOrBacktrack(ne, on_not_equal);
477}
478
479
480bool RegExpMacroAssemblerARM::CheckSpecialCharacterClass(uc16 type,
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000481 Label* on_no_match) {
482 // Range checks (c in min..max) are generally implemented by an unsigned
483 // (c - min) <= (max - min) check
484 switch (type) {
485 case 's':
486 // Match space-characters
487 if (mode_ == ASCII) {
488 // ASCII space characters are '\t'..'\r' and ' '.
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000489 Label success;
490 __ cmp(current_character(), Operand(' '));
491 __ b(eq, &success);
492 // Check range 0x09..0x0d
493 __ sub(r0, current_character(), Operand('\t'));
494 __ cmp(r0, Operand('\r' - '\t'));
495 BranchOrBacktrack(hi, on_no_match);
496 __ bind(&success);
497 return true;
498 }
499 return false;
500 case 'S':
501 // Match non-space characters.
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000502 if (mode_ == ASCII) {
503 // ASCII space characters are '\t'..'\r' and ' '.
504 __ cmp(current_character(), Operand(' '));
505 BranchOrBacktrack(eq, on_no_match);
506 __ sub(r0, current_character(), Operand('\t'));
507 __ cmp(r0, Operand('\r' - '\t'));
508 BranchOrBacktrack(ls, on_no_match);
509 return true;
510 }
511 return false;
512 case 'd':
513 // Match ASCII digits ('0'..'9')
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000514 __ sub(r0, current_character(), Operand('0'));
515 __ cmp(current_character(), Operand('9' - '0'));
516 BranchOrBacktrack(hi, on_no_match);
517 return true;
518 case 'D':
519 // Match non ASCII-digits
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000520 __ sub(r0, current_character(), Operand('0'));
521 __ cmp(r0, Operand('9' - '0'));
522 BranchOrBacktrack(ls, on_no_match);
523 return true;
524 case '.': {
525 // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000526 __ eor(r0, current_character(), Operand(0x01));
527 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
528 __ sub(r0, r0, Operand(0x0b));
529 __ cmp(r0, Operand(0x0c - 0x0b));
530 BranchOrBacktrack(ls, on_no_match);
531 if (mode_ == UC16) {
532 // Compare original value to 0x2028 and 0x2029, using the already
533 // computed (current_char ^ 0x01 - 0x0b). I.e., check for
534 // 0x201d (0x2028 - 0x0b) or 0x201e.
535 __ sub(r0, r0, Operand(0x2028 - 0x0b));
536 __ cmp(r0, Operand(1));
537 BranchOrBacktrack(ls, on_no_match);
538 }
539 return true;
540 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000541 case 'n': {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000542 // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
543 __ eor(r0, current_character(), Operand(0x01));
544 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
545 __ sub(r0, r0, Operand(0x0b));
546 __ cmp(r0, Operand(0x0c - 0x0b));
547 if (mode_ == ASCII) {
548 BranchOrBacktrack(hi, on_no_match);
549 } else {
550 Label done;
551 __ b(ls, &done);
552 // Compare original value to 0x2028 and 0x2029, using the already
553 // computed (current_char ^ 0x01 - 0x0b). I.e., check for
554 // 0x201d (0x2028 - 0x0b) or 0x201e.
555 __ sub(r0, r0, Operand(0x2028 - 0x0b));
556 __ cmp(r0, Operand(1));
557 BranchOrBacktrack(hi, on_no_match);
558 __ bind(&done);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000559 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000560 return true;
561 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000562 case 'w': {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000563 if (mode_ != ASCII) {
564 // Table is 128 entries, so all ASCII characters can be tested.
565 __ cmp(current_character(), Operand('z'));
566 BranchOrBacktrack(hi, on_no_match);
567 }
568 ExternalReference map = ExternalReference::re_word_character_map();
569 __ mov(r0, Operand(map));
570 __ ldrb(r0, MemOperand(r0, current_character()));
571 __ tst(r0, Operand(r0));
572 BranchOrBacktrack(eq, on_no_match);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000573 return true;
574 }
575 case 'W': {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000576 Label done;
577 if (mode_ != ASCII) {
578 // Table is 128 entries, so all ASCII characters can be tested.
579 __ cmp(current_character(), Operand('z'));
580 __ b(hi, &done);
581 }
582 ExternalReference map = ExternalReference::re_word_character_map();
583 __ mov(r0, Operand(map));
584 __ ldrb(r0, MemOperand(r0, current_character()));
585 __ tst(r0, Operand(r0));
586 BranchOrBacktrack(ne, on_no_match);
587 if (mode_ != ASCII) {
588 __ bind(&done);
589 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000590 return true;
591 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000592 case '*':
593 // Match any character.
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000594 return true;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000595 // No custom implementation (yet): s(UC16), S(UC16).
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000596 default:
597 return false;
598 }
599}
600
601
602void RegExpMacroAssemblerARM::Fail() {
603 __ mov(r0, Operand(FAILURE));
604 __ jmp(&exit_label_);
605}
606
607
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000608Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000609 // Finalize code - write the entry point code now we know how many
610 // registers we need.
611
612 // Entry code:
613 __ bind(&entry_label_);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000614 // Push arguments
615 // Save callee-save registers.
616 // Start new stack frame.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000617 // Store link register in existing stack-cell.
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000618 // Order here should correspond to order of offset constants in header file.
619 RegList registers_to_retain = r4.bit() | r5.bit() | r6.bit() |
620 r7.bit() | r8.bit() | r9.bit() | r10.bit() | fp.bit();
621 RegList argument_registers = r0.bit() | r1.bit() | r2.bit() | r3.bit();
622 __ stm(db_w, sp, argument_registers | registers_to_retain | lr.bit());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000623 // Set frame pointer in space for it if this is not a direct call
624 // from generated code.
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000625 __ add(frame_pointer(), sp, Operand(4 * kPointerSize));
626 __ push(r0); // Make room for "position - 1" constant (value is irrelevant).
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000627 __ push(r0); // Make room for "at start" constant (value is irrelevant).
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000628 // Check if we have space on the stack for registers.
629 Label stack_limit_hit;
630 Label stack_ok;
631
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000632 ExternalReference stack_limit =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000633 ExternalReference::address_of_stack_limit(masm_->isolate());
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000634 __ mov(r0, Operand(stack_limit));
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000635 __ ldr(r0, MemOperand(r0));
636 __ sub(r0, sp, r0, SetCC);
637 // Handle it if the stack pointer is already below the stack limit.
638 __ b(ls, &stack_limit_hit);
639 // Check if there is room for the variable number of registers above
640 // the stack limit.
641 __ cmp(r0, Operand(num_registers_ * kPointerSize));
642 __ b(hs, &stack_ok);
643 // Exit with OutOfMemory exception. There is not enough space on the stack
644 // for our working registers.
645 __ mov(r0, Operand(EXCEPTION));
646 __ jmp(&exit_label_);
647
648 __ bind(&stack_limit_hit);
649 CallCheckStackGuardState(r0);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000650 __ cmp(r0, Operand(0, RelocInfo::NONE));
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000651 // If returned value is non-zero, we exit with the returned value as result.
652 __ b(ne, &exit_label_);
653
654 __ bind(&stack_ok);
655
656 // Allocate space on stack for registers.
657 __ sub(sp, sp, Operand(num_registers_ * kPointerSize));
658 // Load string end.
659 __ ldr(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
660 // Load input start.
661 __ ldr(r0, MemOperand(frame_pointer(), kInputStart));
662 // Find negative length (offset of start relative to end).
663 __ sub(current_input_offset(), r0, end_of_input_address());
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000664 // Set r0 to address of char before start of the input string
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000665 // (effectively string position -1).
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000666 __ ldr(r1, MemOperand(frame_pointer(), kStartIndex));
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000667 __ sub(r0, current_input_offset(), Operand(char_size()));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000668 __ sub(r0, r0, Operand(r1, LSL, (mode_ == UC16) ? 1 : 0));
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000669 // Store this value in a local variable, for use when clearing
670 // position registers.
671 __ str(r0, MemOperand(frame_pointer(), kInputStartMinusOne));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000672
673 // Determine whether the start index is zero, that is at the start of the
674 // string, and store that value in a local variable.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000675 __ tst(r1, Operand(r1));
676 __ mov(r1, Operand(1), LeaveCC, eq);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000677 __ mov(r1, Operand(0, RelocInfo::NONE), LeaveCC, ne);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000678 __ str(r1, MemOperand(frame_pointer(), kAtStart));
679
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000680 if (num_saved_registers_ > 0) { // Always is, if generated from a regexp.
681 // Fill saved registers with initial value = start offset - 1
682
683 // Address of register 0.
684 __ add(r1, frame_pointer(), Operand(kRegisterZero));
685 __ mov(r2, Operand(num_saved_registers_));
686 Label init_loop;
687 __ bind(&init_loop);
688 __ str(r0, MemOperand(r1, kPointerSize, NegPostIndex));
689 __ sub(r2, r2, Operand(1), SetCC);
690 __ b(ne, &init_loop);
691 }
692
693 // Initialize backtrack stack pointer.
694 __ ldr(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackHighEnd));
695 // Initialize code pointer register
696 __ mov(code_pointer(), Operand(masm_->CodeObject()));
697 // Load previous char as initial value of current character register.
698 Label at_start;
699 __ ldr(r0, MemOperand(frame_pointer(), kAtStart));
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000700 __ cmp(r0, Operand(0, RelocInfo::NONE));
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000701 __ b(ne, &at_start);
702 LoadCurrentCharacterUnchecked(-1, 1); // Load previous char.
703 __ jmp(&start_label_);
704 __ bind(&at_start);
705 __ mov(current_character(), Operand('\n'));
706 __ jmp(&start_label_);
707
708
709 // Exit code:
710 if (success_label_.is_linked()) {
711 // Save captures when successful.
712 __ bind(&success_label_);
713 if (num_saved_registers_ > 0) {
714 // copy captures to output
715 __ ldr(r1, MemOperand(frame_pointer(), kInputStart));
716 __ ldr(r0, MemOperand(frame_pointer(), kRegisterOutput));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000717 __ ldr(r2, MemOperand(frame_pointer(), kStartIndex));
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000718 __ sub(r1, end_of_input_address(), r1);
719 // r1 is length of input in bytes.
720 if (mode_ == UC16) {
721 __ mov(r1, Operand(r1, LSR, 1));
722 }
723 // r1 is length of input in characters.
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000724 __ add(r1, r1, Operand(r2));
725 // r1 is length of string in characters.
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000726
727 ASSERT_EQ(0, num_saved_registers_ % 2);
728 // Always an even number of capture registers. This allows us to
729 // unroll the loop once to add an operation between a load of a register
730 // and the following use of that register.
731 for (int i = 0; i < num_saved_registers_; i += 2) {
732 __ ldr(r2, register_location(i));
733 __ ldr(r3, register_location(i + 1));
734 if (mode_ == UC16) {
735 __ add(r2, r1, Operand(r2, ASR, 1));
736 __ add(r3, r1, Operand(r3, ASR, 1));
737 } else {
738 __ add(r2, r1, Operand(r2));
739 __ add(r3, r1, Operand(r3));
740 }
741 __ str(r2, MemOperand(r0, kPointerSize, PostIndex));
742 __ str(r3, MemOperand(r0, kPointerSize, PostIndex));
743 }
744 }
745 __ mov(r0, Operand(SUCCESS));
746 }
747 // Exit and return r0
748 __ bind(&exit_label_);
749 // Skip sp past regexp registers and local variables..
750 __ mov(sp, frame_pointer());
751 // Restore registers r4..r11 and return (restoring lr to pc).
752 __ ldm(ia_w, sp, registers_to_retain | pc.bit());
753
754 // Backtrack code (branch target for conditional backtracks).
755 if (backtrack_label_.is_linked()) {
756 __ bind(&backtrack_label_);
757 Backtrack();
758 }
759
760 Label exit_with_exception;
761
762 // Preempt-code
763 if (check_preempt_label_.is_linked()) {
764 SafeCallTarget(&check_preempt_label_);
765
766 CallCheckStackGuardState(r0);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000767 __ cmp(r0, Operand(0, RelocInfo::NONE));
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000768 // If returning non-zero, we should end execution with the given
769 // result as return value.
770 __ b(ne, &exit_label_);
771
772 // String might have moved: Reload end of string from frame.
773 __ ldr(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
774 SafeReturn();
775 }
776
777 // Backtrack stack overflow code.
778 if (stack_overflow_label_.is_linked()) {
779 SafeCallTarget(&stack_overflow_label_);
780 // Reached if the backtrack-stack limit has been hit.
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000781 Label grow_failed;
782
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000783 // Call GrowStack(backtrack_stackpointer(), &stack_base)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000784 static const int num_arguments = 3;
ager@chromium.org357bf652010-04-12 11:30:10 +0000785 __ PrepareCallCFunction(num_arguments, r0);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000786 __ mov(r0, backtrack_stackpointer());
787 __ add(r1, frame_pointer(), Operand(kStackHighEnd));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000788 __ mov(r2, Operand(ExternalReference::isolate_address()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000789 ExternalReference grow_stack =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000790 ExternalReference::re_grow_stack(masm_->isolate());
ager@chromium.org357bf652010-04-12 11:30:10 +0000791 __ CallCFunction(grow_stack, num_arguments);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000792 // If return NULL, we have failed to grow the stack, and
793 // must exit with a stack-overflow exception.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000794 __ cmp(r0, Operand(0, RelocInfo::NONE));
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000795 __ b(eq, &exit_with_exception);
796 // Otherwise use return value as new stack pointer.
797 __ mov(backtrack_stackpointer(), r0);
798 // Restore saved registers and continue.
799 SafeReturn();
800 }
801
802 if (exit_with_exception.is_linked()) {
803 // If any of the code above needed to exit with an exception.
804 __ bind(&exit_with_exception);
805 // Exit with Result EXCEPTION(-1) to signal thrown exception.
806 __ mov(r0, Operand(EXCEPTION));
807 __ jmp(&exit_label_);
808 }
809
810 CodeDesc code_desc;
811 masm_->GetCode(&code_desc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000812 Handle<Code> code = FACTORY->NewCode(code_desc,
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000813 Code::ComputeFlags(Code::REGEXP),
814 masm_->CodeObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000815 PROFILE(Isolate::Current(), RegExpCodeCreateEvent(*code, *source));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000816 return Handle<HeapObject>::cast(code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000817}
818
819
820void RegExpMacroAssemblerARM::GoTo(Label* to) {
821 BranchOrBacktrack(al, to);
822}
823
824
825void RegExpMacroAssemblerARM::IfRegisterGE(int reg,
826 int comparand,
827 Label* if_ge) {
828 __ ldr(r0, register_location(reg));
829 __ cmp(r0, Operand(comparand));
830 BranchOrBacktrack(ge, if_ge);
831}
832
833
834void RegExpMacroAssemblerARM::IfRegisterLT(int reg,
835 int comparand,
836 Label* if_lt) {
837 __ ldr(r0, register_location(reg));
838 __ cmp(r0, Operand(comparand));
839 BranchOrBacktrack(lt, if_lt);
840}
841
842
843void RegExpMacroAssemblerARM::IfRegisterEqPos(int reg,
844 Label* if_eq) {
845 __ ldr(r0, register_location(reg));
846 __ cmp(r0, Operand(current_input_offset()));
847 BranchOrBacktrack(eq, if_eq);
848}
849
850
851RegExpMacroAssembler::IrregexpImplementation
852 RegExpMacroAssemblerARM::Implementation() {
853 return kARMImplementation;
854}
855
856
857void RegExpMacroAssemblerARM::LoadCurrentCharacter(int cp_offset,
858 Label* on_end_of_input,
859 bool check_bounds,
860 int characters) {
861 ASSERT(cp_offset >= -1); // ^ and \b can look behind one character.
862 ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works)
863 if (check_bounds) {
864 CheckPosition(cp_offset + characters - 1, on_end_of_input);
865 }
866 LoadCurrentCharacterUnchecked(cp_offset, characters);
867}
868
869
870void RegExpMacroAssemblerARM::PopCurrentPosition() {
871 Pop(current_input_offset());
872}
873
874
875void RegExpMacroAssemblerARM::PopRegister(int register_index) {
876 Pop(r0);
877 __ str(r0, register_location(register_index));
878}
879
880
881static bool is_valid_memory_offset(int value) {
882 if (value < 0) value = -value;
883 return value < (1<<12);
884}
885
886
887void RegExpMacroAssemblerARM::PushBacktrack(Label* label) {
888 if (label->is_bound()) {
889 int target = label->pos();
890 __ mov(r0, Operand(target + Code::kHeaderSize - kHeapObjectTag));
891 } else {
892 int constant_offset = GetBacktrackConstantPoolEntry();
893 masm_->label_at_put(label, constant_offset);
894 // Reading pc-relative is based on the address 8 bytes ahead of
895 // the current opcode.
896 unsigned int offset_of_pc_register_read =
897 masm_->pc_offset() + Assembler::kPcLoadDelta;
898 int pc_offset_of_constant =
899 constant_offset - offset_of_pc_register_read;
900 ASSERT(pc_offset_of_constant < 0);
901 if (is_valid_memory_offset(pc_offset_of_constant)) {
902 masm_->BlockConstPoolBefore(masm_->pc_offset() + Assembler::kInstrSize);
903 __ ldr(r0, MemOperand(pc, pc_offset_of_constant));
904 } else {
905 // Not a 12-bit offset, so it needs to be loaded from the constant
906 // pool.
907 masm_->BlockConstPoolBefore(
908 masm_->pc_offset() + 2 * Assembler::kInstrSize);
909 __ mov(r0, Operand(pc_offset_of_constant + Assembler::kInstrSize));
910 __ ldr(r0, MemOperand(pc, r0));
911 }
912 }
913 Push(r0);
914 CheckStackLimit();
915}
916
917
918void RegExpMacroAssemblerARM::PushCurrentPosition() {
919 Push(current_input_offset());
920}
921
922
923void RegExpMacroAssemblerARM::PushRegister(int register_index,
924 StackCheckFlag check_stack_limit) {
925 __ ldr(r0, register_location(register_index));
926 Push(r0);
927 if (check_stack_limit) CheckStackLimit();
928}
929
930
931void RegExpMacroAssemblerARM::ReadCurrentPositionFromRegister(int reg) {
932 __ ldr(current_input_offset(), register_location(reg));
933}
934
935
936void RegExpMacroAssemblerARM::ReadStackPointerFromRegister(int reg) {
937 __ ldr(backtrack_stackpointer(), register_location(reg));
938 __ ldr(r0, MemOperand(frame_pointer(), kStackHighEnd));
939 __ add(backtrack_stackpointer(), backtrack_stackpointer(), Operand(r0));
940}
941
942
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000943void RegExpMacroAssemblerARM::SetCurrentPositionFromEnd(int by) {
944 Label after_position;
945 __ cmp(current_input_offset(), Operand(-by * char_size()));
946 __ b(ge, &after_position);
947 __ mov(current_input_offset(), Operand(-by * char_size()));
948 // On RegExp code entry (where this operation is used), the character before
949 // the current position is expected to be already loaded.
950 // We have advanced the position, so it's safe to read backwards.
951 LoadCurrentCharacterUnchecked(-1, 1);
952 __ bind(&after_position);
953}
954
955
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000956void RegExpMacroAssemblerARM::SetRegister(int register_index, int to) {
957 ASSERT(register_index >= num_saved_registers_); // Reserved for positions!
958 __ mov(r0, Operand(to));
959 __ str(r0, register_location(register_index));
960}
961
962
963void RegExpMacroAssemblerARM::Succeed() {
964 __ jmp(&success_label_);
965}
966
967
968void RegExpMacroAssemblerARM::WriteCurrentPositionToRegister(int reg,
969 int cp_offset) {
970 if (cp_offset == 0) {
971 __ str(current_input_offset(), register_location(reg));
972 } else {
973 __ add(r0, current_input_offset(), Operand(cp_offset * char_size()));
974 __ str(r0, register_location(reg));
975 }
976}
977
978
979void RegExpMacroAssemblerARM::ClearRegisters(int reg_from, int reg_to) {
980 ASSERT(reg_from <= reg_to);
981 __ ldr(r0, MemOperand(frame_pointer(), kInputStartMinusOne));
982 for (int reg = reg_from; reg <= reg_to; reg++) {
983 __ str(r0, register_location(reg));
984 }
985}
986
987
988void RegExpMacroAssemblerARM::WriteStackPointerToRegister(int reg) {
989 __ ldr(r1, MemOperand(frame_pointer(), kStackHighEnd));
990 __ sub(r0, backtrack_stackpointer(), r1);
991 __ str(r0, register_location(reg));
992}
993
994
995// Private methods:
996
997void RegExpMacroAssemblerARM::CallCheckStackGuardState(Register scratch) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000998 static const int num_arguments = 3;
ager@chromium.org357bf652010-04-12 11:30:10 +0000999 __ PrepareCallCFunction(num_arguments, scratch);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001000 // RegExp code frame pointer.
1001 __ mov(r2, frame_pointer());
1002 // Code* of self.
1003 __ mov(r1, Operand(masm_->CodeObject()));
1004 // r0 becomes return address pointer.
1005 ExternalReference stack_guard_check =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001006 ExternalReference::re_check_stack_guard_state(masm_->isolate());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001007 CallCFunctionUsingStub(stack_guard_check, num_arguments);
1008}
1009
1010
1011// Helper function for reading a value out of a stack frame.
1012template <typename T>
1013static T& frame_entry(Address re_frame, int frame_offset) {
1014 return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset));
1015}
1016
1017
1018int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address,
1019 Code* re_code,
1020 Address re_frame) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001021 Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
1022 ASSERT(isolate == Isolate::Current());
1023 if (isolate->stack_guard()->IsStackOverflow()) {
1024 isolate->StackOverflow();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001025 return EXCEPTION;
1026 }
1027
1028 // If not real stack overflow the stack guard was used to interrupt
1029 // execution for another purpose.
1030
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001031 // If this is a direct call from JavaScript retry the RegExp forcing the call
1032 // through the runtime system. Currently the direct call cannot handle a GC.
1033 if (frame_entry<int>(re_frame, kDirectCall) == 1) {
1034 return RETRY;
1035 }
1036
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001037 // Prepare for possible GC.
1038 HandleScope handles;
1039 Handle<Code> code_handle(re_code);
1040
1041 Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
1042 // Current string.
1043 bool is_ascii = subject->IsAsciiRepresentation();
1044
1045 ASSERT(re_code->instruction_start() <= *return_address);
1046 ASSERT(*return_address <=
1047 re_code->instruction_start() + re_code->instruction_size());
1048
lrn@chromium.org303ada72010-10-27 09:33:13 +00001049 MaybeObject* result = Execution::HandleStackGuardInterrupt();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001050
1051 if (*code_handle != re_code) { // Return address no longer valid
1052 int delta = *code_handle - re_code;
1053 // Overwrite the return address on the stack.
1054 *return_address += delta;
1055 }
1056
1057 if (result->IsException()) {
1058 return EXCEPTION;
1059 }
1060
1061 // String might have changed.
1062 if (subject->IsAsciiRepresentation() != is_ascii) {
1063 // If we changed between an ASCII and an UC16 string, the specialized
1064 // code cannot be used, and we need to restart regexp matching from
1065 // scratch (including, potentially, compiling a new version of the code).
1066 return RETRY;
1067 }
1068
1069 // Otherwise, the content of the string might have moved. It must still
1070 // be a sequential or external string with the same content.
1071 // Update the start and end pointers in the stack frame to the current
1072 // location (whether it has actually moved or not).
1073 ASSERT(StringShape(*subject).IsSequential() ||
1074 StringShape(*subject).IsExternal());
1075
1076 // The original start address of the characters to match.
1077 const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
1078
1079 // Find the current start address of the same character at the current string
1080 // position.
1081 int start_index = frame_entry<int>(re_frame, kStartIndex);
1082 const byte* new_address = StringCharacterPosition(*subject, start_index);
1083
1084 if (start_address != new_address) {
1085 // If there is a difference, update the object pointer and start and end
1086 // addresses in the RegExp stack frame to match the new value.
1087 const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
1088 int byte_length = end_address - start_address;
1089 frame_entry<const String*>(re_frame, kInputString) = *subject;
1090 frame_entry<const byte*>(re_frame, kInputStart) = new_address;
1091 frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
1092 }
1093
1094 return 0;
1095}
1096
1097
1098MemOperand RegExpMacroAssemblerARM::register_location(int register_index) {
1099 ASSERT(register_index < (1<<30));
1100 if (num_registers_ <= register_index) {
1101 num_registers_ = register_index + 1;
1102 }
1103 return MemOperand(frame_pointer(),
1104 kRegisterZero - register_index * kPointerSize);
1105}
1106
1107
1108void RegExpMacroAssemblerARM::CheckPosition(int cp_offset,
1109 Label* on_outside_input) {
1110 __ cmp(current_input_offset(), Operand(-cp_offset * char_size()));
1111 BranchOrBacktrack(ge, on_outside_input);
1112}
1113
1114
1115void RegExpMacroAssemblerARM::BranchOrBacktrack(Condition condition,
1116 Label* to) {
1117 if (condition == al) { // Unconditional.
1118 if (to == NULL) {
1119 Backtrack();
1120 return;
1121 }
1122 __ jmp(to);
1123 return;
1124 }
1125 if (to == NULL) {
1126 __ b(condition, &backtrack_label_);
1127 return;
1128 }
1129 __ b(condition, to);
1130}
1131
1132
1133void RegExpMacroAssemblerARM::SafeCall(Label* to, Condition cond) {
1134 __ bl(to, cond);
1135}
1136
1137
1138void RegExpMacroAssemblerARM::SafeReturn() {
1139 __ pop(lr);
1140 __ add(pc, lr, Operand(masm_->CodeObject()));
1141}
1142
1143
1144void RegExpMacroAssemblerARM::SafeCallTarget(Label* name) {
1145 __ bind(name);
1146 __ sub(lr, lr, Operand(masm_->CodeObject()));
1147 __ push(lr);
1148}
1149
1150
1151void RegExpMacroAssemblerARM::Push(Register source) {
1152 ASSERT(!source.is(backtrack_stackpointer()));
1153 __ str(source,
1154 MemOperand(backtrack_stackpointer(), kPointerSize, NegPreIndex));
1155}
1156
1157
1158void RegExpMacroAssemblerARM::Pop(Register target) {
1159 ASSERT(!target.is(backtrack_stackpointer()));
1160 __ ldr(target,
1161 MemOperand(backtrack_stackpointer(), kPointerSize, PostIndex));
1162}
1163
1164
1165void RegExpMacroAssemblerARM::CheckPreemption() {
1166 // Check for preemption.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001167 ExternalReference stack_limit =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001168 ExternalReference::address_of_stack_limit(masm_->isolate());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001169 __ mov(r0, Operand(stack_limit));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001170 __ ldr(r0, MemOperand(r0));
1171 __ cmp(sp, r0);
1172 SafeCall(&check_preempt_label_, ls);
1173}
1174
1175
1176void RegExpMacroAssemblerARM::CheckStackLimit() {
ager@chromium.org3811b432009-10-28 14:53:37 +00001177 ExternalReference stack_limit =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001178 ExternalReference::address_of_regexp_stack_limit(masm_->isolate());
ager@chromium.org3811b432009-10-28 14:53:37 +00001179 __ mov(r0, Operand(stack_limit));
1180 __ ldr(r0, MemOperand(r0));
1181 __ cmp(backtrack_stackpointer(), Operand(r0));
1182 SafeCall(&stack_overflow_label_, ls);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001183}
1184
1185
1186void RegExpMacroAssemblerARM::EmitBacktrackConstantPool() {
1187 __ CheckConstPool(false, false);
1188 __ BlockConstPoolBefore(
1189 masm_->pc_offset() + kBacktrackConstantPoolSize * Assembler::kInstrSize);
1190 backtrack_constant_pool_offset_ = masm_->pc_offset();
1191 for (int i = 0; i < kBacktrackConstantPoolSize; i++) {
1192 __ emit(0);
1193 }
1194
1195 backtrack_constant_pool_capacity_ = kBacktrackConstantPoolSize;
1196}
1197
1198
1199int RegExpMacroAssemblerARM::GetBacktrackConstantPoolEntry() {
1200 while (backtrack_constant_pool_capacity_ > 0) {
1201 int offset = backtrack_constant_pool_offset_;
1202 backtrack_constant_pool_offset_ += kPointerSize;
1203 backtrack_constant_pool_capacity_--;
1204 if (masm_->pc_offset() - offset < 2 * KB) {
1205 return offset;
1206 }
1207 }
1208 Label new_pool_skip;
1209 __ jmp(&new_pool_skip);
1210 EmitBacktrackConstantPool();
1211 __ bind(&new_pool_skip);
1212 int offset = backtrack_constant_pool_offset_;
1213 backtrack_constant_pool_offset_ += kPointerSize;
1214 backtrack_constant_pool_capacity_--;
1215 return offset;
1216}
1217
1218
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001219void RegExpMacroAssemblerARM::CallCFunctionUsingStub(
1220 ExternalReference function,
1221 int num_arguments) {
1222 // Must pass all arguments in registers. The stub pushes on the stack.
1223 ASSERT(num_arguments <= 4);
ager@chromium.org357bf652010-04-12 11:30:10 +00001224 __ mov(code_pointer(), Operand(function));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001225 RegExpCEntryStub stub;
1226 __ CallStub(&stub);
1227 if (OS::ActivationFrameAlignment() != 0) {
1228 __ ldr(sp, MemOperand(sp, 0));
1229 }
1230 __ mov(code_pointer(), Operand(masm_->CodeObject()));
1231}
1232
1233
1234void RegExpMacroAssemblerARM::LoadCurrentCharacterUnchecked(int cp_offset,
1235 int characters) {
1236 Register offset = current_input_offset();
1237 if (cp_offset != 0) {
1238 __ add(r0, current_input_offset(), Operand(cp_offset * char_size()));
1239 offset = r0;
1240 }
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001241 // The ldr, str, ldrh, strh instructions can do unaligned accesses, if the CPU
1242 // and the operating system running on the target allow it.
1243 // If unaligned load/stores are not supported then this function must only
1244 // be used to load a single character at a time.
1245#if !V8_TARGET_CAN_READ_UNALIGNED
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001246 ASSERT(characters == 1);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001247#endif
1248
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001249 if (mode_ == ASCII) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001250 if (characters == 4) {
1251 __ ldr(current_character(), MemOperand(end_of_input_address(), offset));
1252 } else if (characters == 2) {
1253 __ ldrh(current_character(), MemOperand(end_of_input_address(), offset));
1254 } else {
1255 ASSERT(characters == 1);
1256 __ ldrb(current_character(), MemOperand(end_of_input_address(), offset));
1257 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001258 } else {
1259 ASSERT(mode_ == UC16);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001260 if (characters == 2) {
1261 __ ldr(current_character(), MemOperand(end_of_input_address(), offset));
1262 } else {
1263 ASSERT(characters == 1);
1264 __ ldrh(current_character(), MemOperand(end_of_input_address(), offset));
1265 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001266 }
1267}
1268
1269
1270void RegExpCEntryStub::Generate(MacroAssembler* masm_) {
1271 int stack_alignment = OS::ActivationFrameAlignment();
1272 if (stack_alignment < kPointerSize) stack_alignment = kPointerSize;
1273 // Stack is already aligned for call, so decrement by alignment
1274 // to make room for storing the link register.
1275 __ str(lr, MemOperand(sp, stack_alignment, NegPreIndex));
1276 __ mov(r0, sp);
1277 __ Call(r5);
1278 __ ldr(pc, MemOperand(sp, stack_alignment, PostIndex));
1279}
1280
1281#undef __
1282
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00001283#endif // V8_INTERPRETED_REGEXP
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001284
1285}} // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001286
1287#endif // V8_TARGET_ARCH_ARM