LCOV - code coverage report
Current view: top level - js/src/irregexp - NativeRegExpMacroAssembler.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 487 675 72.1 %
Date: 2017-07-14 16:53:18 Functions: 44 51 86.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99: */
       3             : 
       4             : // Copyright 2012 the V8 project authors. All rights reserved.
       5             : // Redistribution and use in source and binary forms, with or without
       6             : // modification, are permitted provided that the following conditions are
       7             : // met:
       8             : //
       9             : //     * Redistributions of source code must retain the above copyright
      10             : //       notice, this list of conditions and the following disclaimer.
      11             : //     * Redistributions in binary form must reproduce the above
      12             : //       copyright notice, this list of conditions and the following
      13             : //       disclaimer in the documentation and/or other materials provided
      14             : //       with the distribution.
      15             : //     * Neither the name of Google Inc. nor the names of its
      16             : //       contributors may be used to endorse or promote products derived
      17             : //       from this software without specific prior written permission.
      18             : //
      19             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      20             : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      21             : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      22             : // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      23             : // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      24             : // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      25             : // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      26             : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      27             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      28             : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      29             : // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      30             : 
      31             : #include "irregexp/NativeRegExpMacroAssembler.h"
      32             : 
      33             : #include "irregexp/RegExpStack.h"
      34             : #include "jit/Linker.h"
      35             : #ifdef JS_ION_PERF
      36             : # include "jit/PerfSpewer.h"
      37             : #endif
      38             : #include "vm/MatchPairs.h"
      39             : #include "vtune/VTuneWrapper.h"
      40             : 
      41             : #include "jit/MacroAssembler-inl.h"
      42             : 
      43             : using namespace js;
      44             : using namespace js::irregexp;
      45             : using namespace js::jit;
      46             : 
      47             : /*
      48             :  * This assembler uses the following register assignment convention:
      49             :  *
      50             :  * - current_character :
      51             :  *     Must be loaded using LoadCurrentCharacter before using any of the
      52             :  *     dispatch methods. Temporarily stores the index of capture start after a
      53             :  *     matching pass for a global regexp.
      54             :  * - current_position :
      55             :  *     Current position in input, as negative offset from end of string.
      56             :  *     Please notice that this is the byte offset, not the character offset!
      57             :  * - input_end_pointer :
      58             :  *     Points to byte after last character in the input.
      59             :  * - backtrack_stack_pointer :
      60             :  *     Points to tip of the heap allocated backtrack stack
      61             :  * - StackPointer :
      62             :  *     Points to tip of the native stack, used to access arguments, local
      63             :  *     variables and RegExp registers.
      64             :  *
      65             :  * The tempN registers are free to use for computations.
      66             :  */
      67             : 
      68          40 : NativeRegExpMacroAssembler::NativeRegExpMacroAssembler(JSContext* cx, LifoAlloc* alloc,
      69             :                                                        Mode mode, int registers_to_save,
      70          40 :                                                        RegExpShared::JitCodeTables& tables)
      71             :   : RegExpMacroAssembler(cx, *alloc, registers_to_save),
      72          40 :     tables(tables), cx(cx), mode_(mode)
      73             : {
      74             :     // Find physical registers for each compiler register.
      75          40 :     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
      76             : 
      77          40 :     input_end_pointer = regs.takeAny();
      78          40 :     current_character = regs.takeAny();
      79          40 :     current_position = regs.takeAny();
      80          40 :     backtrack_stack_pointer = regs.takeAny();
      81          40 :     temp0 = regs.takeAny();
      82          40 :     temp1 = regs.takeAny();
      83          40 :     temp2 = regs.takeAny();
      84             : 
      85          40 :     JitSpew(JitSpew_Codegen,
      86             :             "Starting RegExp (input_end_pointer %s) (current_character %s)"
      87             :             " (current_position %s) (backtrack_stack_pointer %s) (temp0 %s) temp1 (%s) temp2 (%s)",
      88             :             input_end_pointer.name(),
      89             :             current_character.name(),
      90             :             current_position.name(),
      91             :             backtrack_stack_pointer.name(),
      92             :             temp0.name(),
      93             :             temp1.name(),
      94          40 :             temp2.name());
      95             : 
      96          40 :     savedNonVolatileRegisters = SavedNonVolatileRegisters(regs);
      97             : 
      98          40 :     masm.jump(&entry_label_);
      99          40 :     masm.bind(&start_label_);
     100          40 : }
     101             : 
     102             : #define SPEW_PREFIX JitSpew_Codegen, "!!! "
     103             : 
     104             : // The signature of the code which this generates is:
     105             : //
     106             : // void execute(InputOutputData*);
     107             : RegExpCode
     108          40 : NativeRegExpMacroAssembler::GenerateCode(JSContext* cx, bool match_only)
     109             : {
     110          40 :     if (!cx->compartment()->ensureJitCompartmentExists(cx))
     111           0 :         return RegExpCode();
     112             : 
     113          40 :     JitSpew(SPEW_PREFIX "GenerateCode");
     114             : 
     115             :     // We need an even number of registers, for stack alignment.
     116          40 :     if (num_registers_ % 2 == 1)
     117           1 :         num_registers_++;
     118             : 
     119          80 :     Label return_temp0;
     120             : 
     121             :     // Finalize code - write the entry point code now we know how many
     122             :     // registers we need.
     123          40 :     masm.bind(&entry_label_);
     124             : 
     125             : #ifdef JS_CODEGEN_ARM64
     126             :     // ARM64 communicates stack address via sp, but uses a pseudo-sp for addressing.
     127             :     masm.initStackPtr();
     128             : #endif
     129             : 
     130             :     // Push non-volatile registers which might be modified by jitcode.
     131          40 :     size_t pushedNonVolatileRegisters = 0;
     132         120 :     for (GeneralRegisterForwardIterator iter(savedNonVolatileRegisters); iter.more(); ++iter) {
     133          80 :         masm.Push(*iter);
     134          80 :         pushedNonVolatileRegisters++;
     135             :     }
     136             : 
     137             : #if defined(XP_IOS) && defined(JS_CODEGEN_ARM)
     138             :     // The stack is 4-byte aligned on iOS, force 8-byte alignment.
     139             :     masm.movePtr(StackPointer, temp0);
     140             :     masm.andPtr(Imm32(~7), StackPointer);
     141             :     masm.push(temp0);
     142             :     masm.push(temp0);
     143             : #endif
     144             : 
     145             : #ifndef JS_CODEGEN_X86
     146             :     // The InputOutputData* is stored as an argument, save it on the stack
     147             :     // above the frame.
     148          40 :     masm.Push(IntArgReg0);
     149             : #endif
     150             : 
     151          40 :     size_t frameSize = sizeof(FrameData) + num_registers_ * sizeof(void*);
     152          40 :     frameSize = JS_ROUNDUP(frameSize + masm.framePushed(), ABIStackAlignment) - masm.framePushed();
     153             : 
     154             :     // Actually emit code to start a new stack frame.
     155          40 :     masm.reserveStack(frameSize);
     156          40 :     masm.checkStackAlignment();
     157             : 
     158             :     // Check if we have space on the stack. Use the *NoInterrupt stack limit to
     159             :     // avoid failing repeatedly when the regex code is called from Ion JIT code,
     160             :     // see bug 1208819.
     161          80 :     Label stack_ok;
     162          40 :     void* context_addr = cx->zone()->group()->addressOfOwnerContext();
     163          40 :     masm.loadPtr(AbsoluteAddress(context_addr), temp0);
     164          40 :     Address limit_addr(temp0, offsetof(JSContext, jitStackLimitNoInterrupt));
     165          40 :     masm.branchStackPtrRhs(Assembler::Below, limit_addr, &stack_ok);
     166             : 
     167             :     // Exit with an exception. There is not enough space on the stack
     168             :     // for our working registers.
     169          40 :     masm.movePtr(ImmWord(RegExpRunStatus_Error), temp0);
     170          40 :     masm.jump(&return_temp0);
     171             : 
     172          40 :     masm.bind(&stack_ok);
     173             : 
     174             : #ifdef XP_WIN
     175             :     // Ensure that we write to each stack page, in order. Skipping a page
     176             :     // on Windows can cause segmentation faults. Assuming page size is 4k.
     177             :     const int kPageSize = 4096;
     178             :     for (int i = frameSize - sizeof(void*); i >= 0; i -= kPageSize)
     179             :         masm.storePtr(temp0, Address(masm.getStackPointer(), i));
     180             : #endif // XP_WIN
     181             : 
     182             : #ifndef JS_CODEGEN_X86
     183             :     // The InputOutputData* is stored on the stack immediately above the frame.
     184          40 :     Address inputOutputAddress(masm.getStackPointer(), frameSize);
     185             : #else
     186             :     // The InputOutputData* is left in its original on stack location.
     187             :     Address inputOutputAddress(masm.getStackPointer(),
     188             :                                frameSize + (pushedNonVolatileRegisters + 1) * sizeof(void*));
     189             : #endif
     190             : 
     191          40 :     masm.loadPtr(inputOutputAddress, temp0);
     192             : 
     193             :     // Copy output registers to FrameData.
     194          40 :     if (!match_only) {
     195          22 :         Register matchPairsRegister = input_end_pointer;
     196          22 :         masm.loadPtr(Address(temp0, offsetof(InputOutputData, matches)), matchPairsRegister);
     197          22 :         masm.loadPtr(Address(matchPairsRegister, MatchPairs::offsetOfPairs()), temp1);
     198          22 :         masm.storePtr(temp1, Address(masm.getStackPointer(), offsetof(FrameData, outputRegisters)));
     199          22 :         masm.load32(Address(matchPairsRegister, MatchPairs::offsetOfPairCount()), temp1);
     200          22 :         masm.lshiftPtr(Imm32(1), temp1);
     201          22 :         masm.store32(temp1, Address(masm.getStackPointer(), offsetof(FrameData, numOutputRegisters)));
     202             : 
     203             : #ifdef DEBUG
     204             :         // Bounds check numOutputRegisters.
     205          44 :         Label enoughRegisters;
     206          44 :         masm.branchPtr(Assembler::GreaterThanOrEqual,
     207          44 :                        temp1, ImmWord(num_saved_registers_), &enoughRegisters);
     208          22 :         masm.assumeUnreachable("Not enough output registers for RegExp");
     209          22 :         masm.bind(&enoughRegisters);
     210             : #endif
     211             :     } else {
     212          18 :         Register endIndexRegister = input_end_pointer;
     213          18 :         masm.loadPtr(Address(temp0, offsetof(InputOutputData, endIndex)), endIndexRegister);
     214          18 :         masm.storePtr(endIndexRegister, Address(masm.getStackPointer(), offsetof(FrameData, endIndex)));
     215             :     }
     216             : 
     217             :     // Load string end pointer.
     218          40 :     masm.loadPtr(Address(temp0, offsetof(InputOutputData, inputEnd)), input_end_pointer);
     219             : 
     220             :     // Load input start pointer, and copy to FrameData.
     221          40 :     masm.loadPtr(Address(temp0, offsetof(InputOutputData, inputStart)), current_position);
     222          40 :     masm.storePtr(current_position, Address(masm.getStackPointer(), offsetof(FrameData, inputStart)));
     223             : 
     224             :     // Load start index, and copy to FrameData.
     225          40 :     masm.loadPtr(Address(temp0, offsetof(InputOutputData, startIndex)), temp1);
     226          40 :     masm.storePtr(temp1, Address(masm.getStackPointer(), offsetof(FrameData, startIndex)));
     227             : 
     228             :     // Set up input position to be negative offset from string end.
     229          40 :     masm.subPtr(input_end_pointer, current_position);
     230             : 
     231             :     // Set temp0 to address of char before start of the string.
     232             :     // (effectively string position -1).
     233          40 :     masm.computeEffectiveAddress(Address(current_position, -char_size()), temp0);
     234             : 
     235             :     // Store this value on the frame, for use when clearing
     236             :     // position registers.
     237          40 :     masm.storePtr(temp0, Address(masm.getStackPointer(), offsetof(FrameData, inputStartMinusOne)));
     238             : 
     239             :     // Update current position based on start index.
     240          40 :     masm.computeEffectiveAddress(BaseIndex(current_position, temp1, factor()), current_position);
     241             : 
     242          80 :     Label load_char_start_regexp, start_regexp;
     243             : 
     244             :     // Load newline if index is at start, previous character otherwise.
     245         120 :     masm.branchPtr(Assembler::NotEqual, 
     246          80 :                    Address(masm.getStackPointer(), offsetof(FrameData, startIndex)), ImmWord(0),
     247          40 :                    &load_char_start_regexp);
     248          40 :     masm.movePtr(ImmWord('\n'), current_character);
     249          40 :     masm.jump(&start_regexp);
     250             : 
     251             :     // Global regexp restarts matching here.
     252          40 :     masm.bind(&load_char_start_regexp);
     253             : 
     254             :     // Load previous char as initial value of current character register.
     255          40 :     LoadCurrentCharacterUnchecked(-1, 1);
     256          40 :     masm.bind(&start_regexp);
     257             : 
     258             :     // Initialize on-stack registers.
     259          40 :     MOZ_ASSERT(num_saved_registers_ > 0);
     260             : 
     261             :     // Fill saved registers with initial value = start offset - 1
     262             :     // Fill in stack push order, to avoid accessing across an unwritten
     263             :     // page (a problem on Windows).
     264          40 :     if (num_saved_registers_ > 8) {
     265           1 :         masm.movePtr(ImmWord(register_offset(0)), temp1);
     266           2 :         Label init_loop;
     267           1 :         masm.bind(&init_loop);
     268           1 :         masm.storePtr(temp0, BaseIndex(masm.getStackPointer(), temp1, TimesOne));
     269           1 :         masm.addPtr(ImmWord(sizeof(void*)), temp1);
     270           2 :         masm.branchPtr(Assembler::LessThan, temp1,
     271           2 :                        ImmWord(register_offset(num_saved_registers_)), &init_loop);
     272             :     } else {
     273             :         // Unroll the loop.
     274         149 :         for (int i = 0; i < num_saved_registers_; i++)
     275         110 :             masm.storePtr(temp0, register_location(i));
     276             :     }
     277             : 
     278             :     // Initialize backtrack stack pointer.
     279          40 :     size_t baseOffset = offsetof(JSContext, regexpStack) + RegExpStack::offsetOfBase();
     280          40 :     masm.loadPtr(AbsoluteAddress(context_addr), backtrack_stack_pointer);
     281          40 :     masm.loadPtr(Address(backtrack_stack_pointer, baseOffset), backtrack_stack_pointer);
     282          40 :     masm.storePtr(backtrack_stack_pointer,
     283          80 :                   Address(masm.getStackPointer(), offsetof(FrameData, backtrackStackBase)));
     284             : 
     285          40 :     masm.jump(&start_label_);
     286             : 
     287             :     // Exit code:
     288          40 :     if (success_label_.used()) {
     289          39 :         MOZ_ASSERT(num_saved_registers_ > 0);
     290             : 
     291          39 :         Address outputRegistersAddress(masm.getStackPointer(), offsetof(FrameData, outputRegisters));
     292             : 
     293             :         // Save captures when successful.
     294          39 :         masm.bind(&success_label_);
     295             : 
     296          39 :         if (!match_only) {
     297          21 :             Register outputRegisters = temp1;
     298          21 :             Register inputByteLength = backtrack_stack_pointer;
     299             : 
     300          21 :             masm.loadPtr(outputRegistersAddress, outputRegisters);
     301             : 
     302          21 :             masm.loadPtr(inputOutputAddress, temp0);
     303          21 :             masm.loadPtr(Address(temp0, offsetof(InputOutputData, inputEnd)), inputByteLength);
     304          21 :             masm.subPtr(Address(temp0, offsetof(InputOutputData, inputStart)), inputByteLength);
     305             : 
     306             :             // Copy captures to output. Note that registers on the C stack are pointer width
     307             :             // so that they might hold pointers, but output registers are int32_t.
     308         101 :             for (int i = 0; i < num_saved_registers_; i++) {
     309          80 :                 masm.loadPtr(register_location(i), temp0);
     310          80 :                 if (i == 0 && global_with_zero_length_check()) {
     311             :                     // Keep capture start in current_character for the zero-length check later.
     312           0 :                     masm.movePtr(temp0, current_character);
     313             :                 }
     314             : 
     315             :                 // Convert to index from start of string, not end.
     316          80 :                 masm.addPtr(inputByteLength, temp0);
     317             : 
     318             :                 // Convert byte index to character index.
     319          80 :                 if (mode_ == CHAR16)
     320          16 :                     masm.rshiftPtrArithmetic(Imm32(1), temp0);
     321             : 
     322          80 :                 masm.store32(temp0, Address(outputRegisters, i * sizeof(int32_t)));
     323             :             }
     324             :         }
     325             : 
     326             :         // Restart matching if the regular expression is flagged as global.
     327          39 :         if (global()) {
     328             :             // Increment success counter.
     329           0 :             masm.add32(Imm32(1), Address(masm.getStackPointer(), offsetof(FrameData, successfulCaptures)));
     330             : 
     331           0 :             Address numOutputRegistersAddress(masm.getStackPointer(), offsetof(FrameData, numOutputRegisters));
     332             : 
     333             :             // Capture results have been stored, so the number of remaining global
     334             :             // output registers is reduced by the number of stored captures.
     335           0 :             masm.load32(numOutputRegistersAddress, temp0);
     336             : 
     337           0 :             masm.sub32(Imm32(num_saved_registers_), temp0);
     338             : 
     339             :             // Check whether we have enough room for another set of capture results.
     340           0 :             masm.branch32(Assembler::LessThan, temp0, Imm32(num_saved_registers_), &exit_label_);
     341             : 
     342           0 :             masm.store32(temp0, numOutputRegistersAddress);
     343             : 
     344             :             // Advance the location for output.
     345           0 :             masm.add32(Imm32(num_saved_registers_ * sizeof(void*)), outputRegistersAddress);
     346             : 
     347             :             // Prepare temp0 to initialize registers with its value in the next run.
     348           0 :             masm.loadPtr(Address(masm.getStackPointer(), offsetof(FrameData, inputStartMinusOne)), temp0);
     349             : 
     350           0 :             if (global_with_zero_length_check()) {
     351             :                 // Special case for zero-length matches.
     352             : 
     353             :                 // The capture start index was loaded into current_character above.
     354           0 :                 masm.branchPtr(Assembler::NotEqual, current_position, current_character,
     355           0 :                                &load_char_start_regexp);
     356             : 
     357             :                 // edi (offset from the end) is zero if we already reached the end.
     358           0 :                 masm.branchTestPtr(Assembler::Zero, current_position, current_position,
     359           0 :                                    &exit_label_);
     360             : 
     361             :                 // Advance current position after a zero-length match.
     362           0 :                 masm.addPtr(Imm32(char_size()), current_position);
     363             :             }
     364             : 
     365           0 :             masm.jump(&load_char_start_regexp);
     366             :         } else {
     367          39 :             if (match_only) {
     368             :                 // Store endIndex.
     369             : 
     370          18 :                 Register endIndexRegister = temp1;
     371          18 :                 Register inputByteLength = backtrack_stack_pointer;
     372             : 
     373          18 :                 masm.loadPtr(Address(masm.getStackPointer(), offsetof(FrameData, endIndex)), endIndexRegister);
     374             : 
     375          18 :                 masm.loadPtr(inputOutputAddress, temp0);
     376          18 :                 masm.loadPtr(Address(temp0, offsetof(InputOutputData, inputEnd)), inputByteLength);
     377          18 :                 masm.subPtr(Address(temp0, offsetof(InputOutputData, inputStart)), inputByteLength);
     378             : 
     379          18 :                 masm.loadPtr(register_location(1), temp0);
     380             : 
     381             :                 // Convert to index from start of string, not end.
     382          18 :                 masm.addPtr(inputByteLength, temp0);
     383             : 
     384             :                 // Convert byte index to character index.
     385          18 :                 if (mode_ == CHAR16)
     386           1 :                     masm.rshiftPtrArithmetic(Imm32(1), temp0);
     387             : 
     388          18 :                 masm.store32(temp0, Address(endIndexRegister, 0));
     389             :             }
     390             : 
     391          39 :             masm.movePtr(ImmWord(RegExpRunStatus_Success), temp0);
     392             :         }
     393             :     }
     394             : 
     395          40 :     masm.bind(&exit_label_);
     396             : 
     397          40 :     if (global()) {
     398             :         // Return the number of successful captures.
     399           0 :         masm.load32(Address(masm.getStackPointer(), offsetof(FrameData, successfulCaptures)), temp0);
     400             :     }
     401             : 
     402          40 :     masm.bind(&return_temp0);
     403             : 
     404             :     // Store the result to the input structure.
     405          40 :     masm.loadPtr(inputOutputAddress, temp1);
     406          40 :     masm.storePtr(temp0, Address(temp1, offsetof(InputOutputData, result)));
     407             : 
     408             : #ifndef JS_CODEGEN_X86
     409             :     // Include the InputOutputData* when adjusting the stack size.
     410          40 :     masm.freeStack(frameSize + sizeof(void*));
     411             : #else
     412             :     masm.freeStack(frameSize);
     413             : #endif
     414             : 
     415             : #if defined(XP_IOS) && defined(JS_CODEGEN_ARM)
     416             :     masm.pop(temp0);
     417             :     masm.movePtr(temp0, StackPointer);
     418             : #endif
     419             : 
     420             :     // Restore non-volatile registers which were saved on entry.
     421         120 :     for (GeneralRegisterBackwardIterator iter(savedNonVolatileRegisters); iter.more(); ++iter)
     422          80 :         masm.Pop(*iter);
     423             : 
     424          40 :     masm.abiret();
     425             : 
     426             :     // Backtrack code (branch target for conditional backtracks).
     427          40 :     if (backtrack_label_.used()) {
     428          39 :         masm.bind(&backtrack_label_);
     429          39 :         Backtrack();
     430             :     }
     431             : 
     432             :     // Backtrack stack overflow code.
     433          40 :     if (stack_overflow_label_.used()) {
     434             :         // Reached if the backtrack-stack limit has been hit. temp2 holds the
     435             :         // StackPointer to use for accessing FrameData.
     436          40 :         masm.bind(&stack_overflow_label_);
     437             : 
     438          80 :         Label grow_failed;
     439             : 
     440          40 :         masm.movePtr(ImmPtr(cx->runtime()), temp1);
     441             : 
     442             :         // Save registers before calling C function
     443          40 :         LiveGeneralRegisterSet volatileRegs(GeneralRegisterSet::Volatile());
     444             : #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
     445             :         volatileRegs.add(Register::FromCode(Registers::lr));
     446             : #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     447             :         volatileRegs.add(Register::FromCode(Registers::ra));
     448             : #endif
     449          40 :         volatileRegs.takeUnchecked(temp0);
     450          40 :         volatileRegs.takeUnchecked(temp1);
     451          40 :         masm.PushRegsInMask(volatileRegs);
     452             : 
     453          40 :         masm.setupUnalignedABICall(temp0);
     454          40 :         masm.passABIArg(temp1);
     455          40 :         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, GrowBacktrackStack));
     456          40 :         masm.storeCallWordResult(temp0);
     457             : 
     458          40 :         masm.PopRegsInMask(volatileRegs);
     459             : 
     460             :         // If return false, we have failed to grow the stack, and
     461             :         // must exit with a stack-overflow exception. Do this in the caller
     462             :         // so that the stack is adjusted by our return instruction.
     463          80 :         Label return_from_overflow_handler;
     464          40 :         masm.branchTest32(Assembler::Zero, temp0, temp0, &return_from_overflow_handler);
     465             : 
     466             :         // Otherwise, store the new backtrack stack base and recompute the new
     467             :         // top of the stack.
     468          40 :         Address backtrackStackBaseAddress(temp2, offsetof(FrameData, backtrackStackBase));
     469          40 :         masm.subPtr(backtrackStackBaseAddress, backtrack_stack_pointer);
     470             : 
     471          40 :         void* context_addr = cx->zone()->group()->addressOfOwnerContext();
     472          40 :         size_t baseOffset = offsetof(JSContext, regexpStack) + RegExpStack::offsetOfBase();
     473          40 :         masm.loadPtr(AbsoluteAddress(context_addr), temp1);
     474          40 :         masm.loadPtr(Address(temp1, baseOffset), temp1);
     475          40 :         masm.storePtr(temp1, backtrackStackBaseAddress);
     476          40 :         masm.addPtr(temp1, backtrack_stack_pointer);
     477             : 
     478             :         // Resume execution in calling code.
     479          40 :         masm.bind(&return_from_overflow_handler);
     480          40 :         masm.abiret();
     481             :     }
     482             : 
     483          40 :     if (exit_with_exception_label_.used()) {
     484             :         // If any of the code above needed to exit with an exception.
     485          40 :         masm.bind(&exit_with_exception_label_);
     486             : 
     487             :         // Exit with an error result to signal thrown exception.
     488          40 :         masm.movePtr(ImmWord(RegExpRunStatus_Error), temp0);
     489          40 :         masm.jump(&return_temp0);
     490             :     }
     491             : 
     492          80 :     Linker linker(masm);
     493          80 :     AutoFlushICache afc("RegExp");
     494          40 :     JitCode* code = linker.newCode<NoGC>(cx, REGEXP_CODE);
     495          40 :     if (!code) {
     496           0 :         ReportOutOfMemory(cx);
     497           0 :         return RegExpCode();
     498             :     }
     499             : 
     500             : #ifdef JS_ION_PERF
     501             :     writePerfSpewerJitCodeProfile(code, "RegExp");
     502             : #endif
     503             : 
     504             : #ifdef MOZ_VTUNE
     505          40 :     vtune::MarkRegExp(code, match_only);
     506             : #endif
     507             : 
     508         246 :     for (size_t i = 0; i < labelPatches.length(); i++) {
     509         206 :         LabelPatch& v = labelPatches[i];
     510         206 :         MOZ_ASSERT(!v.label);
     511         618 :         Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, v.patchOffset),
     512         206 :                                            ImmPtr(code->raw() + v.labelOffset),
     513         206 :                                            ImmPtr(0));
     514             :     }
     515             : 
     516          40 :     JitSpew(JitSpew_Codegen, "Created RegExp (raw %p length %d)",
     517          80 :             (void*) code->raw(), (int) masm.bytesNeeded());
     518             : 
     519          40 :     RegExpCode res;
     520          40 :     res.jitCode = code;
     521          40 :     return res;
     522             : }
     523             : 
     524             : int
     525         166 : NativeRegExpMacroAssembler::stack_limit_slack()
     526             : {
     527         166 :     return RegExpStack::kStackLimitSlack;
     528             : }
     529             : 
     530             : void
     531         221 : NativeRegExpMacroAssembler::AdvanceCurrentPosition(int by)
     532             : {
     533         221 :     JitSpew(SPEW_PREFIX "AdvanceCurrentPosition(%d)", by);
     534             : 
     535         221 :     if (by != 0)
     536         221 :         masm.addPtr(Imm32(by * char_size()), current_position);
     537         221 : }
     538             : 
     539             : void
     540          13 : NativeRegExpMacroAssembler::AdvanceRegister(int reg, int by)
     541             : {
     542          13 :     JitSpew(SPEW_PREFIX "AdvanceRegister(%d, %d)", reg, by);
     543             : 
     544          13 :     MOZ_ASSERT(reg >= 0);
     545          13 :     MOZ_ASSERT(reg < num_registers_);
     546          13 :     if (by != 0)
     547          13 :         masm.addPtr(Imm32(by), register_location(reg));
     548          13 : }
     549             : 
     550             : void
     551         121 : NativeRegExpMacroAssembler::Backtrack()
     552             : {
     553         121 :     JitSpew(SPEW_PREFIX "Backtrack");
     554             : 
     555             :     // Check for an interrupt.
     556         242 :     Label noInterrupt;
     557         121 :     void* contextAddr = cx->zone()->group()->addressOfOwnerContext();
     558         121 :     masm.loadPtr(AbsoluteAddress(contextAddr), temp0);
     559         242 :     masm.branch32(Assembler::Equal, Address(temp0, offsetof(JSContext, interrupt_)), Imm32(0),
     560         121 :                   &noInterrupt);
     561         121 :     masm.movePtr(ImmWord(RegExpRunStatus_Error), temp0);
     562         121 :     masm.jump(&exit_label_);
     563         121 :     masm.bind(&noInterrupt);
     564             : 
     565             :     // Pop code location from backtrack stack and jump to location.
     566         121 :     PopBacktrack(temp0);
     567         121 :     masm.jump(temp0);
     568         121 : }
     569             : 
     570             : void
     571        1051 : NativeRegExpMacroAssembler::Bind(Label* label)
     572             : {
     573        1051 :     JitSpew(SPEW_PREFIX "Bind");
     574             : 
     575        1051 :     masm.bind(label);
     576        1051 : }
     577             : 
     578             : void
     579           1 : NativeRegExpMacroAssembler::CheckAtStart(Label* on_at_start)
     580             : {
     581           1 :     JitSpew(SPEW_PREFIX "CheckAtStart");
     582             : 
     583           2 :     Label not_at_start;
     584             : 
     585             :     // Did we start the match at the start of the string at all?
     586           1 :     Address startIndex(masm.getStackPointer(), offsetof(FrameData, startIndex));
     587           1 :     masm.branchPtr(Assembler::NotEqual, startIndex, ImmWord(0), &not_at_start);
     588             : 
     589             :     // If we did, are we still at the start of the input?
     590           1 :     masm.computeEffectiveAddress(BaseIndex(input_end_pointer, current_position, TimesOne), temp0);
     591             : 
     592           1 :     Address inputStart(masm.getStackPointer(), offsetof(FrameData, inputStart));
     593           1 :     masm.branchPtr(Assembler::Equal, inputStart, temp0, BranchOrBacktrack(on_at_start));
     594             : 
     595           1 :     masm.bind(&not_at_start);
     596           1 : }
     597             : 
     598             : void
     599          21 : NativeRegExpMacroAssembler::CheckNotAtStart(Label* on_not_at_start)
     600             : {
     601          21 :     JitSpew(SPEW_PREFIX "CheckNotAtStart");
     602             : 
     603             :     // Did we start the match at the start of the string at all?
     604          21 :     Address startIndex(masm.getStackPointer(), offsetof(FrameData, startIndex));
     605          21 :     masm.branchPtr(Assembler::NotEqual, startIndex, ImmWord(0), BranchOrBacktrack(on_not_at_start));
     606             : 
     607             :     // If we did, are we still at the start of the input?
     608          21 :     masm.computeEffectiveAddress(BaseIndex(input_end_pointer, current_position, TimesOne), temp0);
     609             : 
     610          21 :     Address inputStart(masm.getStackPointer(), offsetof(FrameData, inputStart));
     611          21 :     masm.branchPtr(Assembler::NotEqual, inputStart, temp0, BranchOrBacktrack(on_not_at_start));
     612          21 : }
     613             : 
     614             : void
     615          73 : NativeRegExpMacroAssembler::CheckCharacter(unsigned c, Label* on_equal)
     616             : {
     617          73 :     JitSpew(SPEW_PREFIX "CheckCharacter(%d)", (int) c);
     618          73 :     masm.branch32(Assembler::Equal, current_character, Imm32(c), BranchOrBacktrack(on_equal));
     619          73 : }
     620             : 
     621             : void
     622         334 : NativeRegExpMacroAssembler::CheckNotCharacter(unsigned c, Label* on_not_equal)
     623             : {
     624         334 :     JitSpew(SPEW_PREFIX "CheckNotCharacter(%d)", (int) c);
     625         334 :     masm.branch32(Assembler::NotEqual, current_character, Imm32(c), BranchOrBacktrack(on_not_equal));
     626         334 : }
     627             : 
     628             : void
     629          49 : NativeRegExpMacroAssembler::CheckCharacterAfterAnd(unsigned c, unsigned and_with,
     630             :                                                    Label* on_equal)
     631             : {
     632          49 :     JitSpew(SPEW_PREFIX "CheckCharacterAfterAnd(%d, %d)", (int) c, (int) and_with);
     633             : 
     634          49 :     if (c == 0) {
     635          12 :         masm.branchTest32(Assembler::Zero, current_character, Imm32(and_with),
     636           6 :                           BranchOrBacktrack(on_equal));
     637             :     } else {
     638          43 :         masm.move32(Imm32(and_with), temp0);
     639          43 :         masm.and32(current_character, temp0);
     640          43 :         masm.branch32(Assembler::Equal, temp0, Imm32(c), BranchOrBacktrack(on_equal));
     641             :     }
     642          49 : }
     643             : 
     644             : void
     645         111 : NativeRegExpMacroAssembler::CheckNotCharacterAfterAnd(unsigned c, unsigned and_with,
     646             :                                                       Label* on_not_equal)
     647             : {
     648         111 :     JitSpew(SPEW_PREFIX "CheckNotCharacterAfterAnd(%d, %d)", (int) c, (int) and_with);
     649             : 
     650         111 :     if (c == 0) {
     651          12 :         masm.branchTest32(Assembler::NonZero, current_character, Imm32(and_with),
     652           6 :                           BranchOrBacktrack(on_not_equal));
     653             :     } else {
     654         105 :         masm.move32(Imm32(and_with), temp0);
     655         105 :         masm.and32(current_character, temp0);
     656         105 :         masm.branch32(Assembler::NotEqual, temp0, Imm32(c), BranchOrBacktrack(on_not_equal));
     657             :     }
     658         111 : }
     659             : 
     660             : void
     661           7 : NativeRegExpMacroAssembler::CheckCharacterGT(char16_t c, Label* on_greater)
     662             : {
     663           7 :     JitSpew(SPEW_PREFIX "CheckCharacterGT(%d)", (int) c);
     664          14 :     masm.branch32(Assembler::GreaterThan, current_character, Imm32(c),
     665           7 :                   BranchOrBacktrack(on_greater));
     666           7 : }
     667             : 
     668             : void
     669           0 : NativeRegExpMacroAssembler::CheckCharacterLT(char16_t c, Label* on_less)
     670             : {
     671           0 :     JitSpew(SPEW_PREFIX "CheckCharacterLT(%d)", (int) c);
     672           0 :     masm.branch32(Assembler::LessThan, current_character, Imm32(c), BranchOrBacktrack(on_less));
     673           0 : }
     674             : 
     675             : void
     676          26 : NativeRegExpMacroAssembler::CheckGreedyLoop(Label* on_tos_equals_current_position)
     677             : {
     678          26 :     JitSpew(SPEW_PREFIX "CheckGreedyLoop");
     679             : 
     680          52 :     Label fallthrough;
     681          26 :     masm.branchPtr(Assembler::NotEqual,
     682          52 :                    Address(backtrack_stack_pointer, -int(sizeof(void*))), current_position,
     683          26 :                    &fallthrough);
     684          26 :     masm.subPtr(Imm32(sizeof(void*)), backtrack_stack_pointer);  // Pop.
     685          26 :     JumpOrBacktrack(on_tos_equals_current_position);
     686          26 :     masm.bind(&fallthrough);
     687          26 : }
     688             : 
     689             : void
     690           0 : NativeRegExpMacroAssembler::CheckNotBackReference(int start_reg, Label* on_no_match)
     691             : {
     692           0 :     JitSpew(SPEW_PREFIX "CheckNotBackReference(%d)", start_reg);
     693             : 
     694           0 :     Label fallthrough;
     695           0 :     Label success;
     696           0 :     Label fail;
     697             : 
     698             :     // Find length of back-referenced capture.
     699           0 :     masm.loadPtr(register_location(start_reg), current_character);
     700           0 :     masm.loadPtr(register_location(start_reg + 1), temp0);
     701           0 :     masm.subPtr(current_character, temp0);  // Length to check.
     702             : 
     703             :     // Fail on partial or illegal capture (start of capture after end of capture).
     704           0 :     masm.branchPtr(Assembler::LessThan, temp0, ImmWord(0), BranchOrBacktrack(on_no_match));
     705             : 
     706             :     // Succeed on empty capture (including no capture).
     707           0 :     masm.branchPtr(Assembler::Equal, temp0, ImmWord(0), &fallthrough);
     708             : 
     709             :     // Check that there are sufficient characters left in the input.
     710           0 :     masm.movePtr(current_position, temp1);
     711           0 :     masm.addPtr(temp0, temp1);
     712           0 :     masm.branchPtr(Assembler::GreaterThan, temp1, ImmWord(0), BranchOrBacktrack(on_no_match));
     713             : 
     714             :     // Save register to make it available below.
     715           0 :     masm.push(backtrack_stack_pointer);
     716             : 
     717             :     // Compute pointers to match string and capture string
     718           0 :     masm.computeEffectiveAddress(BaseIndex(input_end_pointer, current_position, TimesOne), temp1); // Start of match.
     719           0 :     masm.addPtr(input_end_pointer, current_character); // Start of capture.
     720           0 :     masm.computeEffectiveAddress(BaseIndex(temp0, temp1, TimesOne), backtrack_stack_pointer); // End of match.
     721             : 
     722           0 :     Label loop;
     723           0 :     masm.bind(&loop);
     724           0 :     if (mode_ == LATIN1) {
     725           0 :         masm.load8ZeroExtend(Address(current_character, 0), temp0);
     726           0 :         masm.load8ZeroExtend(Address(temp1, 0), temp2);
     727             :     } else {
     728           0 :         MOZ_ASSERT(mode_ == CHAR16);
     729           0 :         masm.load16ZeroExtend(Address(current_character, 0), temp0);
     730           0 :         masm.load16ZeroExtend(Address(temp1, 0), temp2);
     731             :     }
     732           0 :     masm.branch32(Assembler::NotEqual, temp0, temp2, &fail);
     733             : 
     734             :     // Increment pointers into capture and match string.
     735           0 :     masm.addPtr(Imm32(char_size()), current_character);
     736           0 :     masm.addPtr(Imm32(char_size()), temp1);
     737             : 
     738             :     // Check if we have reached end of match area.
     739           0 :     masm.branchPtr(Assembler::Below, temp1, backtrack_stack_pointer, &loop);
     740           0 :     masm.jump(&success);
     741             : 
     742           0 :     masm.bind(&fail);
     743             : 
     744             :     // Restore backtrack stack pointer.
     745           0 :     masm.pop(backtrack_stack_pointer);
     746           0 :     JumpOrBacktrack(on_no_match);
     747             : 
     748           0 :     masm.bind(&success);
     749             : 
     750             :     // Move current character position to position after match.
     751           0 :     masm.movePtr(backtrack_stack_pointer, current_position);
     752           0 :     masm.subPtr(input_end_pointer, current_position);
     753             : 
     754             :     // Restore backtrack stack pointer.
     755           0 :     masm.pop(backtrack_stack_pointer);
     756             : 
     757           0 :     masm.bind(&fallthrough);
     758           0 : }
     759             : 
     760             : void
     761           0 : NativeRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(int start_reg, Label* on_no_match,
     762             :                                                             bool unicode)
     763             : {
     764           0 :     JitSpew(SPEW_PREFIX "CheckNotBackReferenceIgnoreCase(%d, %d)", start_reg, unicode);
     765             : 
     766           0 :     Label fallthrough;
     767             : 
     768           0 :     masm.loadPtr(register_location(start_reg), current_character);  // Index of start of capture
     769           0 :     masm.loadPtr(register_location(start_reg + 1), temp1);  // Index of end of capture
     770           0 :     masm.subPtr(current_character, temp1);  // Length of capture.
     771             : 
     772             :     // The length of a capture should not be negative. This can only happen
     773             :     // if the end of the capture is unrecorded, or at a point earlier than
     774             :     // the start of the capture.
     775           0 :     masm.branchPtr(Assembler::LessThan, temp1, ImmWord(0), BranchOrBacktrack(on_no_match));
     776             : 
     777             :     // If length is zero, either the capture is empty or it is completely
     778             :     // uncaptured. In either case succeed immediately.
     779           0 :     masm.branchPtr(Assembler::Equal, temp1, ImmWord(0), &fallthrough);
     780             : 
     781             :     // Check that there are sufficient characters left in the input.
     782           0 :     masm.movePtr(current_position, temp0);
     783           0 :     masm.addPtr(temp1, temp0);
     784           0 :     masm.branchPtr(Assembler::GreaterThan, temp0, ImmWord(0), BranchOrBacktrack(on_no_match));
     785             : 
     786           0 :     if (mode_ == LATIN1) {
     787           0 :         Label success, fail;
     788             : 
     789             :         // Save register contents to make the registers available below. After
     790             :         // this, the temp0, temp2, and current_position registers are available.
     791           0 :         masm.push(current_position);
     792             : 
     793           0 :         masm.addPtr(input_end_pointer, current_character); // Start of capture.
     794           0 :         masm.addPtr(input_end_pointer, current_position); // Start of text to match against capture.
     795           0 :         masm.addPtr(current_position, temp1); // End of text to match against capture.
     796             : 
     797           0 :         Label loop, loop_increment;
     798           0 :         masm.bind(&loop);
     799           0 :         masm.load8ZeroExtend(Address(current_position, 0), temp0);
     800           0 :         masm.load8ZeroExtend(Address(current_character, 0), temp2);
     801           0 :         masm.branch32(Assembler::Equal, temp0, temp2, &loop_increment);
     802             : 
     803             :         // Mismatch, try case-insensitive match (converting letters to lower-case).
     804           0 :         masm.or32(Imm32(0x20), temp0); // Convert match character to lower-case.
     805             : 
     806             :         // Is temp0 a lowercase letter?
     807           0 :         Label convert_capture;
     808           0 :         masm.computeEffectiveAddress(Address(temp0, -'a'), temp2);
     809           0 :         masm.branch32(Assembler::BelowOrEqual, temp2, Imm32(static_cast<int32_t>('z' - 'a')),
     810           0 :                       &convert_capture);
     811             : 
     812             :         // Latin-1: Check for values in range [224,254] but not 247.
     813           0 :         masm.sub32(Imm32(224 - 'a'), temp2);
     814           0 :         masm.branch32(Assembler::Above, temp2, Imm32(254 - 224), &fail);
     815             : 
     816             :         // Check for 247.
     817           0 :         masm.branch32(Assembler::Equal, temp2, Imm32(247 - 224), &fail);
     818             : 
     819           0 :         masm.bind(&convert_capture);
     820             : 
     821             :         // Also convert capture character.
     822           0 :         masm.load8ZeroExtend(Address(current_character, 0), temp2);
     823           0 :         masm.or32(Imm32(0x20), temp2);
     824             : 
     825           0 :         masm.branch32(Assembler::NotEqual, temp0, temp2, &fail);
     826             : 
     827           0 :         masm.bind(&loop_increment);
     828             : 
     829             :         // Increment pointers into match and capture strings.
     830           0 :         masm.addPtr(Imm32(1), current_character);
     831           0 :         masm.addPtr(Imm32(1), current_position);
     832             : 
     833             :         // Compare to end of match, and loop if not done.
     834           0 :         masm.branchPtr(Assembler::Below, current_position, temp1, &loop);
     835           0 :         masm.jump(&success);
     836             : 
     837           0 :         masm.bind(&fail);
     838             : 
     839             :         // Restore original values before failing.
     840           0 :         masm.pop(current_position);
     841           0 :         JumpOrBacktrack(on_no_match);
     842             : 
     843           0 :         masm.bind(&success);
     844             : 
     845             :         // Drop original character position value.
     846           0 :         masm.addToStackPtr(Imm32(sizeof(uintptr_t)));
     847             : 
     848             :         // Compute new value of character position after the matched part.
     849           0 :         masm.subPtr(input_end_pointer, current_position);
     850             :     } else {
     851           0 :         MOZ_ASSERT(mode_ == CHAR16);
     852             : 
     853             :         // Note: temp1 needs to be saved/restored if it is volatile, as it is used after the call.
     854           0 :         LiveGeneralRegisterSet volatileRegs(GeneralRegisterSet::Volatile());
     855           0 :         volatileRegs.takeUnchecked(temp0);
     856           0 :         volatileRegs.takeUnchecked(temp2);
     857           0 :         masm.PushRegsInMask(volatileRegs);
     858             : 
     859             :         // Set byte_offset1.
     860             :         // Start of capture, where current_character already holds string-end negative offset.
     861           0 :         masm.addPtr(input_end_pointer, current_character);
     862             : 
     863             :         // Set byte_offset2.
     864             :         // Found by adding negative string-end offset of current position
     865             :         // to end of string.
     866           0 :         masm.addPtr(input_end_pointer, current_position);
     867             : 
     868             :         // Parameters are
     869             :         //   Address byte_offset1 - Address captured substring's start.
     870             :         //   Address byte_offset2 - Address of current character position.
     871             :         //   size_t byte_length - length of capture in bytes(!)
     872           0 :         masm.setupUnalignedABICall(temp0);
     873           0 :         masm.passABIArg(current_character);
     874           0 :         masm.passABIArg(current_position);
     875           0 :         masm.passABIArg(temp1);
     876           0 :         if (!unicode) {
     877           0 :             int (*fun)(const char16_t*, const char16_t*, size_t) = CaseInsensitiveCompareStrings;
     878           0 :             masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, fun));
     879             :         } else {
     880           0 :             int (*fun)(const char16_t*, const char16_t*, size_t) = CaseInsensitiveCompareUCStrings;
     881           0 :             masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, fun));
     882             :         }
     883           0 :         masm.storeCallWordResult(temp0);
     884             : 
     885           0 :         masm.PopRegsInMask(volatileRegs);
     886             : 
     887             :         // Check if function returned non-zero for success or zero for failure.
     888           0 :         masm.branchTest32(Assembler::Zero, temp0, temp0, BranchOrBacktrack(on_no_match));
     889             : 
     890             :         // On success, increment position by length of capture.
     891           0 :         masm.addPtr(temp1, current_position);
     892             :     }
     893             : 
     894           0 :     masm.bind(&fallthrough);
     895           0 : }
     896             : 
     897             : void
     898           0 : NativeRegExpMacroAssembler::CheckNotCharacterAfterMinusAnd(char16_t c, char16_t minus, char16_t and_with,
     899             :                                                            Label* on_not_equal)
     900             : {
     901           0 :     JitSpew(SPEW_PREFIX "CheckNotCharacterAfterMinusAnd(%d, %d, %d)", (int) c,
     902           0 :             (int) minus, (int) and_with);
     903             : 
     904           0 :     masm.computeEffectiveAddress(Address(current_character, -minus), temp0);
     905           0 :     if (c == 0) {
     906           0 :         masm.branchTest32(Assembler::NonZero, temp0, Imm32(and_with),
     907           0 :                           BranchOrBacktrack(on_not_equal));
     908             :     } else {
     909           0 :         masm.and32(Imm32(and_with), temp0);
     910           0 :         masm.branch32(Assembler::NotEqual, temp0, Imm32(c), BranchOrBacktrack(on_not_equal));
     911             :     }
     912           0 : }
     913             : 
     914             : void
     915          14 : NativeRegExpMacroAssembler::CheckCharacterInRange(char16_t from, char16_t to,
     916             :                                                   Label* on_in_range)
     917             : {
     918          14 :     JitSpew(SPEW_PREFIX "CheckCharacterInRange(%d, %d)", (int) from, (int) to);
     919             : 
     920          14 :     masm.computeEffectiveAddress(Address(current_character, -from), temp0);
     921          14 :     masm.branch32(Assembler::BelowOrEqual, temp0, Imm32(to - from), BranchOrBacktrack(on_in_range));
     922          14 : }
     923             : 
     924             : void
     925          31 : NativeRegExpMacroAssembler::CheckCharacterNotInRange(char16_t from, char16_t to,
     926             :                                                      Label* on_not_in_range)
     927             : {
     928          31 :     JitSpew(SPEW_PREFIX "CheckCharacterNotInRange(%d, %d)", (int) from, (int) to);
     929             : 
     930          31 :     masm.computeEffectiveAddress(Address(current_character, -from), temp0);
     931          31 :     masm.branch32(Assembler::Above, temp0, Imm32(to - from), BranchOrBacktrack(on_not_in_range));
     932          31 : }
     933             : 
     934             : void
     935          16 : NativeRegExpMacroAssembler::CheckBitInTable(RegExpShared::JitCodeTable table, Label* on_bit_set)
     936             : {
     937          16 :     JitSpew(SPEW_PREFIX "CheckBitInTable");
     938             : 
     939          16 :     masm.movePtr(ImmPtr(table.get()), temp0);
     940             : 
     941             :     // kTableMask is currently 127, so we need to mask even if the input is
     942             :     // Latin1. V8 has the same issue.
     943             :     static_assert(JSString::MAX_LATIN1_CHAR > kTableMask,
     944             :                   "No need to mask if MAX_LATIN1_CHAR <= kTableMask");
     945          16 :     masm.move32(Imm32(kTableSize - 1), temp1);
     946          16 :     masm.and32(current_character, temp1);
     947             : 
     948          16 :     masm.load8ZeroExtend(BaseIndex(temp0, temp1, TimesOne), temp0);
     949          16 :     masm.branchTest32(Assembler::NonZero, temp0, temp0, BranchOrBacktrack(on_bit_set));
     950             : 
     951             :     // Transfer ownership of |table| to the |tables| Vector.
     952             :     {
     953          32 :         AutoEnterOOMUnsafeRegion oomUnsafe;
     954          16 :         if (!tables.append(Move(table)))
     955           0 :             oomUnsafe.crash("RegExp table append");
     956             :     }
     957          16 : }
     958             : 
     959             : void
     960          40 : NativeRegExpMacroAssembler::Fail()
     961             : {
     962          40 :     JitSpew(SPEW_PREFIX "Fail");
     963             : 
     964          40 :     if (!global())
     965          40 :         masm.movePtr(ImmWord(RegExpRunStatus_Success_NotFound), temp0);
     966          40 :     masm.jump(&exit_label_);
     967          40 : }
     968             : 
     969             : void
     970          11 : NativeRegExpMacroAssembler::IfRegisterGE(int reg, int comparand, Label* if_ge)
     971             : {
     972          11 :     JitSpew(SPEW_PREFIX "IfRegisterGE(%d, %d)", reg, comparand);
     973          22 :     masm.branchPtr(Assembler::GreaterThanOrEqual, register_location(reg), ImmWord(comparand),
     974          11 :                    BranchOrBacktrack(if_ge));
     975          11 : }
     976             : 
     977             : void
     978           5 : NativeRegExpMacroAssembler::IfRegisterLT(int reg, int comparand, Label* if_lt)
     979             : {
     980           5 :     JitSpew(SPEW_PREFIX "IfRegisterLT(%d, %d)", reg, comparand);
     981          10 :     masm.branchPtr(Assembler::LessThan, register_location(reg), ImmWord(comparand),
     982           5 :                    BranchOrBacktrack(if_lt));
     983           5 : }
     984             : 
     985             : void
     986           0 : NativeRegExpMacroAssembler::IfRegisterEqPos(int reg, Label* if_eq)
     987             : {
     988           0 :     JitSpew(SPEW_PREFIX "IfRegisterEqPos(%d)", reg);
     989           0 :     masm.branchPtr(Assembler::Equal, register_location(reg), current_position,
     990           0 :                    BranchOrBacktrack(if_eq));
     991           0 : }
     992             : 
     993             : void
     994         591 : NativeRegExpMacroAssembler::LoadCurrentCharacter(int cp_offset, Label* on_end_of_input,
     995             :                                                  bool check_bounds, int characters)
     996             : {
     997         591 :     JitSpew(SPEW_PREFIX "LoadCurrentCharacter(%d, %d)", cp_offset, characters);
     998             : 
     999         591 :     MOZ_ASSERT(cp_offset >= -1);      // ^ and \b can look behind one character.
    1000         591 :     MOZ_ASSERT(cp_offset < (1<<30));  // Be sane! (And ensure negation works)
    1001         591 :     if (check_bounds)
    1002         196 :         CheckPosition(cp_offset + characters - 1, on_end_of_input);
    1003         591 :     LoadCurrentCharacterUnchecked(cp_offset, characters);
    1004         591 : }
    1005             : 
    1006             : void
    1007         631 : NativeRegExpMacroAssembler::LoadCurrentCharacterUnchecked(int cp_offset, int characters)
    1008             : {
    1009         631 :     JitSpew(SPEW_PREFIX "LoadCurrentCharacterUnchecked(%d, %d)", cp_offset, characters);
    1010             : 
    1011         631 :     if (mode_ == LATIN1) {
    1012         578 :         BaseIndex address(input_end_pointer, current_position, TimesOne, cp_offset);
    1013         578 :         if (characters == 4) {
    1014          39 :             masm.load32(address, current_character);
    1015         539 :         } else if (characters == 2) {
    1016          29 :             masm.load16ZeroExtend(address, current_character);
    1017             :         } else {
    1018         510 :             MOZ_ASSERT(characters == 1);
    1019         510 :             masm.load8ZeroExtend(address, current_character);
    1020             :         }
    1021             :     } else {
    1022          53 :         MOZ_ASSERT(mode_ == CHAR16);
    1023          53 :         MOZ_ASSERT(characters <= 2);
    1024          53 :         BaseIndex address(input_end_pointer, current_position, TimesOne, cp_offset * sizeof(char16_t));
    1025          53 :         if (characters == 2)
    1026          12 :             masm.load32(address, current_character);
    1027             :         else
    1028          41 :             masm.load16ZeroExtend(address, current_character);
    1029             :     }
    1030         631 : }
    1031             : 
    1032             : void
    1033         129 : NativeRegExpMacroAssembler::PopCurrentPosition()
    1034             : {
    1035         129 :     JitSpew(SPEW_PREFIX "PopCurrentPosition");
    1036             : 
    1037         129 :     PopBacktrack(current_position);
    1038         129 : }
    1039             : 
    1040             : void
    1041          44 : NativeRegExpMacroAssembler::PopRegister(int register_index)
    1042             : {
    1043          44 :     JitSpew(SPEW_PREFIX "PopRegister(%d)", register_index);
    1044             : 
    1045          44 :     PopBacktrack(temp0);
    1046          44 :     masm.storePtr(temp0, register_location(register_index));
    1047          44 : }
    1048             : 
    1049             : void
    1050         206 : NativeRegExpMacroAssembler::PushBacktrack(Label* label)
    1051             : {
    1052         206 :     JitSpew(SPEW_PREFIX "PushBacktrack");
    1053             : 
    1054         206 :     CodeOffset patchOffset = masm.movWithPatch(ImmPtr(nullptr), temp0);
    1055             : 
    1056         206 :     MOZ_ASSERT(!label->bound());
    1057             : 
    1058             :     {
    1059         412 :         AutoEnterOOMUnsafeRegion oomUnsafe;
    1060         206 :         if (!labelPatches.append(LabelPatch(label, patchOffset)))
    1061           0 :             oomUnsafe.crash("NativeRegExpMacroAssembler::PushBacktrack");
    1062             :     }
    1063             : 
    1064         206 :     PushBacktrack(temp0);
    1065         206 :     CheckBacktrackStackLimit();
    1066         206 : }
    1067             : 
    1068             : void
    1069         206 : NativeRegExpMacroAssembler::BindBacktrack(Label* label)
    1070             : {
    1071         206 :     JitSpew(SPEW_PREFIX "BindBacktrack");
    1072             : 
    1073         206 :     Bind(label);
    1074             : 
    1075        1421 :     for (size_t i = 0; i < labelPatches.length(); i++) {
    1076        1421 :         LabelPatch& v = labelPatches[i];
    1077        1421 :         if (v.label == label) {
    1078         206 :             v.labelOffset = label->offset();
    1079         206 :             v.label = nullptr;
    1080         206 :             break;
    1081             :         }
    1082             :     }
    1083         206 : }
    1084             : 
    1085             : void
    1086         405 : NativeRegExpMacroAssembler::PushBacktrack(Register source)
    1087             : {
    1088         405 :     JitSpew(SPEW_PREFIX "PushBacktrack");
    1089             : 
    1090         405 :     MOZ_ASSERT(source != backtrack_stack_pointer);
    1091             : 
    1092             :     // Notice: This updates flags, unlike normal Push.
    1093         405 :     masm.storePtr(source, Address(backtrack_stack_pointer, 0));
    1094         405 :     masm.addPtr(Imm32(sizeof(void*)), backtrack_stack_pointer);
    1095         405 : }
    1096             : 
    1097             : void
    1098           0 : NativeRegExpMacroAssembler::PushBacktrack(int32_t value)
    1099             : {
    1100           0 :     JitSpew(SPEW_PREFIX "PushBacktrack(%d)", (int) value);
    1101             : 
    1102             :     // Notice: This updates flags, unlike normal Push.
    1103           0 :     masm.storePtr(ImmWord(value), Address(backtrack_stack_pointer, 0));
    1104           0 :     masm.addPtr(Imm32(sizeof(void*)), backtrack_stack_pointer);
    1105           0 : }
    1106             : 
    1107             : void
    1108         294 : NativeRegExpMacroAssembler::PopBacktrack(Register target)
    1109             : {
    1110         294 :     JitSpew(SPEW_PREFIX "PopBacktrack");
    1111             : 
    1112         294 :     MOZ_ASSERT(target != backtrack_stack_pointer);
    1113             : 
    1114             :     // Notice: This updates flags, unlike normal Pop.
    1115         294 :     masm.subPtr(Imm32(sizeof(void*)), backtrack_stack_pointer);
    1116         294 :     masm.loadPtr(Address(backtrack_stack_pointer, 0), target);
    1117         294 : }
    1118             : 
    1119             : void
    1120         206 : NativeRegExpMacroAssembler::CheckBacktrackStackLimit()
    1121             : {
    1122         206 :     JitSpew(SPEW_PREFIX "CheckBacktrackStackLimit");
    1123             : 
    1124         412 :     Label no_stack_overflow;
    1125         206 :     void* context_addr = cx->zone()->group()->addressOfOwnerContext();
    1126         206 :     size_t limitOffset = offsetof(JSContext, regexpStack) + RegExpStack::offsetOfLimit();
    1127         206 :     masm.loadPtr(AbsoluteAddress(context_addr), temp1);
    1128         412 :     masm.branchPtr(Assembler::AboveOrEqual, Address(temp1, limitOffset),
    1129         206 :                    backtrack_stack_pointer, &no_stack_overflow);
    1130             : 
    1131             :     // Copy the stack pointer before the call() instruction modifies it.
    1132         206 :     masm.moveStackPtrTo(temp2);
    1133             : 
    1134         206 :     masm.call(&stack_overflow_label_);
    1135         206 :     masm.bind(&no_stack_overflow);
    1136             : 
    1137             :     // Exit with an exception if the call failed.
    1138         206 :     masm.branchTest32(Assembler::Zero, temp0, temp0, &exit_with_exception_label_);
    1139         206 : }
    1140             : 
    1141             : void
    1142         155 : NativeRegExpMacroAssembler::PushCurrentPosition()
    1143             : {
    1144         155 :     JitSpew(SPEW_PREFIX "PushCurrentPosition");
    1145             : 
    1146         155 :     PushBacktrack(current_position);
    1147         155 : }
    1148             : 
    1149             : void
    1150          44 : NativeRegExpMacroAssembler::PushRegister(int register_index, StackCheckFlag check_stack_limit)
    1151             : {
    1152          44 :     JitSpew(SPEW_PREFIX "PushRegister(%d)", register_index);
    1153             : 
    1154          44 :     masm.loadPtr(register_location(register_index), temp0);
    1155          44 :     PushBacktrack(temp0);
    1156          44 :     if (check_stack_limit)
    1157           0 :         CheckBacktrackStackLimit();
    1158          44 : }
    1159             : 
    1160             : void
    1161          22 : NativeRegExpMacroAssembler::ReadCurrentPositionFromRegister(int reg)
    1162             : {
    1163          22 :     JitSpew(SPEW_PREFIX "ReadCurrentPositionFromRegister(%d)", reg);
    1164             : 
    1165          22 :     masm.loadPtr(register_location(reg), current_position);
    1166          22 : }
    1167             : 
    1168             : void
    1169         253 : NativeRegExpMacroAssembler::WriteCurrentPositionToRegister(int reg, int cp_offset)
    1170             : {
    1171         253 :     JitSpew(SPEW_PREFIX "WriteCurrentPositionToRegister(%d, %d)", reg, cp_offset);
    1172             : 
    1173         253 :     if (cp_offset == 0) {
    1174         172 :         masm.storePtr(current_position, register_location(reg));
    1175             :     } else {
    1176          81 :         masm.computeEffectiveAddress(Address(current_position, cp_offset * char_size()), temp0);
    1177          81 :         masm.storePtr(temp0, register_location(reg));
    1178             :     }
    1179         253 : }
    1180             : 
    1181             : void
    1182          22 : NativeRegExpMacroAssembler::ReadBacktrackStackPointerFromRegister(int reg)
    1183             : {
    1184          22 :     JitSpew(SPEW_PREFIX "ReadBacktrackStackPointerFromRegister(%d)", reg);
    1185             : 
    1186          22 :     masm.loadPtr(register_location(reg), backtrack_stack_pointer);
    1187          44 :     masm.addPtr(Address(masm.getStackPointer(),
    1188          22 :                 offsetof(FrameData, backtrackStackBase)), backtrack_stack_pointer);
    1189          22 : }
    1190             : 
    1191             : void
    1192          12 : NativeRegExpMacroAssembler::WriteBacktrackStackPointerToRegister(int reg)
    1193             : {
    1194          12 :     JitSpew(SPEW_PREFIX "WriteBacktrackStackPointerToRegister(%d)", reg);
    1195             : 
    1196          12 :     masm.movePtr(backtrack_stack_pointer, temp0);
    1197          24 :     masm.subPtr(Address(masm.getStackPointer(),
    1198          12 :                 offsetof(FrameData, backtrackStackBase)), temp0);
    1199          12 :     masm.storePtr(temp0, register_location(reg));
    1200          12 : }
    1201             : 
    1202             : void
    1203           0 : NativeRegExpMacroAssembler::SetCurrentPositionFromEnd(int by)
    1204             : {
    1205           0 :     JitSpew(SPEW_PREFIX "SetCurrentPositionFromEnd(%d)", by);
    1206             : 
    1207           0 :     Label after_position;
    1208           0 :     masm.branchPtr(Assembler::GreaterThanOrEqual, current_position,
    1209           0 :                    ImmWord(-by * char_size()), &after_position);
    1210           0 :     masm.movePtr(ImmWord(-by * char_size()), current_position);
    1211             : 
    1212             :     // On RegExp code entry (where this operation is used), the character before
    1213             :     // the current position is expected to be already loaded.
    1214             :     // We have advanced the position, so it's safe to read backwards.
    1215           0 :     LoadCurrentCharacterUnchecked(-1, 1);
    1216           0 :     masm.bind(&after_position);
    1217           0 : }
    1218             : 
    1219             : void
    1220          11 : NativeRegExpMacroAssembler::SetRegister(int register_index, int to)
    1221             : {
    1222          11 :     JitSpew(SPEW_PREFIX "SetRegister(%d, %d)", register_index, to);
    1223             : 
    1224          11 :     MOZ_ASSERT(register_index >= num_saved_registers_);  // Reserved for positions!
    1225          11 :     masm.storePtr(ImmWord(to), register_location(register_index));
    1226          11 : }
    1227             : 
    1228             : bool
    1229          66 : NativeRegExpMacroAssembler::Succeed()
    1230             : {
    1231          66 :     JitSpew(SPEW_PREFIX "Succeed");
    1232             : 
    1233          66 :     masm.jump(&success_label_);
    1234          66 :     return global();
    1235             : }
    1236             : 
    1237             : void
    1238          60 : NativeRegExpMacroAssembler::ClearRegisters(int reg_from, int reg_to)
    1239             : {
    1240          60 :     JitSpew(SPEW_PREFIX "ClearRegisters(%d, %d)", reg_from, reg_to);
    1241             : 
    1242          60 :     MOZ_ASSERT(reg_from <= reg_to);
    1243          60 :     masm.loadPtr(Address(masm.getStackPointer(), offsetof(FrameData, inputStartMinusOne)), temp0);
    1244         135 :     for (int reg = reg_from; reg <= reg_to; reg++)
    1245          75 :         masm.storePtr(temp0, register_location(reg));
    1246          60 : }
    1247             : 
    1248             : void
    1249         230 : NativeRegExpMacroAssembler::CheckPosition(int cp_offset, Label* on_outside_input)
    1250             : {
    1251         230 :     JitSpew(SPEW_PREFIX "CheckPosition(%d)", cp_offset);
    1252         690 :     masm.branchPtr(Assembler::GreaterThanOrEqual, current_position,
    1253         460 :                    ImmWord(-cp_offset * char_size()), BranchOrBacktrack(on_outside_input));
    1254         230 : }
    1255             : 
    1256             : Label*
    1257         942 : NativeRegExpMacroAssembler::BranchOrBacktrack(Label* branch)
    1258             : {
    1259         942 :     if (branch)
    1260         692 :         return branch;
    1261         250 :     return &backtrack_label_;
    1262             : }
    1263             : 
    1264             : void
    1265         390 : NativeRegExpMacroAssembler::JumpOrBacktrack(Label* to)
    1266             : {
    1267         390 :     JitSpew(SPEW_PREFIX "JumpOrBacktrack");
    1268             : 
    1269         390 :     if (to)
    1270         357 :         masm.jump(to);
    1271             :     else
    1272          33 :         Backtrack();
    1273         390 : }
    1274             : 
    1275             : bool
    1276          18 : NativeRegExpMacroAssembler::CheckSpecialCharacterClass(char16_t type, Label* on_no_match)
    1277             : {
    1278          18 :     JitSpew(SPEW_PREFIX "CheckSpecialCharacterClass(%d)", (int) type);
    1279             : 
    1280          18 :     Label* branch = BranchOrBacktrack(on_no_match);
    1281             : 
    1282             :     // Range checks (c in min..max) are generally implemented by an unsigned
    1283             :     // (c - min) <= (max - min) check
    1284          18 :     switch (type) {
    1285             :       case 's':
    1286             :         // Match space-characters.
    1287           2 :         if (mode_ == LATIN1) {
    1288             :             // One byte space characters are '\t'..'\r', ' ' and \u00a0.
    1289           4 :             Label success;
    1290           2 :             masm.branch32(Assembler::Equal, current_character, Imm32(' '), &success);
    1291             : 
    1292             :             // Check range 0x09..0x0d.
    1293           2 :             masm.computeEffectiveAddress(Address(current_character, -'\t'), temp0);
    1294           2 :             masm.branch32(Assembler::BelowOrEqual, temp0, Imm32('\r' - '\t'), &success);
    1295             : 
    1296             :             // \u00a0 (NBSP).
    1297           2 :             masm.branch32(Assembler::NotEqual, temp0, Imm32(0x00a0 - '\t'), branch);
    1298             : 
    1299           2 :             masm.bind(&success);
    1300           2 :             return true;
    1301             :         }
    1302           0 :         return false;
    1303             :       case 'S':
    1304             :         // The emitted code for generic character classes is good enough.
    1305           3 :         return false;
    1306             :       case 'd':
    1307             :         // Match LATIN1 digits ('0'..'9')
    1308           0 :         masm.computeEffectiveAddress(Address(current_character, -'0'), temp0);
    1309           0 :         masm.branch32(Assembler::Above, temp0, Imm32('9' - '0'), branch);
    1310           0 :         return true;
    1311             :       case 'D':
    1312             :         // Match non LATIN1-digits
    1313           0 :         masm.computeEffectiveAddress(Address(current_character, -'0'), temp0);
    1314           0 :         masm.branch32(Assembler::BelowOrEqual, temp0, Imm32('9' - '0'), branch);
    1315           0 :         return true;
    1316             :       case '.': {
    1317             :         // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
    1318          11 :         masm.move32(current_character, temp0);
    1319          11 :         masm.xor32(Imm32(0x01), temp0);
    1320             : 
    1321             :         // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
    1322          11 :         masm.sub32(Imm32(0x0b), temp0);
    1323          11 :         masm.branch32(Assembler::BelowOrEqual, temp0, Imm32(0x0c - 0x0b), branch);
    1324          11 :         if (mode_ == CHAR16) {
    1325             :             // Compare original value to 0x2028 and 0x2029, using the already
    1326             :             // computed (current_char ^ 0x01 - 0x0b). I.e., check for
    1327             :             // 0x201d (0x2028 - 0x0b) or 0x201e.
    1328           0 :             masm.sub32(Imm32(0x2028 - 0x0b), temp0);
    1329           0 :             masm.branch32(Assembler::BelowOrEqual, temp0, Imm32(0x2029 - 0x2028), branch);
    1330             :         }
    1331          11 :         return true;
    1332             :       }
    1333             :       case 'w': {
    1334           1 :         if (mode_ != LATIN1) {
    1335             :             // Table is 256 entries, so all LATIN1 characters can be tested.
    1336           0 :             masm.branch32(Assembler::Above, current_character, Imm32('z'), branch);
    1337             :         }
    1338           1 :         MOZ_ASSERT(0 == word_character_map[0]);  // Character '\0' is not a word char.
    1339           1 :         masm.movePtr(ImmPtr(word_character_map), temp0);
    1340           1 :         masm.load8ZeroExtend(BaseIndex(temp0, current_character, TimesOne), temp0);
    1341           1 :         masm.branchTest32(Assembler::Zero, temp0, temp0, branch);
    1342           1 :         return true;
    1343             :       }
    1344             :       case 'W': {
    1345           2 :         Label done;
    1346           1 :         if (mode_ != LATIN1) {
    1347             :             // Table is 256 entries, so all LATIN1 characters can be tested.
    1348           0 :             masm.branch32(Assembler::Above, current_character, Imm32('z'), &done);
    1349             :         }
    1350           1 :         MOZ_ASSERT(0 == word_character_map[0]);  // Character '\0' is not a word char.
    1351           1 :         masm.movePtr(ImmPtr(word_character_map), temp0);
    1352           1 :         masm.load8ZeroExtend(BaseIndex(temp0, current_character, TimesOne), temp0);
    1353           1 :         masm.branchTest32(Assembler::NonZero, temp0, temp0, branch);
    1354           1 :         if (mode_ != LATIN1)
    1355           0 :             masm.bind(&done);
    1356           1 :         return true;
    1357             :       }
    1358             :         // Non-standard classes (with no syntactic shorthand) used internally.
    1359             :       case '*':
    1360             :         // Match any character.
    1361           0 :         return true;
    1362             :       case 'n': {
    1363             :         // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 or 0x2029).
    1364             :         // The opposite of '.'.
    1365           0 :         masm.move32(current_character, temp0);
    1366           0 :         masm.xor32(Imm32(0x01), temp0);
    1367             : 
    1368             :         // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
    1369           0 :         masm.sub32(Imm32(0x0b), temp0);
    1370             : 
    1371           0 :         if (mode_ == LATIN1) {
    1372           0 :             masm.branch32(Assembler::Above, temp0, Imm32(0x0c - 0x0b), branch);
    1373             :         } else {
    1374           0 :             Label done;
    1375           0 :             masm.branch32(Assembler::BelowOrEqual, temp0, Imm32(0x0c - 0x0b), &done);
    1376           0 :             MOZ_ASSERT(CHAR16 == mode_);
    1377             : 
    1378             :             // Compare original value to 0x2028 and 0x2029, using the already
    1379             :             // computed (current_char ^ 0x01 - 0x0b). I.e., check for
    1380             :             // 0x201d (0x2028 - 0x0b) or 0x201e.
    1381           0 :             masm.sub32(Imm32(0x2028 - 0x0b), temp0);
    1382           0 :             masm.branch32(Assembler::Above, temp0, Imm32(1), branch);
    1383             : 
    1384           0 :             masm.bind(&done);
    1385             :         }
    1386           0 :         return true;
    1387             :       }
    1388             :         // No custom implementation (yet):
    1389             :       default:
    1390           0 :         return false;
    1391             :     }
    1392             : }
    1393             : 
    1394             : bool
    1395         173 : NativeRegExpMacroAssembler::CanReadUnaligned()
    1396             : {
    1397             : #if defined(JS_CODEGEN_ARM)
    1398             :     return !jit::HasAlignmentFault();
    1399             : #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
    1400             :     return false;
    1401             : #else
    1402         173 :     return true;
    1403             : #endif
    1404             : }
    1405             : 
    1406             : const uint8_t
    1407             : NativeRegExpMacroAssembler::word_character_map[] =
    1408             : {
    1409             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1410             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1411             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1412             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1413             : 
    1414             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1415             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1416             :     0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu,  // '0' - '7'
    1417             :     0xffu, 0xffu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,  // '8' - '9'
    1418             : 
    1419             :     0x00u, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu,  // 'A' - 'G'
    1420             :     0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu,  // 'H' - 'O'
    1421             :     0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu,  // 'P' - 'W'
    1422             :     0xffu, 0xffu, 0xffu, 0x00u, 0x00u, 0x00u, 0x00u, 0xffu,  // 'X' - 'Z', '_'
    1423             : 
    1424             :     0x00u, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu,  // 'a' - 'g'
    1425             :     0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu,  // 'h' - 'o'
    1426             :     0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu, 0xffu,  // 'p' - 'w'
    1427             :     0xffu, 0xffu, 0xffu, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,  // 'x' - 'z'
    1428             : 
    1429             :     // Latin-1 range
    1430             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1431             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1432             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1433             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1434             : 
    1435             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1436             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1437             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1438             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1439             : 
    1440             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1441             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1442             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1443             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1444             : 
    1445             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1446             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1447             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1448             :     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
    1449             : };

Generated by: LCOV version 1.13