blob: 7289296d56815e48c39107ddabd142b6ef316dcc [file] [log] [blame]
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001// Copyright 2012 the V8 project authors. All rights reserved.
lrn@chromium.org7516f052011-03-30 08:52:27 +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
28#include "v8.h"
29
30#if defined(V8_TARGET_ARCH_MIPS)
31
32#include "unicode.h"
33#include "log.h"
34#include "code-stubs.h"
35#include "regexp-stack.h"
36#include "macro-assembler.h"
37#include "regexp-macro-assembler.h"
38#include "mips/regexp-macro-assembler-mips.h"
39
40namespace v8 {
41namespace internal {
42
43#ifndef V8_INTERPRETED_REGEXP
44/*
45 * This assembler uses the following register assignment convention
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +000046 * - t7 : Temporarily stores the index of capture start after a matching pass
47 * for a global regexp.
lrn@chromium.org7516f052011-03-30 08:52:27 +000048 * - t1 : Pointer to current code object (Code*) including heap object tag.
49 * - t2 : Current position in input, as negative offset from end of string.
50 * Please notice that this is the byte offset, not the character offset!
51 * - t3 : Currently loaded character. Must be loaded using
52 * LoadCurrentCharacter before using any of the dispatch methods.
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +000053 * - t4 : Points to tip of backtrack stack
lrn@chromium.org7516f052011-03-30 08:52:27 +000054 * - t5 : Unused.
55 * - t6 : End of input (points to byte after last character in input).
56 * - fp : Frame pointer. Used to access arguments, local variables and
57 * RegExp registers.
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +000058 * - sp : Points to tip of C stack.
lrn@chromium.org7516f052011-03-30 08:52:27 +000059 *
60 * The remaining registers are free for computations.
lrn@chromium.org7516f052011-03-30 08:52:27 +000061 * Each call to a public method should retain this convention.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000062 *
lrn@chromium.org7516f052011-03-30 08:52:27 +000063 * The stack will have the following structure:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000064 *
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +000065 * - fp[64] Isolate* isolate (address of the current isolate)
66 * - fp[60] direct_call (if 1, direct call from JavaScript code,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000067 * if 0, call through the runtime system).
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +000068 * - fp[56] stack_area_base (High end of the memory area to use as
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000069 * backtracking stack).
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +000070 * - fp[52] capture array size (may fit multiple sets of matches)
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000071 * - fp[48] int* capture_array (int[num_saved_registers_], for output).
72 * - fp[44] secondary link/return address used by native call.
73 * --- sp when called ---
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +000074 * - fp[40] return address (lr).
75 * - fp[36] old frame pointer (r11).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000076 * - fp[0..32] backup of registers s0..s7.
77 * --- frame pointer ----
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +000078 * - fp[-4] end of input (address of end of string).
79 * - fp[-8] start of input (address of first character in string).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000080 * - fp[-12] start index (character index of start).
81 * - fp[-16] void* input_string (location of a handle containing the string).
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +000082 * - fp[-20] success counter (only for global regexps to count matches).
83 * - fp[-24] Offset of location before start of input (effectively character
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000084 * position -1). Used to initialize capture registers to a
85 * non-position.
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +000086 * - fp[-28] At start (if 1, we are starting at the start of the
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000087 * string, otherwise 0)
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +000088 * - fp[-32] register 0 (Only positions must be stored in the first
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000089 * - register 1 num_saved_registers_ registers)
90 * - ...
91 * - register num_registers-1
92 * --- sp ---
lrn@chromium.org7516f052011-03-30 08:52:27 +000093 *
94 * The first num_saved_registers_ registers are initialized to point to
95 * "character -1" in the string (i.e., char_size() bytes before the first
96 * character of the string). The remaining registers start out as garbage.
97 *
98 * The data up to the return address must be placed there by the calling
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000099 * code and the remaining arguments are passed in registers, e.g. by calling the
100 * code entry as cast to a function with the signature:
lrn@chromium.org7516f052011-03-30 08:52:27 +0000101 * int (*match)(String* input_string,
102 * int start_index,
103 * Address start,
104 * Address end,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000105 * Address secondary_return_address, // Only used by native call.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000106 * int* capture_output_array,
lrn@chromium.org7516f052011-03-30 08:52:27 +0000107 * byte* stack_area_base,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000108 * bool direct_call = false)
lrn@chromium.org7516f052011-03-30 08:52:27 +0000109 * The call is performed by NativeRegExpMacroAssembler::Execute()
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000110 * (in regexp-macro-assembler.cc) via the CALL_GENERATED_REGEXP_CODE macro
111 * in mips/simulator-mips.h.
112 * When calling as a non-direct call (i.e., from C++ code), the return address
113 * area is overwritten with the ra register by the RegExp code. When doing a
114 * direct call from generated code, the return address is placed there by
115 * the calling code, as in a normal exit frame.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000116 */
117
118#define __ ACCESS_MASM(masm_)
119
120RegExpMacroAssemblerMIPS::RegExpMacroAssemblerMIPS(
121 Mode mode,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000122 int registers_to_save,
123 Zone* zone)
124 : NativeRegExpMacroAssembler(zone),
125 masm_(new MacroAssembler(Isolate::Current(), NULL, kRegExpCodeSize)),
lrn@chromium.org7516f052011-03-30 08:52:27 +0000126 mode_(mode),
127 num_registers_(registers_to_save),
128 num_saved_registers_(registers_to_save),
129 entry_label_(),
130 start_label_(),
131 success_label_(),
132 backtrack_label_(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000133 exit_label_(),
134 internal_failure_label_() {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000135 ASSERT_EQ(0, registers_to_save % 2);
136 __ jmp(&entry_label_); // We'll write the entry code later.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000137 // If the code gets too big or corrupted, an internal exception will be
138 // raised, and we will exit right away.
139 __ bind(&internal_failure_label_);
140 __ li(v0, Operand(FAILURE));
141 __ Ret();
lrn@chromium.org7516f052011-03-30 08:52:27 +0000142 __ bind(&start_label_); // And then continue from here.
143}
144
145
146RegExpMacroAssemblerMIPS::~RegExpMacroAssemblerMIPS() {
147 delete masm_;
148 // Unuse labels in case we throw away the assembler without calling GetCode.
149 entry_label_.Unuse();
150 start_label_.Unuse();
151 success_label_.Unuse();
152 backtrack_label_.Unuse();
153 exit_label_.Unuse();
154 check_preempt_label_.Unuse();
155 stack_overflow_label_.Unuse();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000156 internal_failure_label_.Unuse();
lrn@chromium.org7516f052011-03-30 08:52:27 +0000157}
158
159
160int RegExpMacroAssemblerMIPS::stack_limit_slack() {
161 return RegExpStack::kStackLimitSlack;
162}
163
164
165void RegExpMacroAssemblerMIPS::AdvanceCurrentPosition(int by) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000166 if (by != 0) {
167 __ Addu(current_input_offset(),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000168 current_input_offset(), Operand(by * char_size()));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000169 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000170}
171
172
173void RegExpMacroAssemblerMIPS::AdvanceRegister(int reg, int by) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000174 ASSERT(reg >= 0);
175 ASSERT(reg < num_registers_);
176 if (by != 0) {
177 __ lw(a0, register_location(reg));
178 __ Addu(a0, a0, Operand(by));
179 __ sw(a0, register_location(reg));
180 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000181}
182
183
184void RegExpMacroAssemblerMIPS::Backtrack() {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000185 CheckPreemption();
186 // Pop Code* offset from backtrack stack, add Code* and jump to location.
187 Pop(a0);
188 __ Addu(a0, a0, code_pointer());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000189 __ Jump(a0);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000190}
191
192
193void RegExpMacroAssemblerMIPS::Bind(Label* label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000194 __ bind(label);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000195}
196
197
198void RegExpMacroAssemblerMIPS::CheckCharacter(uint32_t c, Label* on_equal) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000199 BranchOrBacktrack(on_equal, eq, current_character(), Operand(c));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000200}
201
202
203void RegExpMacroAssemblerMIPS::CheckCharacterGT(uc16 limit, Label* on_greater) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000204 BranchOrBacktrack(on_greater, gt, current_character(), Operand(limit));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000205}
206
207
208void RegExpMacroAssemblerMIPS::CheckAtStart(Label* on_at_start) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000209 Label not_at_start;
210 // Did we start the match at the start of the string at all?
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +0000211 __ lw(a0, MemOperand(frame_pointer(), kStartIndex));
212 BranchOrBacktrack(&not_at_start, ne, a0, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000213
214 // If we did, are we still at the start of the input?
215 __ lw(a1, MemOperand(frame_pointer(), kInputStart));
216 __ Addu(a0, end_of_input_address(), Operand(current_input_offset()));
217 BranchOrBacktrack(on_at_start, eq, a0, Operand(a1));
218 __ bind(&not_at_start);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000219}
220
221
222void RegExpMacroAssemblerMIPS::CheckNotAtStart(Label* on_not_at_start) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000223 // Did we start the match at the start of the string at all?
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +0000224 __ lw(a0, MemOperand(frame_pointer(), kStartIndex));
225 BranchOrBacktrack(on_not_at_start, ne, a0, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000226 // If we did, are we still at the start of the input?
227 __ lw(a1, MemOperand(frame_pointer(), kInputStart));
228 __ Addu(a0, end_of_input_address(), Operand(current_input_offset()));
229 BranchOrBacktrack(on_not_at_start, ne, a0, Operand(a1));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000230}
231
232
233void RegExpMacroAssemblerMIPS::CheckCharacterLT(uc16 limit, Label* on_less) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000234 BranchOrBacktrack(on_less, lt, current_character(), Operand(limit));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000235}
236
237
238void RegExpMacroAssemblerMIPS::CheckCharacters(Vector<const uc16> str,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000239 int cp_offset,
240 Label* on_failure,
241 bool check_end_of_string) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000242 if (on_failure == NULL) {
243 // Instead of inlining a backtrack for each test, (re)use the global
244 // backtrack target.
245 on_failure = &backtrack_label_;
246 }
247
248 if (check_end_of_string) {
249 // Is last character of required match inside string.
250 CheckPosition(cp_offset + str.length() - 1, on_failure);
251 }
252
253 __ Addu(a0, end_of_input_address(), Operand(current_input_offset()));
254 if (cp_offset != 0) {
255 int byte_offset = cp_offset * char_size();
256 __ Addu(a0, a0, Operand(byte_offset));
257 }
258
259 // a0 : Address of characters to match against str.
260 int stored_high_byte = 0;
261 for (int i = 0; i < str.length(); i++) {
262 if (mode_ == ASCII) {
263 __ lbu(a1, MemOperand(a0, 0));
264 __ addiu(a0, a0, char_size());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000265 ASSERT(str[i] <= String::kMaxOneByteCharCode);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000266 BranchOrBacktrack(on_failure, ne, a1, Operand(str[i]));
267 } else {
268 __ lhu(a1, MemOperand(a0, 0));
269 __ addiu(a0, a0, char_size());
270 uc16 match_char = str[i];
271 int match_high_byte = (match_char >> 8);
272 if (match_high_byte == 0) {
273 BranchOrBacktrack(on_failure, ne, a1, Operand(str[i]));
274 } else {
275 if (match_high_byte != stored_high_byte) {
276 __ li(a2, Operand(match_high_byte));
277 stored_high_byte = match_high_byte;
278 }
279 __ Addu(a3, a2, Operand(match_char & 0xff));
280 BranchOrBacktrack(on_failure, ne, a1, Operand(a3));
281 }
282 }
283 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000284}
285
286
287void RegExpMacroAssemblerMIPS::CheckGreedyLoop(Label* on_equal) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000288 Label backtrack_non_equal;
289 __ lw(a0, MemOperand(backtrack_stackpointer(), 0));
290 __ Branch(&backtrack_non_equal, ne, current_input_offset(), Operand(a0));
291 __ Addu(backtrack_stackpointer(),
292 backtrack_stackpointer(),
293 Operand(kPointerSize));
294 __ bind(&backtrack_non_equal);
295 BranchOrBacktrack(on_equal, eq, current_input_offset(), Operand(a0));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000296}
297
298
299void RegExpMacroAssemblerMIPS::CheckNotBackReferenceIgnoreCase(
300 int start_reg,
301 Label* on_no_match) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000302 Label fallthrough;
303 __ lw(a0, register_location(start_reg)); // Index of start of capture.
304 __ lw(a1, register_location(start_reg + 1)); // Index of end of capture.
305 __ Subu(a1, a1, a0); // Length of capture.
306
307 // If length is zero, either the capture is empty or it is not participating.
308 // In either case succeed immediately.
309 __ Branch(&fallthrough, eq, a1, Operand(zero_reg));
310
311 __ Addu(t5, a1, current_input_offset());
312 // Check that there are enough characters left in the input.
313 BranchOrBacktrack(on_no_match, gt, t5, Operand(zero_reg));
314
315 if (mode_ == ASCII) {
316 Label success;
317 Label fail;
318 Label loop_check;
319
320 // a0 - offset of start of capture.
321 // a1 - length of capture.
322 __ Addu(a0, a0, Operand(end_of_input_address()));
323 __ Addu(a2, end_of_input_address(), Operand(current_input_offset()));
324 __ Addu(a1, a0, Operand(a1));
325
326 // a0 - Address of start of capture.
327 // a1 - Address of end of capture.
328 // a2 - Address of current input position.
329
330 Label loop;
331 __ bind(&loop);
332 __ lbu(a3, MemOperand(a0, 0));
333 __ addiu(a0, a0, char_size());
334 __ lbu(t0, MemOperand(a2, 0));
335 __ addiu(a2, a2, char_size());
336
337 __ Branch(&loop_check, eq, t0, Operand(a3));
338
339 // Mismatch, try case-insensitive match (converting letters to lower-case).
340 __ Or(a3, a3, Operand(0x20)); // Convert capture character to lower-case.
341 __ Or(t0, t0, Operand(0x20)); // Also convert input character.
342 __ Branch(&fail, ne, t0, Operand(a3));
343 __ Subu(a3, a3, Operand('a'));
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000344 __ Branch(&loop_check, ls, a3, Operand('z' - 'a'));
345 // Latin-1: Check for values in range [224,254] but not 247.
346 __ Subu(a3, a3, Operand(224 - 'a'));
347 // Weren't Latin-1 letters.
348 __ Branch(&fail, hi, a3, Operand(254 - 224));
349 // Check for 247.
350 __ Branch(&fail, eq, a3, Operand(247 - 224));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000351
352 __ bind(&loop_check);
353 __ Branch(&loop, lt, a0, Operand(a1));
354 __ jmp(&success);
355
356 __ bind(&fail);
357 GoTo(on_no_match);
358
359 __ bind(&success);
360 // Compute new value of character position after the matched part.
361 __ Subu(current_input_offset(), a2, end_of_input_address());
362 } else {
363 ASSERT(mode_ == UC16);
364 // Put regexp engine registers on stack.
365 RegList regexp_registers_to_retain = current_input_offset().bit() |
366 current_character().bit() | backtrack_stackpointer().bit();
367 __ MultiPush(regexp_registers_to_retain);
368
369 int argument_count = 4;
370 __ PrepareCallCFunction(argument_count, a2);
371
372 // a0 - offset of start of capture.
373 // a1 - length of capture.
374
375 // Put arguments into arguments registers.
376 // Parameters are
377 // a0: Address byte_offset1 - Address captured substring's start.
378 // a1: Address byte_offset2 - Address of current character position.
379 // a2: size_t byte_length - length of capture in bytes(!).
380 // a3: Isolate* isolate.
381
382 // Address of start of capture.
383 __ Addu(a0, a0, Operand(end_of_input_address()));
384 // Length of capture.
385 __ mov(a2, a1);
386 // Save length in callee-save register for use on return.
387 __ mov(s3, a1);
388 // Address of current input position.
389 __ Addu(a1, current_input_offset(), Operand(end_of_input_address()));
390 // Isolate.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000391 __ li(a3, Operand(ExternalReference::isolate_address(masm_->isolate())));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000392
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000393 {
394 AllowExternalCallThatCantCauseGC scope(masm_);
395 ExternalReference function =
396 ExternalReference::re_case_insensitive_compare_uc16(masm_->isolate());
397 __ CallCFunction(function, argument_count);
398 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000399
400 // Restore regexp engine registers.
401 __ MultiPop(regexp_registers_to_retain);
danno@chromium.org88aa0582012-03-23 15:11:57 +0000402 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000403 __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
404
405 // Check if function returned non-zero for success or zero for failure.
406 BranchOrBacktrack(on_no_match, eq, v0, Operand(zero_reg));
407 // On success, increment position by length of capture.
408 __ Addu(current_input_offset(), current_input_offset(), Operand(s3));
409 }
410
411 __ bind(&fallthrough);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000412}
413
414
415void RegExpMacroAssemblerMIPS::CheckNotBackReference(
416 int start_reg,
417 Label* on_no_match) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000418 Label fallthrough;
419 Label success;
420
421 // Find length of back-referenced capture.
422 __ lw(a0, register_location(start_reg));
423 __ lw(a1, register_location(start_reg + 1));
424 __ Subu(a1, a1, a0); // Length to check.
425 // Succeed on empty capture (including no capture).
426 __ Branch(&fallthrough, eq, a1, Operand(zero_reg));
427
428 __ Addu(t5, a1, current_input_offset());
429 // Check that there are enough characters left in the input.
430 BranchOrBacktrack(on_no_match, gt, t5, Operand(zero_reg));
431
432 // Compute pointers to match string and capture string.
433 __ Addu(a0, a0, Operand(end_of_input_address()));
434 __ Addu(a2, end_of_input_address(), Operand(current_input_offset()));
435 __ Addu(a1, a1, Operand(a0));
436
437 Label loop;
438 __ bind(&loop);
439 if (mode_ == ASCII) {
440 __ lbu(a3, MemOperand(a0, 0));
441 __ addiu(a0, a0, char_size());
442 __ lbu(t0, MemOperand(a2, 0));
443 __ addiu(a2, a2, char_size());
444 } else {
445 ASSERT(mode_ == UC16);
446 __ lhu(a3, MemOperand(a0, 0));
447 __ addiu(a0, a0, char_size());
448 __ lhu(t0, MemOperand(a2, 0));
449 __ addiu(a2, a2, char_size());
450 }
451 BranchOrBacktrack(on_no_match, ne, a3, Operand(t0));
452 __ Branch(&loop, lt, a0, Operand(a1));
453
454 // Move current character position to position after match.
455 __ Subu(current_input_offset(), a2, end_of_input_address());
456 __ bind(&fallthrough);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000457}
458
459
lrn@chromium.org7516f052011-03-30 08:52:27 +0000460void RegExpMacroAssemblerMIPS::CheckNotCharacter(uint32_t c,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000461 Label* on_not_equal) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000462 BranchOrBacktrack(on_not_equal, ne, current_character(), Operand(c));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000463}
464
465
466void RegExpMacroAssemblerMIPS::CheckCharacterAfterAnd(uint32_t c,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000467 uint32_t mask,
468 Label* on_equal) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000469 __ And(a0, current_character(), Operand(mask));
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000470 Operand rhs = (c == 0) ? Operand(zero_reg) : Operand(c);
471 BranchOrBacktrack(on_equal, eq, a0, rhs);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000472}
473
474
475void RegExpMacroAssemblerMIPS::CheckNotCharacterAfterAnd(uint32_t c,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000476 uint32_t mask,
477 Label* on_not_equal) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000478 __ And(a0, current_character(), Operand(mask));
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000479 Operand rhs = (c == 0) ? Operand(zero_reg) : Operand(c);
480 BranchOrBacktrack(on_not_equal, ne, a0, rhs);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000481}
482
483
484void RegExpMacroAssemblerMIPS::CheckNotCharacterAfterMinusAnd(
485 uc16 c,
486 uc16 minus,
487 uc16 mask,
488 Label* on_not_equal) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000489 ASSERT(minus < String::kMaxUtf16CodeUnit);
490 __ Subu(a0, current_character(), Operand(minus));
491 __ And(a0, a0, Operand(mask));
492 BranchOrBacktrack(on_not_equal, ne, a0, Operand(c));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000493}
494
495
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000496void RegExpMacroAssemblerMIPS::CheckCharacterInRange(
497 uc16 from,
498 uc16 to,
499 Label* on_in_range) {
500 __ Subu(a0, current_character(), Operand(from));
501 // Unsigned lower-or-same condition.
502 BranchOrBacktrack(on_in_range, ls, a0, Operand(to - from));
503}
504
505
506void RegExpMacroAssemblerMIPS::CheckCharacterNotInRange(
507 uc16 from,
508 uc16 to,
509 Label* on_not_in_range) {
510 __ Subu(a0, current_character(), Operand(from));
511 // Unsigned higher condition.
512 BranchOrBacktrack(on_not_in_range, hi, a0, Operand(to - from));
513}
514
515
516void RegExpMacroAssemblerMIPS::CheckBitInTable(
517 Handle<ByteArray> table,
518 Label* on_bit_set) {
519 __ li(a0, Operand(table));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000520 if (mode_ != ASCII || kTableMask != String::kMaxOneByteCharCode) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000521 __ And(a1, current_character(), Operand(kTableSize - 1));
522 __ Addu(a0, a0, a1);
523 } else {
524 __ Addu(a0, a0, current_character());
525 }
526
527 __ lbu(a0, FieldMemOperand(a0, ByteArray::kHeaderSize));
528 BranchOrBacktrack(on_bit_set, ne, a0, Operand(zero_reg));
529}
530
531
lrn@chromium.org7516f052011-03-30 08:52:27 +0000532bool RegExpMacroAssemblerMIPS::CheckSpecialCharacterClass(uc16 type,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000533 Label* on_no_match) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000534 // Range checks (c in min..max) are generally implemented by an unsigned
535 // (c - min) <= (max - min) check.
536 switch (type) {
537 case 's':
538 // Match space-characters.
539 if (mode_ == ASCII) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000540 // One byte space characters are '\t'..'\r', ' ' and \u00a0.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000541 Label success;
542 __ Branch(&success, eq, current_character(), Operand(' '));
543 // Check range 0x09..0x0d.
544 __ Subu(a0, current_character(), Operand('\t'));
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000545 __ Branch(&success, ls, a0, Operand('\r' - '\t'));
546 // \u00a0 (NBSP).
547 BranchOrBacktrack(on_no_match, ne, a0, Operand(0x00a0 - '\t'));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000548 __ bind(&success);
549 return true;
550 }
551 return false;
552 case 'S':
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000553 // The emitted code for generic character classes is good enough.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000554 return false;
555 case 'd':
556 // Match ASCII digits ('0'..'9').
557 __ Subu(a0, current_character(), Operand('0'));
558 BranchOrBacktrack(on_no_match, hi, a0, Operand('9' - '0'));
559 return true;
560 case 'D':
561 // Match non ASCII-digits.
562 __ Subu(a0, current_character(), Operand('0'));
563 BranchOrBacktrack(on_no_match, ls, a0, Operand('9' - '0'));
564 return true;
565 case '.': {
566 // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029).
567 __ Xor(a0, current_character(), Operand(0x01));
568 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c.
569 __ Subu(a0, a0, Operand(0x0b));
570 BranchOrBacktrack(on_no_match, ls, a0, Operand(0x0c - 0x0b));
571 if (mode_ == UC16) {
572 // Compare original value to 0x2028 and 0x2029, using the already
573 // computed (current_char ^ 0x01 - 0x0b). I.e., check for
574 // 0x201d (0x2028 - 0x0b) or 0x201e.
575 __ Subu(a0, a0, Operand(0x2028 - 0x0b));
576 BranchOrBacktrack(on_no_match, ls, a0, Operand(1));
577 }
578 return true;
579 }
580 case 'n': {
581 // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029).
582 __ Xor(a0, current_character(), Operand(0x01));
583 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c.
584 __ Subu(a0, a0, Operand(0x0b));
585 if (mode_ == ASCII) {
586 BranchOrBacktrack(on_no_match, hi, a0, Operand(0x0c - 0x0b));
587 } else {
588 Label done;
589 BranchOrBacktrack(&done, ls, a0, Operand(0x0c - 0x0b));
590 // Compare original value to 0x2028 and 0x2029, using the already
591 // computed (current_char ^ 0x01 - 0x0b). I.e., check for
592 // 0x201d (0x2028 - 0x0b) or 0x201e.
593 __ Subu(a0, a0, Operand(0x2028 - 0x0b));
594 BranchOrBacktrack(on_no_match, hi, a0, Operand(1));
595 __ bind(&done);
596 }
597 return true;
598 }
599 case 'w': {
600 if (mode_ != ASCII) {
601 // Table is 128 entries, so all ASCII characters can be tested.
602 BranchOrBacktrack(on_no_match, hi, current_character(), Operand('z'));
603 }
604 ExternalReference map = ExternalReference::re_word_character_map();
605 __ li(a0, Operand(map));
606 __ Addu(a0, a0, current_character());
607 __ lbu(a0, MemOperand(a0, 0));
608 BranchOrBacktrack(on_no_match, eq, a0, Operand(zero_reg));
609 return true;
610 }
611 case 'W': {
612 Label done;
613 if (mode_ != ASCII) {
614 // Table is 128 entries, so all ASCII characters can be tested.
615 __ Branch(&done, hi, current_character(), Operand('z'));
616 }
617 ExternalReference map = ExternalReference::re_word_character_map();
618 __ li(a0, Operand(map));
619 __ Addu(a0, a0, current_character());
620 __ lbu(a0, MemOperand(a0, 0));
621 BranchOrBacktrack(on_no_match, ne, a0, Operand(zero_reg));
622 if (mode_ != ASCII) {
623 __ bind(&done);
624 }
625 return true;
626 }
627 case '*':
628 // Match any character.
629 return true;
630 // No custom implementation (yet): s(UC16), S(UC16).
631 default:
632 return false;
633 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000634}
635
636
637void RegExpMacroAssemblerMIPS::Fail() {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000638 __ li(v0, Operand(FAILURE));
639 __ jmp(&exit_label_);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000640}
641
642
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000643Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +0000644 Label return_v0;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000645 if (masm_->has_exception()) {
646 // If the code gets corrupted due to long regular expressions and lack of
647 // space on trampolines, an internal exception flag is set. If this case
648 // is detected, we will jump into exit sequence right away.
649 __ bind_to(&entry_label_, internal_failure_label_.pos());
650 } else {
651 // Finalize code - write the entry point code now we know how many
652 // registers we need.
653
654 // Entry code:
655 __ bind(&entry_label_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000656
657 // Tell the system that we have a stack frame. Because the type is MANUAL,
658 // no is generated.
659 FrameScope scope(masm_, StackFrame::MANUAL);
660
661 // Actually emit code to start a new stack frame.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000662 // Push arguments
663 // Save callee-save registers.
664 // Start new stack frame.
665 // Store link register in existing stack-cell.
666 // Order here should correspond to order of offset constants in header file.
667 RegList registers_to_retain = s0.bit() | s1.bit() | s2.bit() |
668 s3.bit() | s4.bit() | s5.bit() | s6.bit() | s7.bit() | fp.bit();
669 RegList argument_registers = a0.bit() | a1.bit() | a2.bit() | a3.bit();
670 __ MultiPush(argument_registers | registers_to_retain | ra.bit());
671 // Set frame pointer in space for it if this is not a direct call
672 // from generated code.
673 __ Addu(frame_pointer(), sp, Operand(4 * kPointerSize));
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +0000674 __ mov(a0, zero_reg);
675 __ push(a0); // Make room for success counter and initialize it to 0.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000676 __ push(a0); // Make room for "position - 1" constant (value irrelevant).
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000677
678 // Check if we have space on the stack for registers.
679 Label stack_limit_hit;
680 Label stack_ok;
681
682 ExternalReference stack_limit =
683 ExternalReference::address_of_stack_limit(masm_->isolate());
684 __ li(a0, Operand(stack_limit));
685 __ lw(a0, MemOperand(a0));
686 __ Subu(a0, sp, a0);
687 // Handle it if the stack pointer is already below the stack limit.
688 __ Branch(&stack_limit_hit, le, a0, Operand(zero_reg));
689 // Check if there is room for the variable number of registers above
690 // the stack limit.
691 __ Branch(&stack_ok, hs, a0, Operand(num_registers_ * kPointerSize));
692 // Exit with OutOfMemory exception. There is not enough space on the stack
693 // for our working registers.
694 __ li(v0, Operand(EXCEPTION));
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +0000695 __ jmp(&return_v0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000696
697 __ bind(&stack_limit_hit);
698 CallCheckStackGuardState(a0);
699 // If returned value is non-zero, we exit with the returned value as result.
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +0000700 __ Branch(&return_v0, ne, v0, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000701
702 __ bind(&stack_ok);
703 // Allocate space on stack for registers.
704 __ Subu(sp, sp, Operand(num_registers_ * kPointerSize));
705 // Load string end.
706 __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
707 // Load input start.
708 __ lw(a0, MemOperand(frame_pointer(), kInputStart));
709 // Find negative length (offset of start relative to end).
710 __ Subu(current_input_offset(), a0, end_of_input_address());
711 // Set a0 to address of char before start of the input string
712 // (effectively string position -1).
713 __ lw(a1, MemOperand(frame_pointer(), kStartIndex));
714 __ Subu(a0, current_input_offset(), Operand(char_size()));
715 __ sll(t5, a1, (mode_ == UC16) ? 1 : 0);
716 __ Subu(a0, a0, t5);
717 // Store this value in a local variable, for use when clearing
718 // position registers.
719 __ sw(a0, MemOperand(frame_pointer(), kInputStartMinusOne));
720
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +0000721 // Initialize code pointer register
722 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000723
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +0000724 Label load_char_start_regexp, start_regexp;
725 // Load newline if index is at start, previous character otherwise.
726 __ Branch(&load_char_start_regexp, ne, a1, Operand(zero_reg));
727 __ li(current_character(), Operand('\n'));
728 __ jmp(&start_regexp);
729
730 // Global regexp restarts matching here.
731 __ bind(&load_char_start_regexp);
732 // Load previous char as initial value of current character register.
733 LoadCurrentCharacterUnchecked(-1, 1);
734 __ bind(&start_regexp);
735
736 // Initialize on-stack registers.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000737 if (num_saved_registers_ > 0) { // Always is, if generated from a regexp.
738 // Fill saved registers with initial value = start offset - 1.
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +0000739 if (num_saved_registers_ > 8) {
740 // Address of register 0.
741 __ Addu(a1, frame_pointer(), Operand(kRegisterZero));
742 __ li(a2, Operand(num_saved_registers_));
743 Label init_loop;
744 __ bind(&init_loop);
745 __ sw(a0, MemOperand(a1));
746 __ Addu(a1, a1, Operand(-kPointerSize));
747 __ Subu(a2, a2, Operand(1));
748 __ Branch(&init_loop, ne, a2, Operand(zero_reg));
749 } else {
750 for (int i = 0; i < num_saved_registers_; i++) {
751 __ sw(a0, register_location(i));
752 }
753 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000754 }
755
756 // Initialize backtrack stack pointer.
757 __ lw(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackHighEnd));
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +0000758
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000759 __ jmp(&start_label_);
760
761
762 // Exit code:
763 if (success_label_.is_linked()) {
764 // Save captures when successful.
765 __ bind(&success_label_);
766 if (num_saved_registers_ > 0) {
767 // Copy captures to output.
768 __ lw(a1, MemOperand(frame_pointer(), kInputStart));
769 __ lw(a0, MemOperand(frame_pointer(), kRegisterOutput));
770 __ lw(a2, MemOperand(frame_pointer(), kStartIndex));
771 __ Subu(a1, end_of_input_address(), a1);
772 // a1 is length of input in bytes.
773 if (mode_ == UC16) {
774 __ srl(a1, a1, 1);
775 }
776 // a1 is length of input in characters.
777 __ Addu(a1, a1, Operand(a2));
778 // a1 is length of string in characters.
779
780 ASSERT_EQ(0, num_saved_registers_ % 2);
781 // Always an even number of capture registers. This allows us to
782 // unroll the loop once to add an operation between a load of a register
783 // and the following use of that register.
784 for (int i = 0; i < num_saved_registers_; i += 2) {
785 __ lw(a2, register_location(i));
786 __ lw(a3, register_location(i + 1));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000787 if (i == 0 && global_with_zero_length_check()) {
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +0000788 // Keep capture start in a4 for the zero-length check later.
789 __ mov(t7, a2);
790 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000791 if (mode_ == UC16) {
792 __ sra(a2, a2, 1);
793 __ Addu(a2, a2, a1);
794 __ sra(a3, a3, 1);
795 __ Addu(a3, a3, a1);
796 } else {
797 __ Addu(a2, a1, Operand(a2));
798 __ Addu(a3, a1, Operand(a3));
799 }
800 __ sw(a2, MemOperand(a0));
801 __ Addu(a0, a0, kPointerSize);
802 __ sw(a3, MemOperand(a0));
803 __ Addu(a0, a0, kPointerSize);
804 }
805 }
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +0000806
807 if (global()) {
808 // Restart matching if the regular expression is flagged as global.
809 __ lw(a0, MemOperand(frame_pointer(), kSuccessfulCaptures));
810 __ lw(a1, MemOperand(frame_pointer(), kNumOutputRegisters));
811 __ lw(a2, MemOperand(frame_pointer(), kRegisterOutput));
812 // Increment success counter.
813 __ Addu(a0, a0, 1);
814 __ sw(a0, MemOperand(frame_pointer(), kSuccessfulCaptures));
815 // Capture results have been stored, so the number of remaining global
816 // output registers is reduced by the number of stored captures.
817 __ Subu(a1, a1, num_saved_registers_);
818 // Check whether we have enough room for another set of capture results.
819 __ mov(v0, a0);
820 __ Branch(&return_v0, lt, a1, Operand(num_saved_registers_));
821
822 __ sw(a1, MemOperand(frame_pointer(), kNumOutputRegisters));
823 // Advance the location for output.
824 __ Addu(a2, a2, num_saved_registers_ * kPointerSize);
825 __ sw(a2, MemOperand(frame_pointer(), kRegisterOutput));
826
827 // Prepare a0 to initialize registers with its value in the next run.
828 __ lw(a0, MemOperand(frame_pointer(), kInputStartMinusOne));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000829
830 if (global_with_zero_length_check()) {
831 // Special case for zero-length matches.
832 // t7: capture start index
833 // Not a zero-length match, restart.
834 __ Branch(
835 &load_char_start_regexp, ne, current_input_offset(), Operand(t7));
836 // Offset from the end is zero if we already reached the end.
837 __ Branch(&exit_label_, eq, current_input_offset(),
838 Operand(zero_reg));
839 // Advance current position after a zero-length match.
840 __ Addu(current_input_offset(),
841 current_input_offset(),
842 Operand((mode_ == UC16) ? 2 : 1));
843 }
844
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +0000845 __ Branch(&load_char_start_regexp);
846 } else {
847 __ li(v0, Operand(SUCCESS));
848 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000849 }
850 // Exit and return v0.
851 __ bind(&exit_label_);
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +0000852 if (global()) {
853 __ lw(v0, MemOperand(frame_pointer(), kSuccessfulCaptures));
854 }
855
856 __ bind(&return_v0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000857 // Skip sp past regexp registers and local variables..
858 __ mov(sp, frame_pointer());
859 // Restore registers s0..s7 and return (restoring ra to pc).
860 __ MultiPop(registers_to_retain | ra.bit());
861 __ Ret();
862
863 // Backtrack code (branch target for conditional backtracks).
864 if (backtrack_label_.is_linked()) {
865 __ bind(&backtrack_label_);
866 Backtrack();
867 }
868
869 Label exit_with_exception;
870
871 // Preempt-code.
872 if (check_preempt_label_.is_linked()) {
873 SafeCallTarget(&check_preempt_label_);
874 // Put regexp engine registers on stack.
875 RegList regexp_registers_to_retain = current_input_offset().bit() |
876 current_character().bit() | backtrack_stackpointer().bit();
877 __ MultiPush(regexp_registers_to_retain);
878 CallCheckStackGuardState(a0);
879 __ MultiPop(regexp_registers_to_retain);
880 // If returning non-zero, we should end execution with the given
881 // result as return value.
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +0000882 __ Branch(&return_v0, ne, v0, Operand(zero_reg));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000883
884 // String might have moved: Reload end of string from frame.
885 __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
danno@chromium.org88aa0582012-03-23 15:11:57 +0000886 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000887 SafeReturn();
888 }
889
890 // Backtrack stack overflow code.
891 if (stack_overflow_label_.is_linked()) {
892 SafeCallTarget(&stack_overflow_label_);
893 // Reached if the backtrack-stack limit has been hit.
894 // Put regexp engine registers on stack first.
895 RegList regexp_registers = current_input_offset().bit() |
896 current_character().bit();
897 __ MultiPush(regexp_registers);
898 Label grow_failed;
899 // Call GrowStack(backtrack_stackpointer(), &stack_base)
900 static const int num_arguments = 3;
901 __ PrepareCallCFunction(num_arguments, a0);
902 __ mov(a0, backtrack_stackpointer());
903 __ Addu(a1, frame_pointer(), Operand(kStackHighEnd));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000904 __ li(a2, Operand(ExternalReference::isolate_address(masm_->isolate())));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000905 ExternalReference grow_stack =
906 ExternalReference::re_grow_stack(masm_->isolate());
907 __ CallCFunction(grow_stack, num_arguments);
908 // Restore regexp registers.
909 __ MultiPop(regexp_registers);
910 // If return NULL, we have failed to grow the stack, and
911 // must exit with a stack-overflow exception.
912 __ Branch(&exit_with_exception, eq, v0, Operand(zero_reg));
913 // Otherwise use return value as new stack pointer.
914 __ mov(backtrack_stackpointer(), v0);
915 // Restore saved registers and continue.
danno@chromium.org88aa0582012-03-23 15:11:57 +0000916 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000917 __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
918 SafeReturn();
919 }
920
921 if (exit_with_exception.is_linked()) {
922 // If any of the code above needed to exit with an exception.
923 __ bind(&exit_with_exception);
924 // Exit with Result EXCEPTION(-1) to signal thrown exception.
925 __ li(v0, Operand(EXCEPTION));
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +0000926 __ jmp(&return_v0);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000927 }
928 }
929
930 CodeDesc code_desc;
931 masm_->GetCode(&code_desc);
932 Handle<Code> code = FACTORY->NewCode(code_desc,
933 Code::ComputeFlags(Code::REGEXP),
934 masm_->CodeObject());
935 LOG(Isolate::Current(), RegExpCodeCreateEvent(*code, *source));
936 return Handle<HeapObject>::cast(code);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000937}
938
939
940void RegExpMacroAssemblerMIPS::GoTo(Label* to) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000941 if (to == NULL) {
942 Backtrack();
943 return;
944 }
945 __ jmp(to);
946 return;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000947}
948
949
950void RegExpMacroAssemblerMIPS::IfRegisterGE(int reg,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000951 int comparand,
952 Label* if_ge) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000953 __ lw(a0, register_location(reg));
954 BranchOrBacktrack(if_ge, ge, a0, Operand(comparand));
955}
956
957
958void RegExpMacroAssemblerMIPS::IfRegisterLT(int reg,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000959 int comparand,
960 Label* if_lt) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000961 __ lw(a0, register_location(reg));
962 BranchOrBacktrack(if_lt, lt, a0, Operand(comparand));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000963}
964
965
966void RegExpMacroAssemblerMIPS::IfRegisterEqPos(int reg,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000967 Label* if_eq) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000968 __ lw(a0, register_location(reg));
969 BranchOrBacktrack(if_eq, eq, a0, Operand(current_input_offset()));
lrn@chromium.org7516f052011-03-30 08:52:27 +0000970}
971
972
973RegExpMacroAssembler::IrregexpImplementation
974 RegExpMacroAssemblerMIPS::Implementation() {
975 return kMIPSImplementation;
976}
977
978
979void RegExpMacroAssemblerMIPS::LoadCurrentCharacter(int cp_offset,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000980 Label* on_end_of_input,
981 bool check_bounds,
982 int characters) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000983 ASSERT(cp_offset >= -1); // ^ and \b can look behind one character.
984 ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works).
985 if (check_bounds) {
986 CheckPosition(cp_offset + characters - 1, on_end_of_input);
987 }
988 LoadCurrentCharacterUnchecked(cp_offset, characters);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000989}
990
991
992void RegExpMacroAssemblerMIPS::PopCurrentPosition() {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000993 Pop(current_input_offset());
lrn@chromium.org7516f052011-03-30 08:52:27 +0000994}
995
996
997void RegExpMacroAssemblerMIPS::PopRegister(int register_index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000998 Pop(a0);
999 __ sw(a0, register_location(register_index));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001000}
1001
1002
lrn@chromium.org7516f052011-03-30 08:52:27 +00001003void RegExpMacroAssemblerMIPS::PushBacktrack(Label* label) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001004 if (label->is_bound()) {
1005 int target = label->pos();
1006 __ li(a0, Operand(target + Code::kHeaderSize - kHeapObjectTag));
1007 } else {
jkummerow@chromium.org7bd87f02013-03-20 18:06:29 +00001008 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001009 Label after_constant;
1010 __ Branch(&after_constant);
1011 int offset = masm_->pc_offset();
1012 int cp_offset = offset + Code::kHeaderSize - kHeapObjectTag;
1013 __ emit(0);
1014 masm_->label_at_put(label, offset);
1015 __ bind(&after_constant);
1016 if (is_int16(cp_offset)) {
1017 __ lw(a0, MemOperand(code_pointer(), cp_offset));
1018 } else {
1019 __ Addu(a0, code_pointer(), cp_offset);
1020 __ lw(a0, MemOperand(a0, 0));
1021 }
1022 }
1023 Push(a0);
1024 CheckStackLimit();
lrn@chromium.org7516f052011-03-30 08:52:27 +00001025}
1026
1027
1028void RegExpMacroAssemblerMIPS::PushCurrentPosition() {
1029 Push(current_input_offset());
1030}
1031
1032
1033void RegExpMacroAssemblerMIPS::PushRegister(int register_index,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001034 StackCheckFlag check_stack_limit) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001035 __ lw(a0, register_location(register_index));
1036 Push(a0);
1037 if (check_stack_limit) CheckStackLimit();
lrn@chromium.org7516f052011-03-30 08:52:27 +00001038}
1039
1040
1041void RegExpMacroAssemblerMIPS::ReadCurrentPositionFromRegister(int reg) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001042 __ lw(current_input_offset(), register_location(reg));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001043}
1044
1045
1046void RegExpMacroAssemblerMIPS::ReadStackPointerFromRegister(int reg) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001047 __ lw(backtrack_stackpointer(), register_location(reg));
1048 __ lw(a0, MemOperand(frame_pointer(), kStackHighEnd));
1049 __ Addu(backtrack_stackpointer(), backtrack_stackpointer(), Operand(a0));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001050}
1051
1052
1053void RegExpMacroAssemblerMIPS::SetCurrentPositionFromEnd(int by) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001054 Label after_position;
1055 __ Branch(&after_position,
1056 ge,
1057 current_input_offset(),
1058 Operand(-by * char_size()));
1059 __ li(current_input_offset(), -by * char_size());
1060 // On RegExp code entry (where this operation is used), the character before
1061 // the current position is expected to be already loaded.
1062 // We have advanced the position, so it's safe to read backwards.
1063 LoadCurrentCharacterUnchecked(-1, 1);
1064 __ bind(&after_position);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001065}
1066
1067
1068void RegExpMacroAssemblerMIPS::SetRegister(int register_index, int to) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001069 ASSERT(register_index >= num_saved_registers_); // Reserved for positions!
1070 __ li(a0, Operand(to));
1071 __ sw(a0, register_location(register_index));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001072}
1073
1074
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +00001075bool RegExpMacroAssemblerMIPS::Succeed() {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001076 __ jmp(&success_label_);
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +00001077 return global();
lrn@chromium.org7516f052011-03-30 08:52:27 +00001078}
1079
1080
1081void RegExpMacroAssemblerMIPS::WriteCurrentPositionToRegister(int reg,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001082 int cp_offset) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001083 if (cp_offset == 0) {
1084 __ sw(current_input_offset(), register_location(reg));
1085 } else {
1086 __ Addu(a0, current_input_offset(), Operand(cp_offset * char_size()));
1087 __ sw(a0, register_location(reg));
1088 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001089}
1090
1091
1092void RegExpMacroAssemblerMIPS::ClearRegisters(int reg_from, int reg_to) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001093 ASSERT(reg_from <= reg_to);
1094 __ lw(a0, MemOperand(frame_pointer(), kInputStartMinusOne));
1095 for (int reg = reg_from; reg <= reg_to; reg++) {
1096 __ sw(a0, register_location(reg));
1097 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001098}
1099
1100
1101void RegExpMacroAssemblerMIPS::WriteStackPointerToRegister(int reg) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001102 __ lw(a1, MemOperand(frame_pointer(), kStackHighEnd));
1103 __ Subu(a0, backtrack_stackpointer(), a1);
1104 __ sw(a0, register_location(reg));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001105}
1106
1107
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001108bool RegExpMacroAssemblerMIPS::CanReadUnaligned() {
1109 return false;
1110}
1111
1112
lrn@chromium.org7516f052011-03-30 08:52:27 +00001113// Private methods:
1114
1115void RegExpMacroAssemblerMIPS::CallCheckStackGuardState(Register scratch) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001116 static const int num_arguments = 3;
1117 __ PrepareCallCFunction(num_arguments, scratch);
1118 __ mov(a2, frame_pointer());
1119 // Code* of self.
danno@chromium.org88aa0582012-03-23 15:11:57 +00001120 __ li(a1, Operand(masm_->CodeObject()), CONSTANT_SIZE);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001121 // a0 becomes return address pointer.
1122 ExternalReference stack_guard_check =
1123 ExternalReference::re_check_stack_guard_state(masm_->isolate());
1124 CallCFunctionUsingStub(stack_guard_check, num_arguments);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001125}
1126
1127
1128// Helper function for reading a value out of a stack frame.
1129template <typename T>
1130static T& frame_entry(Address re_frame, int frame_offset) {
1131 return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset));
1132}
1133
1134
1135int RegExpMacroAssemblerMIPS::CheckStackGuardState(Address* return_address,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001136 Code* re_code,
1137 Address re_frame) {
1138 Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
1139 ASSERT(isolate == Isolate::Current());
1140 if (isolate->stack_guard()->IsStackOverflow()) {
1141 isolate->StackOverflow();
1142 return EXCEPTION;
1143 }
1144
1145 // If not real stack overflow the stack guard was used to interrupt
1146 // execution for another purpose.
1147
1148 // If this is a direct call from JavaScript retry the RegExp forcing the call
1149 // through the runtime system. Currently the direct call cannot handle a GC.
1150 if (frame_entry<int>(re_frame, kDirectCall) == 1) {
1151 return RETRY;
1152 }
1153
1154 // Prepare for possible GC.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001155 HandleScope handles(isolate);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001156 Handle<Code> code_handle(re_code);
1157
1158 Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
1159 // Current string.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001160 bool is_ascii = subject->IsOneByteRepresentationUnderneath();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001161
1162 ASSERT(re_code->instruction_start() <= *return_address);
1163 ASSERT(*return_address <=
1164 re_code->instruction_start() + re_code->instruction_size());
1165
ulan@chromium.org812308e2012-02-29 15:58:45 +00001166 MaybeObject* result = Execution::HandleStackGuardInterrupt(isolate);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001167
1168 if (*code_handle != re_code) { // Return address no longer valid.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001169 int delta = code_handle->address() - re_code->address();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001170 // Overwrite the return address on the stack.
1171 *return_address += delta;
1172 }
1173
1174 if (result->IsException()) {
1175 return EXCEPTION;
1176 }
1177
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001178 Handle<String> subject_tmp = subject;
1179 int slice_offset = 0;
1180
1181 // Extract the underlying string and the slice offset.
1182 if (StringShape(*subject_tmp).IsCons()) {
1183 subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first());
1184 } else if (StringShape(*subject_tmp).IsSliced()) {
1185 SlicedString* slice = SlicedString::cast(*subject_tmp);
1186 subject_tmp = Handle<String>(slice->parent());
1187 slice_offset = slice->offset();
1188 }
1189
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001190 // String might have changed.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001191 if (subject_tmp->IsOneByteRepresentation() != is_ascii) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001192 // If we changed between an ASCII and an UC16 string, the specialized
1193 // code cannot be used, and we need to restart regexp matching from
1194 // scratch (including, potentially, compiling a new version of the code).
1195 return RETRY;
1196 }
1197
1198 // Otherwise, the content of the string might have moved. It must still
1199 // be a sequential or external string with the same content.
1200 // Update the start and end pointers in the stack frame to the current
1201 // location (whether it has actually moved or not).
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001202 ASSERT(StringShape(*subject_tmp).IsSequential() ||
1203 StringShape(*subject_tmp).IsExternal());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001204
1205 // The original start address of the characters to match.
1206 const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
1207
1208 // Find the current start address of the same character at the current string
1209 // position.
1210 int start_index = frame_entry<int>(re_frame, kStartIndex);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001211 const byte* new_address = StringCharacterPosition(*subject_tmp,
1212 start_index + slice_offset);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001213
1214 if (start_address != new_address) {
1215 // If there is a difference, update the object pointer and start and end
1216 // addresses in the RegExp stack frame to match the new value.
1217 const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001218 int byte_length = static_cast<int>(end_address - start_address);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001219 frame_entry<const String*>(re_frame, kInputString) = *subject;
1220 frame_entry<const byte*>(re_frame, kInputStart) = new_address;
1221 frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001222 } else if (frame_entry<const String*>(re_frame, kInputString) != *subject) {
1223 // Subject string might have been a ConsString that underwent
1224 // short-circuiting during GC. That will not change start_address but
1225 // will change pointer inside the subject handle.
1226 frame_entry<const String*>(re_frame, kInputString) = *subject;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001227 }
1228
lrn@chromium.org7516f052011-03-30 08:52:27 +00001229 return 0;
1230}
1231
1232
1233MemOperand RegExpMacroAssemblerMIPS::register_location(int register_index) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001234 ASSERT(register_index < (1<<30));
1235 if (num_registers_ <= register_index) {
1236 num_registers_ = register_index + 1;
1237 }
1238 return MemOperand(frame_pointer(),
1239 kRegisterZero - register_index * kPointerSize);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001240}
1241
1242
1243void RegExpMacroAssemblerMIPS::CheckPosition(int cp_offset,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001244 Label* on_outside_input) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001245 BranchOrBacktrack(on_outside_input,
1246 ge,
1247 current_input_offset(),
1248 Operand(-cp_offset * char_size()));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001249}
1250
1251
1252void RegExpMacroAssemblerMIPS::BranchOrBacktrack(Label* to,
1253 Condition condition,
1254 Register rs,
1255 const Operand& rt) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001256 if (condition == al) { // Unconditional.
1257 if (to == NULL) {
1258 Backtrack();
1259 return;
1260 }
1261 __ jmp(to);
1262 return;
1263 }
1264 if (to == NULL) {
1265 __ Branch(&backtrack_label_, condition, rs, rt);
1266 return;
1267 }
1268 __ Branch(to, condition, rs, rt);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001269}
1270
1271
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001272void RegExpMacroAssemblerMIPS::SafeCall(Label* to,
1273 Condition cond,
1274 Register rs,
1275 const Operand& rt) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001276 __ BranchAndLink(to, cond, rs, rt);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001277}
1278
1279
1280void RegExpMacroAssemblerMIPS::SafeReturn() {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001281 __ pop(ra);
1282 __ Addu(t5, ra, Operand(masm_->CodeObject()));
1283 __ Jump(t5);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001284}
1285
1286
1287void RegExpMacroAssemblerMIPS::SafeCallTarget(Label* name) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001288 __ bind(name);
1289 __ Subu(ra, ra, Operand(masm_->CodeObject()));
1290 __ push(ra);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001291}
1292
1293
1294void RegExpMacroAssemblerMIPS::Push(Register source) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001295 ASSERT(!source.is(backtrack_stackpointer()));
1296 __ Addu(backtrack_stackpointer(),
1297 backtrack_stackpointer(),
1298 Operand(-kPointerSize));
1299 __ sw(source, MemOperand(backtrack_stackpointer()));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001300}
1301
1302
1303void RegExpMacroAssemblerMIPS::Pop(Register target) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001304 ASSERT(!target.is(backtrack_stackpointer()));
1305 __ lw(target, MemOperand(backtrack_stackpointer()));
1306 __ Addu(backtrack_stackpointer(), backtrack_stackpointer(), kPointerSize);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001307}
1308
1309
1310void RegExpMacroAssemblerMIPS::CheckPreemption() {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001311 // Check for preemption.
1312 ExternalReference stack_limit =
1313 ExternalReference::address_of_stack_limit(masm_->isolate());
1314 __ li(a0, Operand(stack_limit));
1315 __ lw(a0, MemOperand(a0));
1316 SafeCall(&check_preempt_label_, ls, sp, Operand(a0));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001317}
1318
1319
1320void RegExpMacroAssemblerMIPS::CheckStackLimit() {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001321 ExternalReference stack_limit =
1322 ExternalReference::address_of_regexp_stack_limit(masm_->isolate());
1323
1324 __ li(a0, Operand(stack_limit));
1325 __ lw(a0, MemOperand(a0));
1326 SafeCall(&stack_overflow_label_, ls, backtrack_stackpointer(), Operand(a0));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001327}
1328
1329
1330void RegExpMacroAssemblerMIPS::CallCFunctionUsingStub(
1331 ExternalReference function,
1332 int num_arguments) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001333 // Must pass all arguments in registers. The stub pushes on the stack.
1334 ASSERT(num_arguments <= 4);
1335 __ li(code_pointer(), Operand(function));
1336 RegExpCEntryStub stub;
1337 __ CallStub(&stub);
1338 if (OS::ActivationFrameAlignment() != 0) {
1339 __ lw(sp, MemOperand(sp, 16));
1340 }
danno@chromium.org88aa0582012-03-23 15:11:57 +00001341 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001342}
1343
1344
1345void RegExpMacroAssemblerMIPS::LoadCurrentCharacterUnchecked(int cp_offset,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001346 int characters) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001347 Register offset = current_input_offset();
1348 if (cp_offset != 0) {
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +00001349 // t7 is not being used to store the capture start index at this point.
1350 __ Addu(t7, current_input_offset(), Operand(cp_offset * char_size()));
1351 offset = t7;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001352 }
1353 // We assume that we cannot do unaligned loads on MIPS, so this function
1354 // must only be used to load a single character at a time.
1355 ASSERT(characters == 1);
1356 __ Addu(t5, end_of_input_address(), Operand(offset));
1357 if (mode_ == ASCII) {
1358 __ lbu(current_character(), MemOperand(t5, 0));
1359 } else {
1360 ASSERT(mode_ == UC16);
1361 __ lhu(current_character(), MemOperand(t5, 0));
1362 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001363}
1364
1365
1366void RegExpCEntryStub::Generate(MacroAssembler* masm_) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001367 int stack_alignment = OS::ActivationFrameAlignment();
1368 if (stack_alignment < kPointerSize) stack_alignment = kPointerSize;
1369 // Stack is already aligned for call, so decrement by alignment
1370 // to make room for storing the return address.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001371 __ Subu(sp, sp, Operand(stack_alignment + kCArgsSlotsSize));
1372 const int return_address_offset = kCArgsSlotsSize;
1373 __ Addu(a0, sp, return_address_offset);
1374 __ sw(ra, MemOperand(a0, 0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001375 __ mov(t9, t1);
1376 __ Call(t9);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001377 __ lw(ra, MemOperand(sp, return_address_offset));
1378 __ Addu(sp, sp, Operand(stack_alignment + kCArgsSlotsSize));
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001379 __ Jump(ra);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001380}
1381
1382
1383#undef __
1384
1385#endif // V8_INTERPRETED_REGEXP
1386
1387}} // namespace v8::internal
1388
1389#endif // V8_TARGET_ARCH_MIPS