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